Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734/* * PROJECT: ReactOS GUI first stage setup application * LICENSE: GPL-3.0-or-later (https://spdx.org/licenses/GPL-3.0-or-later) * PURPOSE: Implements a TreeList control: a tree window with columns. * COPYRIGHT: Copyright (C) Anton Zechner (az_software@inode.at) 2007 * Copyright (C) S�bastien Kirche (sebastien.kirche@free.fr) 2014 * * NOTE: Taken from the TreeList code found at https://github.com/sebkirche/treelist */
//*****************************************************************************//*//*//* TreeListWnd.cpp//*//*//*****************************************************************************//// This code creates a tree window with a list////// Copyright (C) Anton Zechner (az_software@inode.at) 2007// Copyright (C) S�bastien Kirche (sebastien.kirche@free.fr) 2014//// TreeListWnd is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)// Sourcecode which use TreeListWnd must be published. Commercial users// must published their code too, or make an licence agreement with me.////// TreeListWnd wird unter GNU GENERAL PUBLIC LICENSE (GPL) vertreiben.// Sourcecode welcher TreeListWnd verwendet muss ver�ffendlicht werden.// Komerzielle Nutzer m�ssen ihren Code ebenfalls ver�ffentlichen, oder// eine Nutzungsvereinbarung mit mir treffen.////// Version: 2.04//#ifdef UNICODE#ifndef _UNICODE#define _UNICODE#endif#endif
#if 0 #include <stdio.h> #include <windows.h> #include <string.h> #include <malloc.h> #include <tchar.h>#else #include "reactos.h"#endif
#define new(TYPE, numElems) \ HeapAlloc(GetProcessHeap(), 0, (numElems) * sizeof(TYPE))#define delete(ptr) \ HeapFree(GetProcessHeap(), 0, (ptr))
#include "treelist.h"
#ifndef GWLP_USERDATA#define GWLP_USERDATA GWL_USERDATA#endif#ifndef GWLP_WNDPROC#define GWLP_WNDPROC GWL_WNDPROC#endif#ifndef _WIN64#ifndef SetWindowLongPtr#define SetWindowLongPtr SetWindowLong#endif#ifndef GetWindowLongPtr#define GetWindowLongPtr GetWindowLong#endif#ifndef DWORD_PTR#define DWORD_PTR DWORD#endif#ifndef LONG_PTR#define LONG_PTR LONG#endif#endif#ifdef UNICODE#define str_len (unsigned)wcslen#define str_cmp wcscmp#define str_ncpy wcsncpy#define str_ncmp wcsncmp#define str_icmp _wcsicmp#else#define str_len (unsigned)strlen#define str_cmp strcmp#define str_ncpy strncpy#define str_ncmp strncmp#define str_icmp _stricmp#endif#ifndef WM_MOUSEWHEEL#define WM_MOUSEWHEEL 0x020A#endif#ifndef WHEEL_DELTA#define WHEEL_DELTA 120#endif#ifndef MAX_COLUMNS#define MAX_COLUMNS 32#endif#define MAX_COLORS 16#define EN_SETTEXT 0x1000#define EN_RETURN 0x1578#define EN_ESCAPE 0x1579#define ID_TOOLTIPCHECK 0x3912#define SORT_NOUPDATE 1234567#define VK_ISACHAR 0x01000000#define FIRST_LINE 0xFFFFFFFE#define FROM_HEADER 0x88776655#define I_CCB I_CHILDRENCALLBACK#define U(h) ((unsigned)(ULONG_PTR)(h))#define THEMEIMGLIST ((HIMAGELIST)1)#define GetHandle(h) ((TreeListData*)GetWindowLongPtr(h,0))#define TVIF_ALL (TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT)#define UNLOCK(d) ReleaseSemaphore(d->hSem,1,NULL)#define LOCK(d) WaitForSingleObject(d->hSem,INFINITE)#define TVIS_EDIT(m) ((1<<m)&((1<<TVAX_EDIT)|(1<<TVAX_COMBO)|(1<<TVAX_STEPED)|(1<<TVAX_CHECKED)))#define TVIS_BASEFLAGS (TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED)#define TVIS_TRACKED (TVIX_TRACKED<<16)#define TVIS_BKCOLOR (TVIX_BKCOLOR<<16)#undef TVIS_FOCUSED#define TVIS_FOCUSED (TVIX_FOCUSED<<16)#define TVIS_TEXTCOLOR (TVIX_TEXTCOLOR<<16)#define TVC_ONLYFOCUS TVIF_ONLYFOCUS#define TVC_UNSELECT 0x4000#define TVC_DESELECT 0x8000#define DEFAULT_IDENT 19#define DEFAULT_SHIFT 7#ifndef BPBF_COMPATIBLEBITMAP#define BPBF_COMPATIBLEBITMAP 0#endif#ifndef TVP_GLYPH#define TVP_GLYPH 2#endif#ifndef GLPS_CLOSED#define GLPS_CLOSED 1#endif#ifndef GLPS_OPENED#define GLPS_OPENED 2#endif#ifndef BP_CHECKBOX#define BP_CHECKBOX 3#endif#ifndef CBS_UNCHECKEDNORMAL#define CBS_UNCHECKEDNORMAL 1#endif#ifndef CBS_CHECKEDNORMAL#define CBS_CHECKEDNORMAL 5#endif
#define TVAX_NONE (TVAE_NONE >>TVAE_MODEPOS)// No automatic edit#define TVAX_EDIT (TVAE_EDIT >>TVAE_MODEPOS)// automatic edit with edit#define TVAX_COMBO (TVAE_COMBO >>TVAE_MODEPOS)// automatic edit with ComboBox#define TVAX_CBLIST (TVAE_CBLIST >>TVAE_MODEPOS)// automatic edit with ComboListBox#define TVAX_STEP (TVAE_STEP >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter#define TVAX_STEPED (TVAE_STEPED >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter und Edit#define TVAX_CHECK (TVAE_CHECK >>TVAE_MODEPOS)// automatic edit with CheckBox#define TVAX_CHECKED (TVAE_CHECKED>>TVAE_MODEPOS)// automatic edit with CheckBox and Edit
#define TVIX_VARBUTTON 0x01 // buttons are not permanent#define TVIX_HASBUTTON 0x02 // entry has button#define TVIX_HASIMAGE 0x04 // entry has icon#define TVIX_TRACKED 0x08 // entry under the cursor#define TVIX_TEXTCOLOR 0x10 // entry has its own text color#define TVIX_BKCOLOR 0x20 // entry has its own backround color#define TVIX_FOCUSED 0x40 // entry has the focus
typedef struct { LPARAM lParam; // LPARAM argument for the item LPTSTR pText; // pointer to the item text UINT uState; // item state int iImage; // item image index int iSelectedImage; // item selected image index unsigned uShowPos; // Ist die Position in der Sichtbarliste (0=unsichtbar) unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines) unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines) unsigned uPrevItem; // Ist die Nummer des vorherigen Eintrages (0=keines) unsigned uNextItem; // Ist die Nummer des n�chsten Eintrages (0=keines) unsigned uParent; // Ist die Nummer des Elterneintrages (0=Root) unsigned uLevel; // Ist die Ebene des Eintrages (0=Root) int iTextPixels; // Ist die Breites des Textes in Pixel WORD uTextSize; // L�nge des Textes in Zeichen BYTE bCallback; // Sind Bits f�r Callbacks BYTE bFlags; // Diverse Flags COLORREF uColorText; // Spezielle Textfarbe COLORREF uColorBk; // Spezielle Hintergrundfarbe} BaseItem;
typedef struct { LPTSTR pText; // Zeiger auf Tree-Text UINT uState; // Zustand des Eintrages int iImage; // Ist die Nummer des an zu zeigenden Icons int iTextPixels; // Ist die Breites des Textes in Pixel WORD uTextSize; // L�nge des Textes in Zeichen BYTE bCallback; // Sind Bits f�r Callbacks BYTE bFlags; // Diverse Flags COLORREF uColorText; // Spezielle Textfarbe COLORREF uColorBk; // Spezielle Hintergrundfarbe} ExtraItem;
typedef struct { void *pCbData; // Data for autoedit INT iCbIcon; // Starting offset for in icon list for autoedit short sSize; // width of the column short sReal; // real width of the column short sMin; // minimum width short sFixed; // fixed width BYTE bMinEx; // the width cannot be less than min width BYTE bWeight; // weight for variable columns BYTE bNext; // Ist die Spalte die nach der eigenen sichtbar ist (gespeicherte Reihenfolge) BYTE bIndex; // Ist die Spalte in der diese Reihe sichtbar ist (sichtbarer Index) BYTE bAlign; // Text alignment BYTE bEdit; // Automaisches Editiern einer Spalte (siehe TVAE_???>>7) BYTE bFlags; // Automaisches Editiern einer Spalte (siehe TVAE_???) BYTE bEnable; // Automaisches einer mit Statebits aktivieren BYTE bCbSize; // Maximum number of entries in the data list BYTE bCbChar; // separator for the data list BYTE bMark; // is column marked ? BYTE bDummy[32 - 23 - sizeof(void *)]; // padding bytes - 32 bytes alignment} ColumnData;
typedef struct { HWND hWnd; // handle of the control HANDLE hSem; // access semaphore LPVOID hTheme; // Handle f�r benutztes Thema (TREELIST) LPVOID hThemeBt; // Handle f�r benutztes Thema (BUTTON) WNDPROC pProcId3; // Fenster Funktion f�r ID3 Fenster HIMAGELIST hStates; // Handle der Icon-Liste f�r States und Overlay HIMAGELIST hImages; // Handle der Icon-Liste HIMAGELIST hChecks; // Handle der Icon-Liste f�r die Checkboxen in den Spalten HIMAGELIST hSubImg; // Handle der Icon-Liste f�r die Spalten HIMAGELIST hHeadImg; // Handle for header images HFONT hFontN; // Normal font HFONT hFontB; // Bold fonts HFONT hFontL; // Last used font HFONT hFontT; // Tooltip font HWND hEdit; // Handle des Edit-Fensters HWND hHeader; // Handle des Header Fensters HWND hToolTip; // Handle des Tooltip-Fensters WNDPROC pToolProc; // Alte Fensterfunktion des Tooltips COLORREF uColors[MAX_COLORS]; // 0=Hintergrundfarbe 1=Abwechselnte Farbe 2=Farbe f�r Trennlinien 3=Textfarbe int iFontHeight; // Ist die H�he des Fonts int iFontLine; // Ist die Position der Linie beim unterstreichen int iFontOff; // Ist die Position um der ein Text horizontal verschoben wird int iStatesMode; // Die hStates Image-Liste wurde f�r die Checkboxen erzeugt int iStatesXsize; // Breite der States und Overlay Icons int iStatesYsize; // H�he der States und Overlay Icons int iChecksMode; // Die hChecks Image-Liste wurde f�r die Checkboxen erzeugt int iChecksXsize; // Breite der States und Overlay Icons int iChecksYsize; // H�he der States und Overlay Icons int iImagesXsize; // Breite der Icons int iImagesYsize; // H�he der Icons int iSubImgMode; // Die SubImg Image-Liste ist nicht die hImages Liste int iSubImgXsize; // Breite der Icons int iSubImgYsize; // H�he der Icons int iRowHeight; // Ist die H�he einer Zeile int iAllWeight; // Das Gewicht aller variablen Spalten int iVarSize; // Ist die Breite aller variablen Spalten int iFixSize; // Ist die Breite aller fixen Spalten int iIndent; // Einr�ckung der Kindereint�ge int iShift; // Einr�ckung der vertikalen Linien int iAutoAdd; // Offset zum Open-Icon f�r TVS_EX_AUTOEXPANDICON int iMaxSizeX; // Die Gr��e des breitesten sichtbaren Eintrages unsigned uItemPosCount; // Anzahl der sichtbaren Eintr�ge unsigned *pItemPos; // Liste mit den Offsets der sichtbaren Eintr�ge BaseItem **pTreeItems; // Zeiger auf Item Zeiger ExtraItem **pExtraItems[MAX_COLUMNS - 1]; // Zeiger auf die Spalteneintr�ge unsigned uTreeItemsMax; // Gr��e der Liste mit den vorhanden Eintr�ge (alociert um 1 gr��er) unsigned uTreeItemsCount; // Anzahl der vorhanden Eintr�ge unsigned uNextSeachPos; // N�chste Position zum suchen von freien Eintr�gen unsigned uUserDataSize; // Ist die Gr��e der Userdaten in einem Eintrag unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines) unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines) unsigned uSingleSel; // Ist die Nummer des gew�hlten Eintrages (bei Checkboxen) unsigned uScrollX; // Aktuelle X-Scroll-Position unsigned uScrollY; // Aktuelle Y-Scroll-Position unsigned uSizeX; // Aktuelle X-Fenster-Gr��e unsigned uSizeY; // Aktuelle Y-Fenster-Gr��e unsigned uSizeYsub; // Aktuelle Y-Fenster-Gr��e ohne Header unsigned uStyle; // Ist der aktuele Style des Fensters unsigned uStyleEx; // Erweiterte Sytle-Flags (siehe TVS_EX_???) unsigned uStartPixel; // Ist die Y-Koordinate bei der der erste Eintrag beginnt unsigned uMaxEnties; // Anzahl der sichtbaren Eintr�ge (inkl. halbsichtbare) unsigned uPageEnties; // Anzahl der sichtbaren Eintr�ge (ohne halbsichtbare) unsigned uColumnCount; // Anzahl der Spalten unsigned uColumnCountVar; // Anzahl der variabeln Spalten unsigned uSelectedCount; // Anzahl der ausgew�hlten Eintr�ge unsigned uSelectedBase; // Ist der Eintrag ab dem gew�hlt wurde unsigned uSelectedItem; // Ist der Eintrag der gerade gew�hlt ist unsigned uSelectedSub; // Ist die Spalte die gerade gew�hlt ist unsigned uFocusItem; // Ist der Eintrag der einen leeren Focus hat unsigned uFocusSub; // Ist die Spalte die einen leeren Focus hat unsigned uToolTipItem; // Ist der ToolTip-Eintrag der gerade gew�hlt ist unsigned uToolTipShow; // Ist die Zeitverz�gerung in 500 ms Schritten f�r das Tooltip unsigned uToolTipSub; // Ist die ToolTip-Spalte die gerade gew�hlt ist POINT sToolTipPos; // Ist die globale Koordinate des ToolTips unsigned uEditMode; // Ist der Modus des Editfensters (0=Edit 1=ComboBox 2=ComboBox fix) unsigned uEditItem; // Ist der Eintrag der gerade editiert wird unsigned uEditSub; // Ist die Spalte die gerade editiert wird unsigned uOldXPage; // Alte Werte f�r X-Scroll-Bar unsigned uOldXCount; // * unsigned uOldYPage; // Alte Werte f�r Y-Scroll-Bar unsigned uOldYCount; // * unsigned uTrippleB; // Bereite des "..." Strings f�r den fetten Fonts unsigned uTrippleN; // Bereite des "..." Strings f�r den normalen Fonts unsigned uTrackedItem; // Ist der Eintrag der unterstrichen werden soll unsigned uTrackedSub; // Ist die Spalte des Eintrages der unterstrichen werden soll unsigned uInsertMark; // Ist der Eintrag mit der Einf�gemarke unsigned uMarkedCols; // Anzahl der markierten Spalten unsigned uDragFlags; // Welche Maustasten sind an unsigned uDragItem; // Eintrag f�r Dragoperation unsigned uDragSub; // Untereintrag f�r Dragoperation unsigned uLastSel; // Letzte Textauswahl beim Editieren unsigned uLastMove; // Letzte Cursorposition bei WM_MOUSEMOVE unsigned uButtonPos; // Wo wurde eine Maustaste wurde zuletzt gedr�ckt unsigned uButtonLast; // Wann wurde eine Maustaste wurde zuletzt gedr�ckt unsigned uToolTipSize; // Textspeichergr��e f�r Tooltip LPTSTR pToolTipText; // Textspeicher f�r Tooltip TCHAR cTempText1 [260]; // Erster Textpuffer f�r Callbacks TCHAR cTempText2 [260]; // Zeiter Textpuffer f�r Callbacks ColumnData aColumn [MAX_COLUMNS]; // Daten der Spalten int aColumnXpos [MAX_COLUMNS + 2]; // Array mit den Positionen der Spalten BYTE aColumnPos [MAX_COLUMNS + 2]; // Array mit Anzeigepositionen der Spalten char cColorChanged[MAX_COLORS ]; // Welche Farbe wurden ver�ndert char cColumnStart; // Wurde das Autoeditiren mit einer WM_CHAR Eingabe gestartet char cFixedHeight; // Ist eine fixe H�he eingestellt char cLockChanges; // Sperren von Fenster�nderungen char cHasRootRow; // Wird gesetzt wenn eine Root-Spalte eingef�gt wird char cKeyIgnore; // Die n�chste Taste nicht f�r Sucher verwenden char cClickFlag; // Merker f�r LBUTTON-DOWN bei Multiselect char cClickEdit; // Merker f�r LBUTTON-DOWN bei Edit-Click char cIsEnabled; // Ist das Fenster freigegeben char cHasFocus; // Hat das Fenster den Focus char cReSelect; // Soll die Auswahl neu selektiert werden char cGlyphOk; // Die Schaltf�che �ber Themen zeichnen char cEditCb; // Muss das Edit-Fenster einen Callback aufrufen char cButtonFlag; // Welche Maustaste wurde zuletzt gedr�ckt} TreeListData;
typedef HRESULT(WINAPI *SetWindowThemeT)(HWND, LPCWSTR, LPCWSTR);typedef HRESULT(WINAPI *EndBufferedPtT)(HANDLE, BOOL);typedef HANDLE(WINAPI *BeginBufferedPnT)(HDC, RECT *, DWORD, LPVOID, HDC *);typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);typedef LPVOID (WINAPI *OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList);typedef HRESULT(WINAPI *CloseThemeDataT)(LPVOID);typedef HRESULT(WINAPI *DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT *);typedef HRESULT(WINAPI *GetThemeBackgRcT)(LPVOID, HDC, int, int, LPCRECT, LPRECT);typedef BOOL (WINAPI *IsAppThemedT)();typedef BOOL (WINAPI *IsThemeActiveT)();
static HMODULE hUxThemeDll = NULL;static SetWindowThemeT pSetWindowTheme = NULL;static EndBufferedPtT pEndBufferedPt = NULL;static BeginBufferedPnT pBeginBufferedPt = NULL;static BufferedPtInitT pBufferedPtInit = NULL;static BufferedPtInitT pBufferedPtExit = NULL;static OpenThemeDataT pOpenThemeData = NULL;static CloseThemeDataT pCloseThemeData = NULL;static DrawThemeBackgT pDrawThemeBackg = NULL;static GetThemeBackgRcT pGetThemeBackgRc = NULL;static IsAppThemedT pIsAppThemed = NULL;static IsThemeActiveT pIsThemeActive = NULL;static HPEN hPatternPen = NULL;static HFONT hDefaultFontN = NULL;static HFONT hDefaultFontB = NULL;static LONG lWindowCount = -1;#ifndef __REACTOS__static RECT sToolRect = { -2, 0, 2, 64};#endifstatic TCHAR cKeyData[16];static unsigned uKeyLast;static unsigned uKeyPos;static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect);static LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode);static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect);static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam);static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam);static int TreeListEndLabelEdit(TreeListData *pData, int iMode);static BOOL bDrawWithTheme = FALSE;
//*****************************************************************************//*//* TreeListRegister//*//*****************************************************************************// Registiert das TreeList Fenster.// Ergibt 1 wenn das Fenster erfolgreich registiert wurde.int TreeListRegister(HINSTANCE hInstance) {
static int iIsRegistered = FALSE; WNDCLASSEX sClass;
OutputDebugString(TEXT("TreeListRegister() - before checking\n"));
if(iIsRegistered) return TRUE;
OutputDebugString(TEXT("TreeListRegister() - before registration\n"));
memset(&sClass, 0, sizeof(sClass)); sClass.cbSize = sizeof(sClass); sClass.style = CS_DBLCLKS | CS_GLOBALCLASS; sClass.lpfnWndProc = TreeListProc; sClass.cbClsExtra = 0; sClass.cbWndExtra = sizeof(TreeListData *); sClass.hInstance = hInstance; sClass.hIcon = NULL; sClass.hCursor = LoadCursor(NULL, IDC_ARROW); sClass.hbrBackground = NULL; sClass.lpszMenuName = NULL; sClass.hIconSm = NULL; sClass.lpszClassName = _T(TVC_CLASSNAME);
if(!RegisterClassEx(&sClass)) return 0;
OutputDebugString(TEXT("TreeListRegister() - registration done\n")); iIsRegistered = TRUE;
return TRUE;}
BOOL TreeListUnregister(HINSTANCE hInstance){ return UnregisterClass(_T(TVC_CLASSNAME),hInstance);}
//*****************************************************************************//*//* GlobalInit//*//*****************************************************************************static void GlobalInit() {
LOGBRUSH sLog; long lCount;
lCount = InterlockedIncrement(&lWindowCount); if(lCount > 0) return;
sLog.lbColor = GetSysColor(COLOR_BTNSHADOW); sLog.lbStyle = PS_SOLID; sLog.lbHatch = 0; hPatternPen = ExtCreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &sLog, 0, NULL);
if(!hPatternPen) { hPatternPen = CreatePen(PS_DOT, 1, RGB(0, 0, 0)); }
if(!hUxThemeDll) { hUxThemeDll = LoadLibrary(_T("UxTheme.dll")); if(hUxThemeDll) { pSetWindowTheme = (SetWindowThemeT)GetProcAddress(hUxThemeDll, "SetWindowTheme"); pEndBufferedPt = (EndBufferedPtT)GetProcAddress(hUxThemeDll, "EndBufferedPaint"); pBeginBufferedPt = (BeginBufferedPnT)GetProcAddress(hUxThemeDll, "BeginBufferedPaint"); pBufferedPtInit = (BufferedPtInitT)GetProcAddress(hUxThemeDll, "BufferedPaintInit"); pBufferedPtExit = (BufferedPtInitT)GetProcAddress(hUxThemeDll, "BufferedPaintUnInit"); pOpenThemeData = (OpenThemeDataT)GetProcAddress(hUxThemeDll, "OpenThemeData"); pCloseThemeData = (CloseThemeDataT)GetProcAddress(hUxThemeDll, "CloseThemeData"); pDrawThemeBackg = (DrawThemeBackgT)GetProcAddress(hUxThemeDll, "DrawThemeBackground"); pGetThemeBackgRc = (GetThemeBackgRcT)GetProcAddress(hUxThemeDll, "GetThemeBackgroundContentRect"); pIsAppThemed = (IsAppThemedT)GetProcAddress(hUxThemeDll, "IsAppThemed"); pIsThemeActive = (IsThemeActiveT)GetProcAddress(hUxThemeDll, "IsThemeActive");
if(pIsAppThemed && pIsThemeActive) bDrawWithTheme = pIsAppThemed() && pIsThemeActive(); } }
if(pBufferedPtInit) { pBufferedPtInit(); }
}
//*****************************************************************************//*//* GlobalDeinit//*//*****************************************************************************static void GlobalDeinit() {
int lCount;
lCount = InterlockedDecrement(&lWindowCount); if(lCount >= 0) return;
if(hDefaultFontN) { DeleteObject(hDefaultFontN); hDefaultFontN = NULL; }
if(hDefaultFontB) { DeleteObject(hDefaultFontB); hDefaultFontB = NULL; }
if(hPatternPen) { DeleteObject(hPatternPen); hPatternPen = NULL; }
if(pBufferedPtExit) { pBufferedPtExit(); }
}
//*****************************************************************************//*//* SendNotify//*//*****************************************************************************// Sendet eine WM_NOTIFY Nachricht and das Elternfenster// pData : Zeiger auf die Fensterdaten// pNotify : Zeiger auf die Notify-Daten// Ergibt den R�ckgabewert der WM_NOTIFY Nachrichstatic LRESULT SendNotify(TreeListData *pData, NMHDR *pNotify) {
pNotify->hwndFrom = pData->hWnd; pNotify->idFrom = GetWindowLong(pNotify->hwndFrom, GWL_ID);
return SendMessage(GetParent(pNotify->hwndFrom), WM_NOTIFY, pNotify->idFrom, (LPARAM)pNotify);}
//*****************************************************************************//*//* CallbackEntry//*//*****************************************************************************// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen// pData : Zeiger auf die Fensterdaten// pEntry : Zeiger auf den Eintrag// uItem : Nummer des Eintrages// uFlags : Welche Daten sollen abgefragt werden// Ergibt den R�ckgabewert der WM_NOTIFY Nachrichstatic void CallbackEntry(TreeListData *pData, BaseItem *pEntry, unsigned uItem, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
NMTVDISPINFO sInfo;
sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | uFlags; sInfo.item.lParam = pEntry->lParam; sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sInfo.item.state = pEntry->uState; sInfo.item.stateMask = 0xFFFFFFFF; sInfo.item.iImage = I_IMAGECALLBACK; sInfo.item.iSelectedImage = I_IMAGECALLBACK; sInfo.item.cChildren = I_CHILDRENCALLBACK;
if(uFlags & TVIF_TEXT) { if(*uTextSize) { pData->cTempText2[sizeof(pData->cTempText2) / sizeof(TCHAR) - 1] = 0; pData->cTempText2[0] = 0; sInfo.item.pszText = pData->cTempText2; sInfo.item.cchTextMax = sizeof(pData->cTempText2) / sizeof(TCHAR) - 1; } else { pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0; pData->cTempText1[0] = 0; sInfo.item.pszText = pData->cTempText1; sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1; } } else { sInfo.item.pszText = 0; sInfo.item.cchTextMax = 0; }
sInfo.hdr.hwndFrom = pData->hWnd; sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID); sInfo.hdr.code = TVN_GETDISPINFO;
UNLOCK(pData); SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo); LOCK(pData);
if(uFlags & TVIF_IMAGE) { if(!(pEntry->uState & TVIS_SELECTED)) *iImage = sInfo.item.iImage; } else if(uFlags & TVIF_SELECTEDIMAGE) { if(pEntry->uState & TVIS_SELECTED) *iImage = sInfo.item.iSelectedImage; }
if(uFlags & TVIF_CHILDREN) { switch(sInfo.item.cChildren) { case 0: pEntry->bFlags &= ~TVIX_HASBUTTON; pEntry->bFlags |= TVIX_VARBUTTON; break;
case 1: pEntry->bFlags &= ~TVIX_VARBUTTON; pEntry->bFlags |= TVIX_HASBUTTON; break;
default : pEntry->bFlags |= TVIX_VARBUTTON;
if(pEntry->uFirstChild) pEntry->bFlags |= TVIX_HASBUTTON; else pEntry->bFlags &= ~TVIX_HASBUTTON; } }
if(uFlags & TVIF_TEXT) { *pText = sInfo.item.pszText; *uTextSize = str_len(sInfo.item.pszText); pEntry->iTextPixels = 0; }
}
//*****************************************************************************//*//* CallbackExtra//*//*****************************************************************************// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen// pData : Zeiger auf die Fensterdaten// pEntry : Zeiger auf den Eintrag// uItem : Nummer des Eintrages// uFlags : Welche Daten sollen abgefragt werden// Ergibt den R�ckgabewert der WM_NOTIFY Nachrichstatic void CallbackExtra(TreeListData *pData, BaseItem *pEntry, ExtraItem *pExtra, unsigned uItem, unsigned uSub, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
NMTVDISPINFO sInfo;
sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | uFlags; sInfo.item.lParam = pEntry->lParam; sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sInfo.item.state = pExtra->uState; sInfo.item.state |= (pEntry->uState & TVIS_BASEFLAGS); sInfo.item.stateMask = 0xFFFFFFFF; sInfo.item.iImage = I_IMAGECALLBACK; sInfo.item.iSelectedImage = I_IMAGECALLBACK; sInfo.item.cChildren = uSub;
if(uFlags & TVIF_TEXT) { pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0; pData->cTempText1[0] = 0; sInfo.item.pszText = pData->cTempText1; sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1; } else { sInfo.item.pszText = 0; sInfo.item.cchTextMax = 0; }
sInfo.hdr.hwndFrom = pData->hWnd; sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID); sInfo.hdr.code = TVN_GETDISPINFO;
UNLOCK(pData); SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo); LOCK(pData);
if(uFlags & TVIF_IMAGE) *iImage = sInfo.item.iImage; if(uFlags & TVIF_TEXT) { *pText = sInfo.item.pszText; *uTextSize = str_len(sInfo.item.pszText); }
}
//*****************************************************************************//*//* EditProc//*//*****************************************************************************// Ist die Fensterfunktion f�r das Edit Fensterstatic LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
TreeListData *pData; WNDPROC pProc; DWORD dwStop; DWORD dwStart; DWORD dwCount; LRESULT lResult; HWND hParent; HWND hCombo; int iDelta; int iState; int iPos; int iId;
hParent = GetParent(hWnd); iId = GetWindowLong(hWnd, GWL_ID);
if(iId == 3) { hCombo = hWnd; pData = GetHandle(hParent); pProc = pData->pProcId3; } else { hCombo = hParent; hParent = GetParent(hParent); pData = GetHandle(hParent); pProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_USERDATA); }
if(uMsg == WM_KEYDOWN) { if(wParam == VK_RETURN) { SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd); return 0; }
if(wParam == VK_ESCAPE) { SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_ESCAPE), (LPARAM)hWnd); return 0; }
if((pData->uStyleEx & TVS_EX_STEPOUT) && !(GetAsyncKeyState(VK_SHIFT) & 0x8000)) { switch(wParam) { // Aus Fenster springen
case VK_UP: if(pData->uEditMode) break; PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd); PostMessage(hParent, WM_KEYDOWN, VK_UP , 0x00500001); PostMessage(hParent, WM_KEYUP , VK_UP , 0x00500001); return 0;
case VK_DOWN: if(pData->uEditMode) break; PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd); PostMessage(hParent, WM_KEYDOWN, VK_DOWN, 0x00500001); PostMessage(hParent, WM_KEYUP , VK_DOWN, 0x00500001); return 0;
case VK_LEFT: if(pData->uEditMode && iId == 3) break; SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop); if(dwStart || dwStop) break; PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd); PostMessage(hParent, WM_KEYDOWN, VK_LEFT, 0x00500001); PostMessage(hParent, WM_KEYUP , VK_LEFT, 0x00500001); return 0;
case VK_RIGHT: if(pData->uEditMode && iId == 3) break; SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop); dwCount = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0); if(dwCount > dwStart) break; if(dwCount > dwStop) break;
PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd); PostMessage(hParent, WM_KEYDOWN, VK_RIGHT, 0x00500001); PostMessage(hParent, WM_KEYUP , VK_RIGHT, 0x00500001); return 0; } }
if(wParam == VK_DOWN && pData->uEditMode) { if(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0)) { SendMessage(hCombo, CB_SHOWDROPDOWN, 1, 0); return 0; } } } else if(uMsg == WM_CHAR) { if(wParam == VK_RETURN) { return 0; }
if(wParam == VK_ESCAPE) { return 0; } } else if(uMsg == WM_COMMAND) { if(wParam == MAKELONG(3, EN_ESCAPE) || wParam == MAKELONG(3, EN_RETURN)) { SendMessage(hParent, WM_COMMAND, wParam, (LPARAM)hWnd); return 0; } } else if(uMsg == WM_MOUSEWHEEL) { iState = (int)CallWindowProc(pProc, hWnd, CB_GETDROPPEDSTATE, 0, 0); if(iState) { iDelta = (short)HIWORD(wParam); iDelta /= WHEEL_DELTA; iPos = (int)CallWindowProc(pProc, hWnd, CB_GETTOPINDEX, 0, 0); iPos -= iDelta; CallWindowProc(pProc, hWnd, CB_SETTOPINDEX, iPos, 0); return 0; } } else if(uMsg == WM_GETDLGCODE) { // Welche Tasten werden im Dialog benutzt return DLGC_WANTALLKEYS; } else if(uMsg == WM_SETTEXT) { lResult = CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);; SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_SETTEXT), (LPARAM)hWnd); return lResult; }
return CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);}
//*****************************************************************************//*//* ToolProc//*//*****************************************************************************// Ist die Fensterfunktion f�r das ToolTip Fensterstatic LRESULT CALLBACK ToolProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
TreeListData *pData; POINT sPoint; UINT uPos;
if(uMsg == WM_SETFOCUS) { SetFocus((HWND)lParam); return 0; }
pData = (TreeListData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) { // Mausklicks auf Tooltip zum Elternfenster sPoint.x = LOWORD(lParam); sPoint.y = HIWORD(lParam);
ClientToScreen(hWnd , &sPoint); ScreenToClient(pData->hWnd, &sPoint);
uPos = MAKELONG(sPoint.x, sPoint.y);
return TreeListProc(pData->hWnd, uMsg, wParam, uPos); }
return CallWindowProc(pData->pToolProc, hWnd, uMsg, wParam, lParam);}
//*****************************************************************************//*//* ChangeColSize//*//*****************************************************************************// �ndert die Gr��e der variablen Spalten// pData : Zeiger auf die Fensterdaten// iDelta : Ist die Gr��en�nderung in Pixelstatic void ChangeColSize(TreeListData *pData, int iDelta) {
unsigned uPos; HDITEM sItem; RECT sRect; TV_COLSIZE sNotify; int iWeight; int iValue; int iPoint; int iStart; int iSize; int iRest; int iOff; int iNum; int iCnt; int iAll; int iVar; int iFix;
sItem.mask = HDI_WIDTH; iAll = pData->iAllWeight; iCnt = pData->uColumnCountVar;
if(iCnt <= 1) { // Nur eine variable Spalte for(uPos = 0; uPos < pData->uColumnCount; uPos++) { iWeight = pData->aColumn[uPos].bWeight; if(!iWeight) continue;
iValue = pData->aColumn[uPos].sSize; iValue += iDelta; sItem.cxy = iValue;
pData->aColumn[uPos].sSize = (short)iValue; pData->iVarSize = iValue;
if(sItem.cxy < pData->aColumn[uPos].sMin) { sItem.cxy = pData->aColumn[uPos].sMin; }
if(pData->aColumn[uPos].sReal != sItem.cxy) { // �ndert sich die Breite pData->aColumn[uPos].sReal = (short)sItem.cxy; Header_SetItem(pData->hHeader, uPos, &sItem);
if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = uPos; sNotify.uIndex = pData->aColumn[uPos].bIndex; sNotify.uPosX = pData->aColumnXpos[uPos]; sNotify.iSize = sItem.cxy;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); } }
break; }
return; }
if(iDelta > 0) iStart = (pData->uSizeX) % iAll; else iStart = (pData->uSizeX - iDelta) % iAll;
iOff = 0;
for(uPos = 0;; uPos++) { // Suchen die Anfangsspalte iWeight = pData->aColumn[uPos].bWeight; if(!iWeight) continue;
iOff += iWeight; if(iOff > iStart) break; }
iPoint = 0; iSize = iDelta / iAll; iRest = iDelta % iAll; iNum = iRest; iOff -= iStart;
iWeight = iOff; iValue = pData->aColumn[uPos].sSize; iValue += iSize * iWeight; iPoint += iRest * iWeight; iValue += iPoint / iAll; iNum -= iPoint / iAll; iPoint %= iAll;
pData->aColumn[uPos].sSize = (short)iValue;
if(iWeight >= pData->aColumn[uPos].bWeight) { // Wurde die ganze Spalte berechnet iCnt--; iOff = 0; }
while(iCnt > 0) { uPos++;
if(uPos >= pData->uColumnCount) uPos = 0; iWeight = pData->aColumn[uPos].bWeight; if(!iWeight) continue;
iValue = pData->aColumn[uPos].sSize;
iCnt--; if(iCnt) { iValue += iSize * iWeight; iPoint += iRest * iWeight; iValue += iPoint / iAll; iNum -= iPoint / iAll; iPoint %= iAll; } else { iWeight -= iOff; iValue += iSize * iWeight; iValue += iNum; }
pData->aColumn[uPos].sSize = (short)iValue; }
iVar = 0; iFix = 0; iCnt = pData->uColumnCountVar;
for(uPos = 0; iCnt > 0; uPos++) { // Ausgeben der neuen Breiten iWeight = pData->aColumn[uPos].bWeight; if(!iWeight) { iFix += pData->aColumn[uPos].sSize; continue; }
iVar += pData->aColumn[uPos].sSize; sItem.cxy = pData->aColumn[uPos].sSize;
if(sItem.cxy < pData->aColumn[uPos].sMin) { sItem.cxy = pData->aColumn[uPos].sMin; }
if(pData->aColumn[uPos].sReal != sItem.cxy) { // �ndert sich die Breite pData->aColumn[uPos].sReal = (short)sItem.cxy; Header_SetItem(pData->hHeader, uPos, &sItem);
if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = uPos; sNotify.uIndex = pData->aColumn[uPos].bIndex; sNotify.uPosX = pData->aColumnXpos[uPos]; sNotify.iSize = sItem.cxy;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); } }
iCnt--; }
pData->iFixSize = iFix; pData->iVarSize = iVar;
if(iDelta > 0) { GetClientRect(pData->hHeader, &sRect); InvalidateRect(pData->hHeader, NULL, FALSE); }
}
//*****************************************************************************//*//* CreateToolTip//*//*****************************************************************************// Erzeugt ein ToolTip Fenster// pData : Zeiger auf die Fensterdatenstatic void CreateToolTip(TreeListData *pData) {
TOOLINFO sInfo;
if(pData->hToolTip) return;
pData->hToolTip = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, pData->hWnd, NULL, NULL, NULL); pData->pToolProc = (WNDPROC)GetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC);
sInfo.cbSize = sizeof(TOOLINFO); sInfo.uFlags = TTF_ABSOLUTE | TTF_TRACK | TTF_IDISHWND; sInfo.hwnd = pData->hWnd; sInfo.hinst = NULL; sInfo.uId = (LPARAM)(pData->hWnd); sInfo.lpszText = LPSTR_TEXTCALLBACK;
GetClientRect(pData->hWnd, &sInfo.rect); SendMessage(pData->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&sInfo); SendMessage(pData->hToolTip, TTM_SETMAXTIPWIDTH, 0, 10000); SetWindowLong(pData->hToolTip, GWL_ID, 2); SetWindowLongPtr(pData->hToolTip, GWLP_USERDATA, (LPARAM)pData); SetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC , (LPARAM)ToolProc);}
//*****************************************************************************//*//* CreateStateImageList//*//*****************************************************************************// Erzeugt eine Image-Liste mit zwei Checkboxen// pData : Zeiger auf die Fensterdaten// iMode : Welche Imageliste soll erzeugt werden (0=hStates 1=hChecks)static void CreateStateImageList(TreeListData *pData, int iMode) {
BITMAPINFO sInfo; BYTE aMem[0x1000]; HDC hDcSrc; HDC hDc; HBITMAP hBmp; HBITMAP hBmpNew; RECT sRect; int iBits;
if(pOpenThemeData) { // �ber Thema zeichnen if(!pData->hThemeBt) { pData->hThemeBt = pOpenThemeData(pData->hWnd, L"BUTTON"); }
if(pData->hThemeBt) { if(iMode) { if(pData->hChecks && pData->hChecks != THEMEIMGLIST) { ImageList_Destroy(pData->hChecks); }
pData->hChecks = THEMEIMGLIST; pData->iChecksXsize = 16; pData->iChecksYsize = 16; pData->iChecksMode = 1; } else { if(pData->hStates && pData->hStates != THEMEIMGLIST) { ImageList_Destroy(pData->hStates); }
pData->hStates = THEMEIMGLIST; pData->iStatesXsize = 16; pData->iStatesYsize = 16; pData->iStatesMode = 1; }
return; } }
if(iMode) { if(pData->hChecks && pData->hChecks != THEMEIMGLIST) return; } else { if(pData->hStates && pData->hStates != THEMEIMGLIST) return; }
hDcSrc = GetDC(NULL); hDc = CreateCompatibleDC(NULL); hBmp = CreateCompatibleBitmap(hDcSrc, 16 * 3, 16);
SelectObject(hDc, hBmp); SelectObject(hDc, GetStockObject(NULL_PEN)); SetBkMode(hDc, OPAQUE); SetBkColor(hDc, GetSysColor(COLOR_WINDOW)); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); Rectangle(hDc, -1, -1, 16 * 3 + 2, 16 + 2);
sRect.top = 8 - 6; sRect.bottom = 8 + 7; sRect.left = 16 * 1 + 8 - 7; sRect.right = 16 * 1 + 8 + 6;
DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT);
sRect.left = 16 * 2 + 8 - 7; sRect.right = 16 * 2 + 8 + 6;
DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT);
iBits = GetDeviceCaps(hDc, BITSPIXEL);
sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); sInfo.bmiHeader.biWidth = 16 * 3; sInfo.bmiHeader.biHeight = 16; sInfo.bmiHeader.biPlanes = 1; sInfo.bmiHeader.biBitCount = (WORD)iBits; sInfo.bmiHeader.biCompression = BI_RGB; sInfo.bmiHeader.biSizeImage = 0; sInfo.bmiHeader.biXPelsPerMeter = 0; sInfo.bmiHeader.biYPelsPerMeter = 0; sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;; sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS); GetDIBits(hDc, hBmp, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
hBmpNew = CreateCompatibleBitmap(hDc, 16 * 3, 16);
SetDIBits(hDc, hBmpNew, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
if(iMode == 0) { pData->hStates = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14); pData->iStatesXsize = 16; pData->iStatesYsize = 16; pData->iStatesMode = 1;
ImageList_AddMasked(pData->hStates, hBmpNew, GetSysColor(COLOR_HIGHLIGHT)); } else { pData->hChecks = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14); pData->iChecksXsize = 16; pData->iChecksYsize = 16; pData->iChecksMode = 1;
ImageList_AddMasked(pData->hChecks, hBmpNew, GetSysColor(COLOR_HIGHLIGHT)); }
DeleteObject(hBmpNew); DeleteObject(hBmp); DeleteDC(hDc); ReleaseDC(NULL, hDcSrc);}
//*****************************************************************************//*//* CreateDragImage//*//*****************************************************************************// Erzeugt eine Image-Liste mit zwei Checkboxen// pData : Zeiger auf die Fensterdaten// uSub : Ist die Spalte f�r die das Drag-Image erzeugt werden soll// Ergibt ein Handle mit der Imageliste oder NULL bei einem Fehlerstatic HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub) {
ExtraItem *pExtra; BaseItem *pEntry; HIMAGELIST hList; BITMAPINFO sInfo; BYTE *pMem; HDC hDcSrc; HDC hDc; HBITMAP hBmp; HBITMAP hBmpNew; RECT sRect; unsigned uTSize; int iAdd; int iBits; int iWidth; int iHeigh; int iImage; int iYpos; LPCTSTR pText;
if(uItem > pData->uTreeItemsMax) return NULL;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
iHeigh = pData->iFontHeight;
if(uSub) { // Image f�r Extraeintrag erzeugen if(uSub >= pData->uColumnCount) return 0;
pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) { pText = _T("????"); uTSize = 4; iImage = -1; iWidth = pData->iFontHeight * 4; } else { pText = pExtra->pText; uTSize = pExtra->uTextSize; iImage = pExtra->iImage; iWidth = pExtra->iTextPixels;
if(pExtra->bCallback & (TVIF_IMAGE | TVIF_TEXT)) { CallbackExtra(pData, pEntry, pExtra, uItem, uSub, pExtra->bCallback, &iImage, &uTSize, &pText); } } } else { // Image f�r Haupteintrag erzeugen pText = pEntry->pText; uTSize = pEntry->uTextSize; iImage = pEntry->iImage; iWidth = pEntry->iTextPixels;
if(pEntry->bCallback & (TVIF_IMAGE | TVIF_TEXT)) { CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTSize, &pText); } }
if(pData->hImages && iImage >= 0) { // Gr��en f�r Images anpassen if(iHeigh < pData->iImagesYsize) iHeigh = pData->iImagesYsize; iAdd = pData->iImagesXsize + 2; iWidth += iAdd; } else { iAdd = 0; iImage = 1; }
if(iWidth > 240) iWidth = 240; if(iHeigh > 32) iHeigh = 32;
pMem = new(BYTE, iHeigh * (iWidth + 4) * 4 + 1024); if(!pMem) return NULL;
hDcSrc = GetDC(NULL); hDc = CreateCompatibleDC(NULL); hBmp = CreateCompatibleBitmap(hDcSrc, iWidth, iHeigh);
SelectObject(hDc, hBmp); SelectObject(hDc, GetStockObject(NULL_PEN)); SelectObject(hDc, (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN); SetTextColor(hDc, pData->uColors[TVC_TEXT]); SetBkColor(hDc, RGB(123, 77, 91));
sRect.top = 0; sRect.bottom = iHeigh; sRect.left = 0; sRect.right = iWidth; iYpos = (iHeigh - pData->iFontHeight) / 2;
ExtTextOut(hDc, iAdd, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sRect, pText, uTSize, NULL);
if(iImage >= 0) { SetBkColor(hDc, GetSysColor(COLOR_WINDOW)); ImageList_Draw(pData->hImages, iImage, hDc, 0, 0, ILD_TRANSPARENT); }
iBits = GetDeviceCaps(hDc, BITSPIXEL);
sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); sInfo.bmiHeader.biWidth = iWidth; sInfo.bmiHeader.biHeight = iHeigh; sInfo.bmiHeader.biPlanes = 1; sInfo.bmiHeader.biBitCount = (WORD)iBits; sInfo.bmiHeader.biCompression = BI_RGB; sInfo.bmiHeader.biSizeImage = 0; sInfo.bmiHeader.biXPelsPerMeter = 0; sInfo.bmiHeader.biYPelsPerMeter = 0; sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;; sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS); GetDIBits(hDc, hBmp, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
hBmpNew = CreateCompatibleBitmap(hDc, iWidth, iHeigh);
SetDIBits(hDc, hBmpNew, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
hList = ImageList_Create(iWidth, iHeigh, ILC_COLORDDB | ILC_MASK, 1, 0);
ImageList_AddMasked(hList, hBmpNew, RGB(123, 77, 91));
DeleteObject(hBmpNew); DeleteObject(hBmp); DeleteDC(hDc); ReleaseDC(NULL, hDcSrc);
delete(pMem);
return hList;}
//*****************************************************************************//*//* UpdateColorsList//*//*****************************************************************************// Aktualisiert alle Farben// pData : Zeiger auf die Fensterdatenstatic void UpdateColorsList(TreeListData *pData) {
unsigned uColOdd; unsigned uColor; int iDiff; int iSum;
if(!pData->cColorChanged[TVC_BK ]) pData->uColors[TVC_BK ] = GetSysColor(COLOR_WINDOW); if(!pData->cColorChanged[TVC_BOX ]) pData->uColors[TVC_BOX ] = GetSysColor(COLOR_BTNSHADOW); if(!pData->cColorChanged[TVC_EVEN ]) pData->uColors[TVC_EVEN ] = GetSysColor(COLOR_WINDOW); if(!pData->cColorChanged[TVC_TEXT ]) pData->uColors[TVC_TEXT ] = GetSysColor(COLOR_WINDOWTEXT); if(!pData->cColorChanged[TVC_LINE ]) pData->uColors[TVC_LINE ] = GetSysColor(COLOR_WINDOWTEXT); if(!pData->cColorChanged[TVC_FRAME ]) pData->uColors[TVC_FRAME ] = GetSysColor(COLOR_3DFACE); if(!pData->cColorChanged[TVC_TRACK ]) pData->uColors[TVC_TRACK ] = GetSysColor(COLOR_WINDOWTEXT) ^ RGB(0, 0, 255); if(!pData->cColorChanged[TVC_INSERT ]) pData->uColors[TVC_INSERT ] = GetSysColor(COLOR_INFOBK); if(!pData->cColorChanged[TVC_ODD ]) pData->uColors[TVC_ODD ] = GetSysColor(COLOR_INFOBK); if(!pData->cColorChanged[TVC_BOXBG ]) pData->uColors[TVC_BOXBG ] = GetSysColor(COLOR_WINDOW); if(!pData->cColorChanged[TVC_COLBK ]) pData->uColors[TVC_COLBK ] = GetSysColor(COLOR_WINDOW); if(!pData->cColorChanged[TVC_COLODD ]) pData->uColors[TVC_COLODD ] = GetSysColor(COLOR_BTNSHADOW); if(!pData->cColorChanged[TVC_COLEVEN]) pData->uColors[TVC_COLEVEN] = GetSysColor(COLOR_WINDOW); if(!pData->cColorChanged[TVC_GRAYED ]) pData->uColors[TVC_GRAYED ] = GetSysColor(COLOR_SCROLLBAR);
if(pData->hTheme && !pData->cColorChanged[TVC_BOXBG] && !pData->cColorChanged[TVC_BOX] && !pData->cColorChanged[TVC_LINE]) { pData->cGlyphOk = 1; } else { pData->cGlyphOk = 0; }
if(!pData->cColorChanged[TVC_GRAYED]) { pData->uColors[TVC_GRAYED] = (GetSysColor(COLOR_SCROLLBAR) & 0x00FEFEFE) >> 1; pData->uColors[TVC_GRAYED] += (GetSysColor(COLOR_WINDOW) & 0x00FEFEFE) >> 1; }
if(!pData->cColorChanged[TVC_ODD]) { uColOdd = pData->uColors[TVC_ODD]; iDiff = ((uColOdd) & 0xFF) - ((pData->uColors[TVC_EVEN]) & 0xFF); iSum = iDiff * iDiff; iDiff = ((uColOdd >> 8) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 8) & 0xFF); iSum += iDiff * iDiff; iDiff = ((uColOdd >> 16) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 16) & 0xFF); iSum += iDiff * iDiff;
if(iSum < 64) { // Ist die alternierente Farbe fast gleich ? uColOdd = pData->uColors[TVC_EVEN] & 0x0000FFFF; uColOdd |= ((pData->uColors[TVC_EVEN] & 0x00FF0000) - 0x00080000) & 0x00FF0000; }
pData->uColors[TVC_ODD] = uColOdd; }
if(!pData->cColorChanged[TVC_COLBK]) { uColor = GetSysColor(COLOR_WINDOW); if(uColor & 0x00F00000) uColor -= 0x00100000; if(uColor & 0x0000F000) uColor -= 0x00001000; if(uColor & 0x000000F0) uColor -= 0x00000010;
pData->uColors[TVC_COLBK] = uColor; }
if(!pData->cColorChanged[TVC_COLODD]) { uColor = pData->uColors[TVC_ODD]; if(uColor & 0x00F00000) uColor -= 0x00100000; if(uColor & 0x0000F000) uColor -= 0x00001000; if(uColor & 0x000000F0) uColor -= 0x00000010;
pData->uColors[TVC_COLODD] = uColor; }
if(!pData->cColorChanged[TVC_COLEVEN]) { uColor = GetSysColor(COLOR_WINDOW); if(uColor & 0x00F00000) uColor -= 0x00100000; if(uColor & 0x0000F000) uColor -= 0x00001000; if(uColor & 0x000000F0) uColor -= 0x00000010;
pData->uColors[TVC_COLEVEN] = uColor; }
if(!pData->cColorChanged[TVC_MARKODD ]) pData->uColors[TVC_MARKODD ] = ((pData->uColors[TVC_ODD ] >> 3) & 0x1F1F1F) * 7; if(!pData->cColorChanged[TVC_MARKODD ]) pData->uColors[TVC_MARKODD ] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1; if(!pData->cColorChanged[TVC_MARKEVEN]) pData->uColors[TVC_MARKEVEN] = ((pData->uColors[TVC_EVEN ] >> 3) & 0x1F1F1F) * 7; if(!pData->cColorChanged[TVC_MARKEVEN]) pData->uColors[TVC_MARKEVEN] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1;}
//*****************************************************************************//*//* UpdateHeight//*//*****************************************************************************// Checks if the row height has changed// pData : pointer to the window data// Returns 1 if changed or 0 else.static int UpdateHeight(TreeListData *pData) {
int iHeight; RECT sRect;
if(pData->cFixedHeight) return 0;
iHeight = 10;
if(pData->hChecks) if(iHeight < pData->iChecksYsize + 2) iHeight = pData->iChecksYsize + 2; if(pData->hStates) if(iHeight < pData->iStatesYsize + 2) iHeight = pData->iStatesYsize + 2; if(iHeight < pData->iSubImgYsize + 2) iHeight = pData->iSubImgYsize + 2; if(iHeight < pData->iImagesYsize + 2) iHeight = pData->iImagesYsize + 2; if(iHeight < pData->iFontHeight + 2) iHeight = pData->iFontHeight + 2; if(pData->uStyleEx & TVS_EX_ITEMLINES) iHeight++; if(pData->uStyle & TVS_NONEVENHEIGHT && (iHeight & 1)) iHeight++; if(pData->iRowHeight == iHeight) return 0;
pData->iRowHeight = iHeight;
if(pData->uSizeY > pData->uStartPixel) { pData->uMaxEnties = pData->uSizeY; pData->uMaxEnties -= pData->uStartPixel; } else { pData->uMaxEnties = 0; }
pData->uPageEnties = pData->uMaxEnties; pData->uMaxEnties += pData->iRowHeight - 1; pData->uMaxEnties /= pData->iRowHeight; pData->uPageEnties /= pData->iRowHeight;
GetClientRect(pData->hWnd, &sRect); InvalidateRect(pData->hWnd, &sRect, FALSE);
return 1;}
//*****************************************************************************//*//* UpdateRect//*//*****************************************************************************// Zeichnet einen Eintrag neu// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Ist die Spaltennummer// Ergibt 1 wenn der Eintrag sichtbar warstatic int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub) {
BaseItem *pEntry; RECT sRect; UINT uNext; UINT uPos;
pEntry = pData->pTreeItems[uItem]; if(!pEntry || !pEntry->uShowPos) return 0; // Ist der Eintrag aufgeklappt
uPos = pEntry->uShowPos - pData->uScrollY - 1; if(uPos >= pData->uMaxEnties) return 0; // Eintrag im Fenster sichtbar
uNext = pData->aColumn[uSub].bNext; sRect.left = pData->aColumnXpos[uSub ]; sRect.left -= pData->uScrollX; sRect.right = pData->aColumnXpos[uNext]; sRect.right -= pData->uScrollX; sRect.top = pData->uStartPixel; sRect.top += pData->iRowHeight * uPos; sRect.bottom = pData->iRowHeight + sRect.top;
InvalidateRect(pData->hWnd, &sRect, FALSE);
return 1;}
//*****************************************************************************//*//* UpdateColRect//*//*****************************************************************************// Zeichnet einen ganze Spalte neu// pData : Zeiger auf die Fensterdaten// uColumn : Die nummer der Spalte// Ergibt 1 wenn der Eintrag sichtbar warstatic int UpdateColRect(TreeListData *pData, unsigned uColumn) {
RECT sRect; UINT uNext;
if(uColumn >= pData->uColumnCount) return 0;
sRect.left = pData->aColumnXpos[uColumn]; sRect.left -= pData->uScrollX; if(sRect.left > (int)pData->uSizeX) return 0;
uNext = pData->aColumn[uColumn].bNext;
sRect.right = pData->aColumnXpos[uNext]; sRect.right -= pData->uScrollX; if(sRect.right < 0) return 0;
sRect.top = 0; sRect.bottom = pData->uSizeY;
InvalidateRect(pData->hWnd, &sRect, FALSE);
return 1;}
//*****************************************************************************//*//* UpdateRow//*//*****************************************************************************// Zeichnet einen Eintrag �ber die ganze Zeile neu// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// Ergibt 1 wenn der Eintrag sichtbar warstatic int UpdateRow(TreeListData *pData, unsigned uItem) {
BaseItem *pEntry; RECT sRect; unsigned uPos;
pEntry = pData->pTreeItems[uItem]; if(!pEntry || !pEntry->uShowPos) return 0; // Ist der Eintrag aufgeklappt
uPos = pEntry->uShowPos - pData->uScrollY - 1; if(uPos >= pData->uMaxEnties) return 0; // Eintrag im Fenster sichtbar
sRect.left = 0; sRect.right = pData->uSizeX; sRect.top = pData->uStartPixel; sRect.top += pData->iRowHeight * uPos; sRect.bottom = pData->iRowHeight + sRect.top; InvalidateRect(pData->hWnd, &sRect, FALSE);
return 1;}
//*****************************************************************************//*//* UpdateView//*//*****************************************************************************// Redraw the whole window// pData : Zeiger auf die Fensterdaten// Ergibt 1 wenn der Eintrag sichtbar warstatic void UpdateView(TreeListData *pData) {
RECT sRect;
GetClientRect(pData->hWnd, &sRect); sRect.top = pData->uStartPixel; InvalidateRect(pData->hWnd, &sRect, FALSE);
if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HIDEHEADERS) == 0)){ GetClientRect(pData->hHeader, &sRect); InvalidateRect(pData->hHeader, &sRect, FALSE); }}
//*****************************************************************************//*//* UpdateScrollX//*//*****************************************************************************// Aktualisiert die X-Scroolbar// pData : Zeiger auf die Fensterdaten// Ergibt 1 wenn der sich Einstellungen ver�ndert habenstatic void UpdateScrollX(TreeListData *pData) {
SCROLLINFO sInfo; unsigned uSize; unsigned uCols;
uCols = pData->uColumnCount; if(uCols) uSize = pData->aColumnXpos[uCols] - 1; else uSize = pData->iMaxSizeX - 1;
if(pData->uOldXCount == uSize) if(pData->uOldXPage == pData->uSizeX) { return; }
pData->uOldXPage = pData->uSizeX; pData->uOldXCount = uSize;
UNLOCK(pData);
sInfo.cbSize = sizeof(SCROLLINFO); sInfo.fMask = SIF_ALL; sInfo.nMin = 0; sInfo.nMax = uSize; sInfo.nPage = pData->uSizeX; sInfo.nPos = pData->uScrollX; sInfo.nTrackPos = 0;
if(pData->uStyle & TVS_NOSCROLL) { sInfo.nMax = 0; } else if(pData->uStyleEx & TVS_EX_AUTOHSCROLL) { sInfo.nMax = 0; } else if(sInfo.nMax > 0) { sInfo.nMax--; }
if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollX > 0) { sInfo.nPos = 0; pData->uScrollX = 0;
UpdateView(pData);
if(pData->hHeader) { MoveWindow(pData->hHeader, 0, 0, pData->uSizeX, pData->uStartPixel, TRUE); } }
SetScrollInfo(pData->hWnd, SB_HORZ, &sInfo, TRUE);
LOCK(pData);}
//*****************************************************************************//*//* UpdateScrollY//*//*****************************************************************************// Aktualisiert die Y-Scroolbar// pData : Zeiger auf die Fensterdaten// Ergibt 1 wenn der sich Einstellungen ver�ndert habenstatic void UpdateScrollY(TreeListData *pData) {
SCROLLINFO sInfo;
if(pData->uOldYCount == pData->uItemPosCount) if(pData->uOldYPage == pData->uPageEnties) { return; }
pData->uOldYPage = pData->uPageEnties; pData->uOldYCount = pData->uItemPosCount;
UNLOCK(pData);
sInfo.cbSize = sizeof(SCROLLINFO); sInfo.fMask = SIF_ALL; sInfo.nMin = 0; sInfo.nMax = pData->uItemPosCount; sInfo.nPage = pData->uPageEnties; sInfo.nPos = pData->uScrollY; sInfo.nTrackPos = 0;
if(pData->uStyle & TVS_NOSCROLL) { sInfo.nMax = 0; }
if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollY > 0) { sInfo.nPos = 0; pData->uScrollY = 0;
UpdateView(pData); }
SetScrollInfo(pData->hWnd, SB_VERT, &sInfo, TRUE);
LOCK(pData);}
//*****************************************************************************//*//* UpdateToolTip//*//*****************************************************************************// Aktualisiert den Text f�r das Tootip// pData : Zeiger auf Fensterdaten// uItem : Item auf den der Mauszeiger zeigt// uFlags : Flags vom HitTeststatic void UpdateToolTip(TreeListData *pData, unsigned uItem, unsigned uFlags) {
TCHAR cTemp[INFOTIPSIZE];#ifndef __REACTOS__ HWND hToolTip;#endif NMTVGETINFOTIP sToolNv; NMTREEVIEW sNotify; TOOLINFO sInfo; ExtraItem *pExtra; BaseItem *pEntry; LPCTSTR pText; RECT sRect; unsigned uSize; unsigned uCol; unsigned uLen; LRESULT lRet; int iTemp; // Tooltip ausbelnden if(!uItem || (uItem == pData->uEditItem && TVHT_SUBTOCOL(uFlags) == pData->uEditSub)) { if(pData->uToolTipItem) goto ExitTip; return; }
pEntry = pData->pTreeItems[uItem];
if(uFlags & TVHT_ONITEM) { if(pData->uToolTipItem != uItem || pData->uToolTipSub != 0) { if(!pData->pTreeItems[uItem]) { // Existiert der Eintag noch ? goto ExitTip; }
TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
if(sRect.right > (int)pData->uSizeX) { sRect.right = pData->uSizeX; }
lRet = 0;
if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via speziellem Notify holen sNotify.hdr.code = TVN_ITEMTOOLTIP; sNotify.action = 0; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.pszText = pEntry->pText; sNotify.itemNew.cchTextMax = pEntry->uTextSize; sNotify.itemNew.cChildren = 0; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = sRect.left; sNotify.ptDrag.y = sRect.top;
UNLOCK(pData); lRet = SendNotify(pData, &sNotify.hdr); LOCK(pData);
if(lRet) goto UserTip; } else if(pData->uStyle & TVS_INFOTIP) { // Tooltip-Daten via normalem Notify holen sToolNv.hdr.code = TVN_GETINFOTIP; sToolNv.cchTextMax = INFOTIPSIZE; sToolNv.hItem = (HTREEITEM)(ULONG_PTR)uItem; sToolNv.lParam = pEntry->lParam; sToolNv.pszText = cTemp;
str_ncpy(cTemp, pEntry->pText, INFOTIPSIZE); cTemp[INFOTIPSIZE - 1] = 0;
UNLOCK(pData); lRet = SendNotify(pData, &sNotify.hdr); LOCK(pData);
sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.pszText = sToolNv.pszText; sNotify.itemNew.cchTextMax = str_len(sToolNv.pszText); sNotify.itemNew.cChildren = 0; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.ptDrag.x = sRect.left; sNotify.ptDrag.y = sRect.top;
goto UserTip; } // Passt der Text in die Spalte if(sRect.right - sRect.left <= pEntry->iTextPixels + 4) { pText = pEntry->pText; uSize = pEntry->uTextSize;
if(pEntry->bCallback & TVIF_TEXT) { CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText); }
if(!pText || *pText == 0) goto ExitTip;
uLen = str_len(pText) + 1; if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern delete(pData->pToolTipText); pData->uToolTipSize = (uLen + 255)&~0xFF; pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4); }
memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR)); pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
#ifndef __REACTOS__ hToolTip = pData->hToolTip;#endif pData->sToolTipPos.x = sRect.left; pData->sToolTipPos.y = sRect.top;
ClientToScreen(pData->hWnd, &pData->sToolTipPos);
UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
if(pData->uToolTipItem) { SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo); pData->uToolTipItem = 0; }
SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y)); SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
LOCK(pData);
pData->uToolTipItem = uItem; pData->uToolTipShow = 0; pData->uToolTipSub = 0;
SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL); } else { if(pData->uToolTipItem) goto ExitTip; } }
return; }
if(uFlags & (TVHT_ONSUBICON | TVHT_ONSUBLABEL)) { if(pData->uToolTipItem != uItem || TVHT_SUBTOCOL(uFlags) != pData->uToolTipSub) { lRet = 0; uCol = TVHT_SUBTOCOL(uFlags); pExtra = pData->pExtraItems[uCol - 1][uItem];
if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via Notify holen TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol), &sRect);
if(sRect.right > (int)pData->uSizeX) { sRect.right = pData->uSizeX; }
if(pExtra) { sNotify.itemNew.state = pExtra->uState; sNotify.itemNew.pszText = pExtra->pText; sNotify.itemNew.cchTextMax = pExtra->uTextSize; } else { sNotify.itemNew.state = 0; sNotify.itemNew.cchTextMax = 0; sNotify.itemNew.pszText = _T(""); }
sNotify.hdr.code = TVN_ITEMTOOLTIP; sNotify.action = 0; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.cChildren = uCol; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = sRect.left; sNotify.ptDrag.y = sRect.top;
UNLOCK(pData); lRet = SendNotify(pData, &sNotify.hdr); LOCK(pData);
if(lRet) goto UserTip; }
if(pExtra) { // Tooltip auf Unterspalte ? TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol), &sRect);
if(sRect.right > (int)pData->uSizeX) { sRect.right = pData->uSizeX; }
if(sRect.right - sRect.left <= pExtra->iTextPixels + 4) { pText = pExtra->pText; uSize = pExtra->uTextSize;
if(pExtra->bCallback & TVIF_TEXT) { CallbackExtra(pData, pEntry, pExtra, uItem, uCol, TVIF_TEXT, &iTemp, &uSize, &pText); }
if(!pText || *pText == 0) goto ExitTip;
uLen = str_len(pText) + 1; if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern delete(pData->pToolTipText); pData->uToolTipSize = (uLen + 255)&~0xFF; pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4); }
memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR)); pData->hFontT = (pExtra->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
pData->sToolTipPos.x = sRect.left; pData->sToolTipPos.y = sRect.top;#ifndef __REACTOS__ hToolTip = pData->hToolTip;#endif
ClientToScreen(pData->hWnd, &pData->sToolTipPos);
UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
if(pData->uToolTipItem) { SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo); pData->uToolTipItem = 0; }
SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y)); SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
LOCK(pData);
pData->uToolTipItem = uItem; pData->uToolTipSub = uCol; pData->uToolTipShow = 0;
SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL); } else { if(pData->uToolTipItem) goto ExitTip; } } else { if(pData->uToolTipItem) goto ExitTip; } }
return; }
ExitTip:
if(pData->uToolTipItem) { // Tooltip ausblenden UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
LOCK(pData);
pData->uToolTipItem = 0; pData->uToolTipSub = 0; pData->uToolTipShow = 0;
KillTimer(pData->hWnd, ID_TOOLTIPCHECK); }
return;
UserTip:
pText = sNotify.itemNew.pszText; // Soll ein User-Tooltip angezeigt werden uSize = sNotify.itemNew.cchTextMax; sRect.left = sNotify.ptDrag.x; sRect.top = sNotify.ptDrag.y;
if(!pText || *pText == 0) goto ExitTip;
uLen = str_len(pText) + 1; if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern
delete(pData->pToolTipText); pData->uToolTipSize = (uLen + 255)&~0xFF; pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4); }
memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR)); pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
ClientToScreen(pData->hWnd, &sNotify.ptDrag); pData->sToolTipPos = sNotify.ptDrag;#ifndef __REACTOS__ hToolTip = pData->hToolTip;#endif // Tooltip verz�gert anzeigen if((sNotify.itemNew.mask & TVIF_TOOLTIPTIME) && sNotify.itemNew.lParam > 0) { pData->uToolTipShow = (unsigned)(sNotify.itemNew.lParam + 499) / 500; pData->uToolTipSub = sNotify.itemNew.cChildren; pData->uToolTipItem = uItem;
SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 500, NULL);
return; }
UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
if(pData->uToolTipItem) { // Tooltip Fenster aktivieren SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo); pData->uToolTipItem = 0; }
SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(sNotify.ptDrag.x, sNotify.ptDrag.y)); SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
LOCK(pData);
pData->uToolTipShow = 0; pData->uToolTipItem = uItem; pData->uToolTipSub = sNotify.itemNew.cChildren;
SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);}
//*****************************************************************************//*//* CreateFontset//*//*****************************************************************************// Create the font set (normal, bold, etc...) from the given HFONTstatic int CreateFontset(TreeListData *pData, HFONT hFont){ LOGFONT sLog; HFONT hBold; int iRet = 0; if(GetObject(hFont, sizeof(sLog), &sLog)){ sLog.lfWeight = FW_BOLD; if((hBold = CreateFontIndirect(&sLog))){ pData->hFontN = hFont; //store the given font if(pData->hFontB != hDefaultFontB){ //if the current bold is not the default bold, free it DeleteObject(pData->hFontB); } pData->hFontB = hBold; //store the created bold iRet = 1; } } return iRet;}
//*****************************************************************************//*//* UpdateFont//*//*****************************************************************************// Erzeugt einen den fetten Font f�r das Fenster// pData : Zeiger auf die Fensterdaten// iRedraw : Soll das Fenster neugezeichnet werden// Ergibt 1 wenn der Font ver�ndert wurdestatic int UpdateFont(TreeListData *pData) {
int iPos; int iRet; HDC hDc; LOGFONT sLog; SIZE sSize; TEXTMETRIC sMetrics; BaseItem *pEntry; BaseItem **pList; ExtraItem *pExtra; ExtraItem **pItems; unsigned uSub;
if(!hDefaultFontN) { // Den Standard-Font erzeugen SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(sLog), &sLog, 0); sLog.lfWeight = FW_NORMAL; hDefaultFontN = CreateFontIndirect(&sLog); sLog.lfWeight = FW_BOLD; hDefaultFontB = CreateFontIndirect(&sLog); }
if(!pData->hFontN) pData->hFontN = hDefaultFontN; if(!pData->hFontB) pData->hFontB = hDefaultFontB;
/* if(pData->hFontN == hDefaultFontN) { // Ist der Standard-Font eingestellt pData->hFontB = hDefaultFontB; } else { pData->hFontB = pData->hFontN; }*/
if(pData->hFontN != pData->hFontL) { pData->hFontL = pData->hFontN;
hDc = GetDC(NULL); SelectObject(hDc, pData->hFontN); GetTextMetrics(hDc, &sMetrics); pData->iFontHeight = sMetrics.tmHeight; pData->iFontLine = sMetrics.tmAscent + 1; pData->iFontOff = (sMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) ? 0 : -1; ReleaseDC(NULL, hDc);
pList = pData->pTreeItems; iPos = pData->uTreeItemsMax;
for(; iPos >= 0; iPos--) { // Alle Textbreiten zur�cksetzen pEntry = pList[iPos]; if(!pEntry) continue;
pEntry->iTextPixels = 0; }
for(uSub = 1; uSub < pData->uColumnCount; uSub++) { iPos = pData->uTreeItemsMax; pItems = pData->pExtraItems[uSub - 1];
for(; iPos >= 0; iPos--) { pExtra = pItems[iPos]; if(!pExtra) continue;
pExtra->iTextPixels = 0; } }
iRet = 1; } else { iRet = 0; }
// compute Width of "..." text hDc = GetDC(NULL); SelectObject(hDc, pData->hFontN); GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize); pData->uTrippleN = sSize.cx; SelectObject(hDc, pData->hFontB); GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize); pData->uTrippleB = sSize.cx; ReleaseDC(NULL, hDc);
return iRet;}
//*****************************************************************************//*//* UpdateItems//*//*****************************************************************************// Berechnet die Positionen der Zeilen f�r die sichtbaren Eintr�ge// pData : Zeiger auf die Fensterdaten// uItem : Ist der Eintrag ab dem begonnen wirdstatic void UpdateItems(TreeListData *pData, unsigned uItem) {
unsigned uPos; unsigned uOld; unsigned uNum; unsigned uTemp; unsigned uStart; unsigned *pLines; BaseItem **pItems; BaseItem *pEntry; BaseItem *pTemp; RECT sRect;
uOld = pData->uItemPosCount; pLines = pData->pItemPos; pItems = pData->pTreeItems;
if(!uItem) { // Am Anfang beginnen uItem = pData->uFirstChild; if(!uItem) { // Leere Liste if(!uOld) return;
for(uNum = 0; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen uTemp = pLines[uNum]; if(!uTemp) continue; pLines[uNum] = 0; pTemp = pItems[uTemp]; if(!pTemp) continue; pTemp->uShowPos = 0; }
pData->uItemPosCount = 0;
GetClientRect(pData->hWnd, &sRect); InvalidateRect(pData->hWnd, &sRect, TRUE);
memset(pLines, 0, sizeof(unsigned)*uOld); return; }
for(uNum = 0; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen uTemp = pLines[uNum]; if(!uTemp) continue; pLines[uNum] = 0; pTemp = pItems[uTemp]; if(!pTemp) continue; pTemp->uShowPos = 0; }
pEntry = pItems[uItem]; pEntry->uShowPos = 1; pLines[0] = uItem; uPos = 1; uStart = 0; } else { // Bei einem Eintrag beginnen pEntry = pItems[uItem]; uPos = pEntry->uShowPos; if(uPos) uStart = uPos - 1; else uStart = 0;
for(uNum = uPos; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen uTemp = pLines[uNum]; if(!uTemp) continue; pLines[uNum] = 0; pTemp = pItems[uTemp]; if(!pTemp) continue; pTemp->uShowPos = 0; } }
for(;;) { // Die Zeilen neu zuordnen if(pEntry->uFirstChild && (pEntry->uState & TVIS_EXPANDED)) { uItem = pEntry->uFirstChild; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; } else { for(;;) { uItem = pEntry->uParent; if(!uItem) break;
pEntry = pItems[uItem]; if(pEntry->uNextItem) { // Gibt es etwas in der gleichen Ebene uItem = pEntry->uNextItem; break; } }
if(!uItem) break; }
pEntry = pItems[uItem];
if(pLines[uPos] != uItem) { pLines[uPos] = uItem; } else { if(uStart == uPos) uStart++; }
uPos++; pEntry->uShowPos = uPos; }
pData->uItemPosCount = uPos;
if(uStart > pData->uScrollY) // Neu zu zeichnenten Bereich bestimmen uStart -= pData->uScrollY; else uStart = 0;
GetClientRect(pData->hWnd, &sRect);
sRect.top = pData->uStartPixel + pData->iRowHeight * uStart;
if(sRect.top <= sRect.bottom) { InvalidateRect(pData->hWnd, &sRect, FALSE); }
if(uOld != uPos) UpdateScrollY(pData);}
//*****************************************************************************//*//* UpdateColumns//*//*****************************************************************************// Pr�ft ob es Ver�nderungen in Spaltenbreiten gab// pData : Zeiger auf die Fensterdaten// Ergibt die Breite ab der die Spalten ver�ndert wurden oder 0x10000static int UpdateColumns(TreeListData *pData) {#ifndef __REACTOS__ HWND hHeader;#endif UINT uNext; UINT uCol; UINT uSub; int iSize; int iNum; int iNow; int iOld; int iRet;
#ifndef __REACTOS__ hHeader = pData->hHeader;#endif pData->aColumnXpos[0] = 0;
iRet = 0x10000; iOld = 0; iNow = 0;
for(uCol = 0; uCol < pData->uColumnCount;) { // Suche die erste ge�nderte Spalte uSub = pData->aColumnPos[uCol]; iSize = pData->aColumn[uSub].sReal; uSub = pData->aColumn[uSub].bNext; iOld = iNow; iNow += iSize; uCol += 1;
if(uCol == 1) iNow -= 1; if(iNow < iOld) iNow = iOld; if(uSub == pData->uColumnCount) if(iNow >= (int)pData->uSizeX - 1) { iNow++; }
iNum = pData->aColumnXpos[uSub];
if(iNum == iNow) continue; if(iNum == 0) iNum = iOld; if(iNum >= iNow) { iRet = iOld; } else { iRet = iOld;
if(pData->uSelectedItem) { // Problem bei ausgew�hlten leeren Eintr�gen uNext = pData->aColumn[pData->uSelectedSub].bNext; if(uNext == uSub) { UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub); } }
if(pData->uTrackedItem) { uNext = pData->aColumn[pData->uTrackedSub].bNext; if(uNext == uSub) { UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub); } } }
pData->aColumnXpos[uSub] = iNow; break; }
while(uCol < pData->uColumnCount) { // Restliche Spalten berechen iOld = iNow; uSub = pData->aColumnPos[uCol]; iNow += pData->aColumn[uSub].sReal; uSub = pData->aColumn[uSub].bNext; uCol += 1;
if(uCol == pData->uColumnCount) if(iNow >= (int)pData->uSizeX - 1) { iNow++; }
pData->aColumnXpos[uSub] = iNow; }
pData->aColumnXpos[pData->uColumnCount + 1] = pData->uSizeX + 1;
return iRet;}
//*****************************************************************************//*//* TreeListSetOrderArray//*//*****************************************************************************// Stellt die anzeige Reihenfolge der Spalten ein// pData : Zeiger auf die Fensterdaten// uItems : Ist die Nummer des Eintrages// pArray : Zeiger auf die Eintr�ge. Null steht f�r die Standartreihenfolge.// z.B. {0,2,1} meint die sichtbare Reihenfolge Col0,Col2,Col1// Der erste Eintrag muss 0 immer sein.// Ergibt 1 = Ok// 0 = Fehlerstatic int TreeListSetOrderArray(TreeListData *pData, unsigned uItems, unsigned *pArray) {
BYTE aFlags[MAX_COLUMNS + 1]; UINT aArray[MAX_COLUMNS + 1]; TV_COLSIZE sNotify; UINT uDiff; UINT uCol; UINT uSub;
if(!pArray) { // Spezialreihenfolge setzen if(uItems == FROM_HEADER) { // Array aus Header holen if(!Header_GetOrderArray(pData->hHeader, pData->uColumnCount, aArray)) { return 0; }
if(aArray[0] != 0) { return 0; } } else { for(uCol = pData->uColumnCount; uCol > 0; uCol++) { // Standartreihenfolge uCol--; aArray[uCol] = uCol; } }
uItems = pData->uColumnCount; pArray = aArray; } else { // Pr�fe Array if(pData->uColumnCount != uItems || uItems == 0 || *pArray) { return 0; } }
memset(aFlags, 0, sizeof(aFlags) - 1);
for(uCol = 0, uDiff = 0; uCol < uItems; uCol++) { // Die Eintr�ge pr�fen uSub = pArray[uCol]; if(uSub >= uItems) return 0; if(aFlags[uSub]) return 0;
aFlags[uSub] = (BYTE)uCol;
uDiff |= uCol ^ pData->aColumnPos[uSub]; }
if(uDiff == 0) { // Alles blieb gleich return 1; }
aFlags[0 ] = 0; aFlags[uItems] = (BYTE)uItems;
for(uCol = 1; uCol < uItems; uCol++) { // Die Eintr�ge anpassen pData->aColumnPos[uCol] = (BYTE)pArray[uCol]; }
for(uCol = 0; uCol < uItems; uCol++) { uSub = aFlags[uCol]; pData->aColumn[uCol].bIndex = (BYTE)uSub; pData->aColumn[uCol].bNext = pData->aColumnPos[uSub + 1]; }
Header_SetOrderArray(pData->hHeader, uItems, pArray); UpdateColumns(pData); UpdateView(pData);
if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Alle Spalten haben sich ver�ndert UNLOCK(pData);
for(uCol = 0; uCol < uItems; uCol++) { sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = uCol; sNotify.uIndex = pData->aColumn[uCol].bIndex; sNotify.uPosX = pData->aColumnXpos[uCol]; sNotify.iSize = pData->aColumn[uCol].sReal;
SendNotify(pData, &sNotify.hdr); }
LOCK(pData); }
return 1;}
//*****************************************************************************//*//* TreeListToggleItem//*//*****************************************************************************// Klappt bei einem Eintrag die Kinder um, und schickt alle Notify-Nachrichten.// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uAddFlags : Sind die State-Flags die hinzugef�gt werden sollen// Bits 0..3 entahlen das Kommando, bei automatisch ermitteln// Ergibt -1 = Fehler// 0 = Ausgef�hrt// 1 = Abbruchstatic int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags) {
NMTREEVIEW sNotify; BaseItem **pList; BaseItem *pEntry; BaseItem *pTemp; unsigned uAction; unsigned uLevel; unsigned uNext; LRESULT lRet; BOOL bDo;
if(uItem > pData->uTreeItemsMax) return 0;
pList = pData->pTreeItems; pEntry = pList[uItem]; if(!pEntry) return -1;
uAction = uAddFlags & 0x0F; if(!uAction) { uAction = ((pEntry->uState ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) ? TVE_EXPAND : TVE_COLLAPSE; }
sNotify.action = uAction; sNotify.hdr.code = TVN_ITEMEXPANDING; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData);
lRet = SendNotify(pData, &sNotify.hdr);
LOCK(pData);
pList = pData->pTreeItems; pEntry = pList[uItem];
if(pEntry == 0) return -1; // Eintrag inzischen gel�scht ? if(lRet != 0) return 1; // User-Abbruch ?
if(uAction == TVE_EXPAND) { // Aufklappen if(pEntry->uState & TVIS_EXPANDED) { bDo = FALSE; // Nur von + auf - } else { pEntry->uState |= TVIS_EXPANDED; // Kinder Aufklappen bDo = TRUE; } } else { // Zuklappen pEntry->uState &= ~TVIS_EXPANDED; bDo = TRUE; }
pEntry->uState &= ~TVIS_EXPANDPARTIAL; pEntry->uState |= uAddFlags&~0x0F;
if(pEntry->uShowPos && bDo) { if(pEntry->uState & TVIS_EXPANDED) { // Kinderfenster aktuallisieren uLevel = 0; uNext = pEntry->uFirstChild;
while(uNext) { pTemp = pList[uNext]; pTemp->uShowPos = 0;
if(pTemp->uFirstChild) { uNext = pTemp->uFirstChild; uLevel++; continue; }
if(pTemp->uNextItem) { uNext = pTemp->uNextItem; continue; }
if(uLevel == 0) break;
uNext = pList[pTemp->uParent]->uNextItem; uLevel--; } }
UpdateItems(pData, uItem); }
sNotify.action = uAction; sNotify.hdr.code = TVN_ITEMEXPANDED; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData);
SendNotify(pData, &sNotify.hdr);
LOCK(pData);
pList = pData->pTreeItems; pEntry = pData->pTreeItems[uItem];
if(!pEntry) return -1; // Eintrag inzischen gel�scht ?
if(uAction == TVE_EXPAND) { // ONCE setzen nach Expandieren pEntry->uState |= TVIS_EXPANDEDONCE; }
if(pData->uSelectedItem && bDo) { // Ist der ausgew�hlten Eintrag sichtbar ? pEntry = pList[pData->uSelectedItem]; if(!pEntry) { pData->uSelectedItem = 0; pData->uSelectedSub = 0; } else if(!pEntry->uShowPos) { while(!pEntry->uShowPos) { uItem = pEntry->uParent; pEntry = pList[uItem]; }
TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_UNKNOWN); } }
if(bDo == FALSE) { // Nur von + auf - UpdateRect(pData, uItem, 0); }
return 0;}
//*****************************************************************************//*//* TreeListGetItemRect//*//*****************************************************************************// Holt das Rechteck eines Eintrages// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uFlags : Bit 0 : 0=volle Zeile 1=nur Text// Bit 7 : 1=nur Spalte// Bit 24.. : Spaltennummer// Ergibt 1 wenn der Eintrag sichtbar warstatic int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect) {
ExtraItem *pExtra; BaseItem *pEntry; unsigned uNext; unsigned uPos; unsigned uSub;
if(uItem > pData->uTreeItemsMax) { memset(pRect, 0, sizeof(RECT)); return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry->uShowPos) { // Ist der Eintrag aufgeklappt memset(pRect, 0, sizeof(RECT)); return 0; }
uPos = pEntry->uShowPos - pData->uScrollY - 1; if(uPos >= pData->uMaxEnties) { // Eintrag im Fenster sichtbar memset(pRect, 0, sizeof(RECT)); return 0; }
pRect->top = pData->uStartPixel; pRect->top += pData->iRowHeight * uPos; pRect->bottom = pData->iRowHeight + pRect->top;
if((uFlags & 0xFC) == TVIR_GETCOLUMN) { // Nur Spalten uSub = uFlags >> 24; if(uSub >= pData->uColumnCount) uSub = 0;
uNext = pData->aColumn[uSub].bNext; pRect->left = pData->aColumnXpos[uSub]; pRect->left -= pData->uScrollX; pRect->right = pData->aColumnXpos[uNext]; pRect->right -= pData->uScrollX; } else { uSub = 0; pRect->left = 0; pRect->left -= pData->uScrollX; pRect->right = pData->uSizeX; }
if(uFlags & TVIR_TEXT) { // Nur Text ausgeben if(uSub > 0) { pExtra = pData ->pExtraItems[uSub - 1][uItem];
if(pData->aColumn[uSub].bEdit == TVAX_CHECK) { pRect->left += pData->iChecksXsize; if(pRect->left > pRect->right) pRect->left = pRect->right; } else if(pExtra && pExtra->bFlags & TVIX_HASIMAGE) { pRect->left += pData->iImagesXsize; if(pRect->left > pRect->right) pRect->left = pRect->right; } } else { if(pData->cHasRootRow) { // Root-Linien ausgleichen pRect->left += pData->iIndent; }
pRect->left += pData->iIndent * pEntry->uLevel;
if(pData->hStates) { pRect->left += pData->iStatesXsize; }
if(!(pData->uStyle & TVS_HASLINES)) { pRect->left -= 1; }
if(pData->uStyleEx & TVS_EX_ITEMLINES) { pRect->left += 1; if(pEntry->bFlags & TVIX_HASIMAGE) pRect->left++; }
if(pEntry->bFlags & TVIX_HASIMAGE) { pRect->left += pData->iImagesXsize; }
if(pRect->left > pRect->right) { pRect->left = pRect->right; } } }
return 1;}
//*****************************************************************************//*//* TreeListEnsureVisible//*//*****************************************************************************// Macht einen Eintrag sichtbar// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Untereintrag der sichtbar sein soll// 0xFFFFFFFF nur Zeile// FIRST_LINE als oberster Eintrag// Ergibt 1 wenn nur zum Eintrag gescrollt wurde bzw. 0 wenn aufgeklapt wurdestatic int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
BaseItem *pEntry; BaseItem *pTemp; unsigned uTemp; unsigned uNext; unsigned uPos; int iNum; int iAnf; int iOff; int iEnd; int iMax; int iRet;
if(uItem > pData->uTreeItemsMax) return -1;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return -1;
uPos = pEntry->uShowPos; if(!uPos) { // Zweige aufklappen wenn Eintrag zugeklappt
iRet = 0;
for(pTemp = pEntry;;) { uTemp = pTemp->uParent; pTemp = pData->pTreeItems[uTemp]; if(!pTemp) break; if((pTemp->uState & TVIS_EXPANDED) == 0) { if(TreeListToggleItem(pData, uTemp, 0)) return 0; } }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uPos = pEntry->uShowPos; if(!uPos) return 0; } else { // Nur Scrollen iRet = 1; }
uPos--; if(uPos < pData->uScrollY) { // Vor erster Zeile pData->uScrollY = uPos; SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE); UpdateView(pData); } else if(uSub == FIRST_LINE) { // Als ersten Eintrag if(uPos != pData->uScrollY) { pData->uScrollY = uPos; SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE); UpdateView(pData); }
return iRet; } else if(uPos >= pData->uScrollY + pData->uPageEnties) { // Nach letzter Zeile iOff = uPos - (pData->uPageEnties - 1); iMax = pData->uItemPosCount; iMax -= pData->uPageEnties - 1;
if(iOff >= iMax) iOff = iMax; if(iOff < 0) iOff = 0; if(iOff != (int)pData->uScrollY) { pData->uScrollY = iOff; SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE); UpdateView(pData); } }
if(uSub < pData->uColumnCount) { // Horizontal einrichten uNext = pData->aColumn[uSub].bNext; iNum = pData->uSizeX; iOff = pData->uScrollX; iAnf = pData->aColumnXpos[uSub ]; iEnd = pData->aColumnXpos[uNext];
if(iOff + iNum < iAnf) iOff = iAnf; if(iOff >= iEnd) iOff = iAnf; if(iOff + iNum < iEnd) iOff = iEnd - iNum; if(iOff > iAnf) iOff = iAnf;
iMax = pData->aColumnXpos[pData->uColumnCount]; iMax -= pData->uSizeX / 2;
if(iOff > iMax) iOff = iMax; if(iOff < 0) iOff = 0; if(iOff != (int)pData->uScrollX) { pData->uScrollX = iOff; SetScrollPos(pData->hWnd, SB_HORZ, iOff, TRUE); UpdateView(pData); MoveWindow(pData->hHeader, -iOff, 0, iNum + iOff, pData->uStartPixel, TRUE); } } return iRet;}
//*****************************************************************************//*//* TreeListIsVisible//*//*****************************************************************************// Pr�ft ob ein Eintrag sichtbar ist// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Untereintrag der gepr�ft werden soll// 0xFFFFFFFF nur Zeile pr�fen// Ergibt den Zustand des Eintrages:// -1 = Unbekannter Eintrag// 0 = Eintrag ist zugeklappt// 1 = Eintrag ist aufgeklappt aber nicht sichtbar// 2 = Eintrag ist aufgeklappt und teilweise sichtbar// 3 = Eintrag ist aufgeklappt und Spalte ist nur teilweise sichtbar// 4 = Eintrag ist aufgeklappt und ganz sichtbarstatic int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
BaseItem *pEntry; unsigned uNext; unsigned uPos; int iNum; int iAnf; int iOff; int iEnd;
if(uItem > pData->uTreeItemsMax) return -1;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return -1;
uPos = pEntry->uShowPos; if(!uPos) { // Ist der Eintrag zugeklappt return 0; }
uPos--; if(uPos < pData->uScrollY) { // Vor erster Zeile
return 1; }
if(uPos >= pData->uScrollY + pData->uMaxEnties) { // Nach letzter Zeile return 1; }
if(uPos == pData->uScrollY + pData->uPageEnties) { // Auf halbsichtbarer Zeile if(uSub < pData->uColumnCount) { uNext = pData->aColumn[uSub].bNext; iNum = pData->uSizeX; iOff = pData->uScrollX; iAnf = pData->aColumnXpos[uSub ]; iEnd = pData->aColumnXpos[uNext];
if(iOff + iNum < iAnf) return 1; if(iOff >= iEnd) return 1; }
return 2; }
if(uSub < pData->uColumnCount) { // Spalte pr�fen uNext = pData->aColumn[uSub].bNext; iNum = pData->uSizeX; iOff = pData->uScrollX; iAnf = pData->aColumnXpos[uSub ]; iEnd = pData->aColumnXpos[uNext];
if(iOff + iNum < iAnf) return 1; if(iOff >= iEnd) return 1; if(iOff + iNum < iEnd) return 3; if(iOff > iAnf) return 3; }
return 4;}
//*****************************************************************************//*//* TreeListDeleteItem//*//*****************************************************************************// L�scht einen Eintrag aus dem Fenster// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages der gel�scht werden soll// iMode : Wie soll der Eintrag gel�scht werden// 0 = Eintrag l�schen und nicht neu zeichnen// 1 = Eintrag l�schen und neu zeichnen// 2 = Nur Kindereintr�ge l�schen und neu zeichnen// Ergibt 1 wenn der Eintrag gel�scht wurde.static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode) {
NMTREEVIEW sNotify; ExtraItem **pList; ExtraItem *pExtra; BaseItem *pEntry; BaseItem *pTemp; unsigned uPos; int iOff; int iMax;
if(pData->cLockChanges) return 0;
if(uItem > pData->uTreeItemsMax) { // Pr�fe den Eintrag if(uItem != U(TVI_ROOT)) return 0; // Alles l�schen if(pData->uLastChild == 0) return 0;
while(pData->uLastChild) { TreeListDeleteItem(pData, pData->uLastChild, 0); }
pData->uItemPosCount = 0;
UpdateScrollY(pData); UpdateView(pData);
return 1; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) { // Pr�fe den Eintrag if(uItem != 0) return 0; // Alles l�schen if(pData->uLastChild == 0) return 0;
while(pData->uLastChild) { TreeListDeleteItem(pData, pData->uLastChild, 0); }
pData->uItemPosCount = 0;
UpdateScrollY(pData); UpdateView(pData);
return 1; }
if(iMode == 2) { // Nur Kindereintr�ge l�schen if(!pEntry->uFirstChild) { return 0; }
while(pEntry->uLastChild) { // Alle Kinder l�schen TreeListDeleteItem(pData, pEntry->uLastChild, 0); }
uPos = pEntry->uShowPos; if(uPos) { UpdateItems(pData, uItem); }
return 1; }
while(pEntry->uLastChild) { // Alle Kinder l�schen TreeListDeleteItem(pData, pEntry->uLastChild, 0); }
if(uItem == pData->uSelectedItem) { // Einen ausgew�hlten Eintrag l�schen sNotify.hdr.code = TVN_SELCHANGED; sNotify.action = TVC_UNKNOWN; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = pEntry->uState&~TVIS_SELECTED; sNotify.itemOld.lParam = pEntry->lParam; sNotify.itemOld.cChildren = 0; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemNew.hItem = NULL; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = 0; sNotify.itemNew.lParam = 0; sNotify.itemNew.cChildren = 0; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); // Bekant geben das der Eintrag nicht mehr ausgew�hlt ist LOCK(pData);
pData->uSelectedItem = 0; pData->uSelectedSub = 0; }
sNotify.hdr.code = TVN_DELETEITEM; sNotify.itemNew.mask = 0; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemOld.lParam = pEntry->lParam; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData);
pEntry = pData->pTreeItems[uItem]; // Pr�fen ob der Eintrag noch existiert if(!pEntry) return 0;
if(uItem == pData->uTrackedItem) { // Einen unterstrichenen Eintrag l�schen pData->uTrackedItem = 0; pData->uTrackedSub = 0; }
if(pData->uInsertMark == uItem) { pData->uInsertMark = 0; }
if(pData->uSingleSel == uItem) { pData->uSingleSel = 0; }
if(pEntry->uPrevItem) { // Gibt es einen vorherigen Eintrag pTemp = pData->pTreeItems[pEntry->uPrevItem]; pTemp->uNextItem = pEntry->uNextItem; } else { if(pEntry->uParent) { // Neues erstes Kind in Elterneintrag pTemp = pData->pTreeItems[pEntry->uParent]; pTemp->uFirstChild = pEntry->uNextItem; } else { pData->uFirstChild = pEntry->uNextItem; } }
if(pEntry->uNextItem) { // Gibt es einen vorherigen Eintrag pTemp = pData->pTreeItems[pEntry->uNextItem]; pTemp->uPrevItem = pEntry->uPrevItem; } else { if(pEntry->uParent) { // Neues letztes Kind in Elterneintrag pTemp = pData->pTreeItems[pEntry->uParent]; pTemp->uLastChild = pEntry->uPrevItem;
if(pTemp->uFirstChild == 0 && pTemp->uLastChild == 0) { pTemp->bFlags &= ~TVIX_HASBUTTON; } } else { pData->uLastChild = pEntry->uPrevItem; } }
for(uPos = 1; uPos < pData->uColumnCount; uPos++) { // Alle Extraeintr�ge l�schen pList = pData->pExtraItems[uPos - 1];
pExtra = pList[uItem]; if(!pExtra) continue;
pList[uItem] = NULL;
if(pExtra->pText) { pExtra->uTextSize = 0; delete(pExtra->pText); }
delete(pExtra); }
pData->pTreeItems[uItem] = NULL; // Den Eintrag l�schen
if(pEntry->pText) { pEntry->uTextSize = 0; delete(pEntry->pText); }
if(iMode) { // Den Eintrag neuzeichnen uItem = pEntry->uPrevItem; if(!uItem && !pEntry->uNextItem) { uItem = pEntry->uParent; if(!uItem) uPos = 1; else uPos = pData->pTreeItems[uItem]->uShowPos; } else { uPos = pEntry->uShowPos; }
if(uPos) { UpdateItems(pData, uItem); } }
if(pEntry->uState & TVIS_SELECTED) // Ausgew�hlte Eintr�ge runterz�hlen if(pData->uSelectedCount > 0) { pData->uSelectedCount--; }
delete(pEntry);
pData->uTreeItemsCount--;
iOff = pData->uScrollY; // Pr�fe die Scrollposition iMax = pData->uItemPosCount; iMax -= pData->uPageEnties - 1;
if(iOff >= iMax) iOff = iMax; if(iOff < 0) iOff = 0; if(iOff != (int)pData->uScrollY) { pData->uScrollY = iOff; SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE); UpdateView(pData); }
return 1;}
//*****************************************************************************//*//* TreeListXorSelectItem//*//*****************************************************************************// W�hlt einen Eintrag ab bzw. an// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll// iMode : Ist der Grund f�r die �nderung// TVC_BYKEYBOARD// TVC_BYMOUSE// TVC_UNKNOWN// Ergibt 1 wenn der Eintrag ab/angew�hlt wurde// 0 wenn der Eintrag nicht ver�ndert wurdestatic int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode) {
NMTREEVIEW sNotify; BaseItem *pEntry; unsigned uOld; unsigned uRet;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(uItem == pData->uSelectedItem) return 0;
uOld = pEntry->uState;
sNotify.hdr.code = TVN_SELCHANGING; sNotify.action = iMode; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.cChildren = 0; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemOld.hItem = NULL; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = 0; sNotify.itemOld.lParam = 0; sNotify.itemOld.cChildren = 0; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); uRet = U(SendNotify(pData, &sNotify.hdr)); LOCK(pData);
if(uRet) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; pEntry->uState ^= TVIS_SELECTED;
sNotify.hdr.code = TVN_SELCHANGED; sNotify.action = iMode; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.cChildren = 0; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemOld.hItem = NULL; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = 0; sNotify.itemOld.lParam = 0; sNotify.itemOld.cChildren = 0; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData);
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uShowPos) { if(pData->uStyleEx & TVS_EX_FULLROWMARK) UpdateRow(pData, uItem); else UpdateRect(pData, uItem, 0); }
if((uOld ^ pEntry->uState)&TVIS_SELECTED) { if(pEntry->uState & TVIS_SELECTED) pData->uSelectedCount++; else pData->uSelectedCount--; }
return 1;}
//*****************************************************************************//*//* TreeListRemoveFocus//*//*****************************************************************************// W�hlt den Focus ab// pData : Zeiger auf die Fensterdatenstatic void TreeListRemoveFocus(TreeListData *pData) {
ExtraItem *pExtra; BaseItem *pEntry; unsigned uItem; unsigned uSub;
if(!pData->uFocusItem) return;
uItem = pData->uFocusItem; pEntry = pData->pTreeItems[uItem];
if(pEntry) { pEntry->bFlags &= ~TVIX_FOCUSED;
uSub = pData->uFocusSub;
if(uSub) { pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) pExtra->bFlags &= ~TVIX_FOCUSED; }
UpdateRect(pData, uItem, uSub); }
pData->uFocusItem = 0; pData->uFocusSub = 0;}
//*****************************************************************************//*//* TreeListSetFocus//*//*****************************************************************************// W�hlt den Focus-Eintrag// pData : Zeiger auf die Fensterdaten// uItem : Eintrag f�r den Focus (0xFFFFFFFF=keine �nderung)// uSub : Spalte f�r den Focus (0xFFFFFFFF=keine �nderung)// Ergibt 1 wenn der Focus gesetzt wurde, bzw 0 bei einem Fehlerstatic int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub) {
ExtraItem *pExtra; BaseItem *pEntry; BaseItem *pTemp; unsigned uTemp; unsigned uCol;
if(pData->uFocusItem) { if(uSub == 0xFFFFFFFF) uSub = pData->uFocusSub; if(uItem == 0xFFFFFFFF) uItem = pData->uFocusItem; } else { if(uSub == 0xFFFFFFFF) uSub = pData->uSelectedSub; if(uItem == 0xFFFFFFFF) uItem = pData->uSelectedItem; }
if(pData->uFocusItem == uItem) if(pData->uFocusSub == uSub) return 1;
if(!uItem) { // Focus abw�hlen TreeListRemoveFocus(pData); return 1; }
if(uItem > pData->uTreeItemsMax) { // Den Eintrag pr�fen return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) { return 0; }
if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) uSub = 0;
if(!(pData->uStyleEx & TVS_EX_MULTISELECT)) { // Einzel auswahl return TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN); }
uTemp = pData->uFocusItem; pTemp = pData->pTreeItems[uTemp];
if(pTemp) { // Den alten Eintrag abw�hlen pTemp->bFlags &= ~TVIX_FOCUSED; uCol = pData->uFocusSub;
if(uCol) { pExtra = pData->pExtraItems[uCol - 1][uTemp]; if(pExtra) pExtra->bFlags &= ~TVIX_FOCUSED; }
UpdateRect(pData, uItem, uSub); }
if(uSub) { // Neuen Eintrag w�hlen pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) pExtra->bFlags |= TVIX_FOCUSED; } else { pEntry->bFlags |= TVIX_FOCUSED; }
pData->uFocusItem = uItem; pData->uFocusSub = uSub;
if(pEntry->uState & TVIS_SELECTED) { // Auch die Auswahl nachziehen if(pData->uSelectedItem != uItem) { uTemp = pData->uSelectedItem; uCol = pData->uSelectedSub; } else { uTemp = 0; uCol = pData->uSelectedSub; }
pData->uSelectedItem = uItem; pData->uSelectedSub = uSub;
if(pData->uStyleEx & TVS_EX_FULLROWMARK) { uCol = uSub + 1; }
if(uTemp) { if(uCol != uSub) UpdateRow(pData, uTemp); else UpdateRect(pData, uTemp, uCol); }
if(uCol != uSub) UpdateRow(pData, uItem); else UpdateRect(pData, uItem, uCol); } else { UpdateRect(pData, uItem, uSub); }
return 1;}
//*****************************************************************************//*//* TreeListSelectItem//*//*****************************************************************************// W�hlt einen Eintrag aus// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll// uSubItem : Ist die Spalte die gew�hlt werden soll// iMode : Ist der Grund f�r die �nderung// TVC_BYKEYBOARD// TVC_BYMOUSE// TVC_UNKNOWN// TVC_ONLYFOCUS (nur der Focus hat sich ver�ndert)// TVC_DESELECT (dieses Flag l�scht die alte Auswahl)// TVC_UNSELECT (dieses Flag l�scht Auswahl bei MultiSel)// Ergibt 2 wenn der Eintrag gew�hlt und umgeklapt wurde// 1 wenn der Eintrag gew�hlt wurde// 0 wenn der Eintrag nicht gew�hlt wurdestatic int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode) {
NMTREEVIEW sNotify; ExtraItem *pExtra; BaseItem *pEntry; BaseItem *pTemp; LPARAM lParam; LPARAM lPaOld; unsigned uState; unsigned uStOld; unsigned uNext; unsigned uPos; unsigned uOld; unsigned uSub; unsigned uRet; int iDel; int iSel;
uOld = pData->uSelectedItem; uSub = pData->uSelectedSub;
if(uSubItem >= pData->uColumnCount && uSubItem > 0) return 0; if(uItem > pData->uTreeItemsMax) return 0; if(uItem == uOld) if(uSubItem == uSub) if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_MULTISELECT)) { return 1; }
if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Ist die Mehrfachauswahl m�glich iSel = iMode & TVC_UNSELECT; iDel = iMode & TVC_DESELECT; if(!iDel) { if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT)) UpdateRow(pData, uOld); else UpdateRect(pData, uOld, uSub);
uOld = 0; uSub = 0; } else { // Alle gew�hlten Eintr�ge abw�hlen if(pData->uSelectedCount > 1 && pData->uTreeItemsMax) { for(uPos = pData->uTreeItemsMax; uPos; uPos--) { pEntry = pData->pTreeItems[uPos]; if(!pEntry || !(pEntry->uState & TVIS_SELECTED)) continue; if(TreeListXorSelectItem(pData, uPos, iMode)) if(!pData->uSelectedCount) break; // Wurden alle Eintr�ge abgew�hlt } } } } else { // Altes Select l�schen iMode &= ~TVC_ONLYFOCUS; iDel = 1; iSel = 0; }
iMode &= ~(TVC_DESELECT | TVC_UNSELECT);
pEntry = pData->pTreeItems[uItem]; if(!pEntry) { // Neuen Statatus holen if(uItem) return 0; uState = 0; lParam = 0; } else { uState = pEntry->uState; lParam = pEntry->lParam;
if(uSubItem) { uState &= TVIS_BASEFLAGS; pExtra = pData->pExtraItems[uSubItem - 1][uItem]; if(pExtra) uState |= pExtra->uState; } }
pTemp = pData->pTreeItems[uOld]; if(!pTemp) { // Alten Status holen uStOld = 0; lPaOld = 0; } else { uStOld = pTemp->uState; lPaOld = pTemp->lParam;
if(uSub) { uStOld &= TVIS_BASEFLAGS; pExtra = pData->pExtraItems[uSub - 1][uOld]; if(pExtra) uStOld |= pExtra->uState; } }
sNotify.hdr.code = TVN_SELCHANGING; sNotify.action = iMode; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = uState; sNotify.itemNew.lParam = lParam; sNotify.itemNew.cChildren = uSubItem; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = uStOld; sNotify.itemNew.lParam = lPaOld; sNotify.itemOld.cChildren = uSub; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData);
if(SendNotify(pData, &sNotify.hdr)) { // Abfragen ob der Eintrag gew�hlt werden darf LOCK(pData); return 0; }
LOCK(pData);
if(uItem) { // Pr�fen ob der Eintrag noch existiert pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; }
if(iDel) { uOld = pData->uSelectedItem; pTemp = pData->pTreeItems[uOld]; }
if(pTemp) { // Den alten Eintrag abw�hlen if(pTemp->uShowPos) { // Den Eintrag neu zeichnen if((pData->uStyleEx & TVS_EX_FULLROWMARK) || pData->uSelectedSub) UpdateRow(pData, uOld); else UpdateRect(pData, uOld, uSub); }
if(pTemp->uState & TVIS_SELECTED) { uStOld &= ~TVIS_SELECTED; pTemp->uState &= ~TVIS_SELECTED;
if(pData->uSelectedCount > 0) { pData->uSelectedCount -= 1; } }
pData->uSelectedSub = 0; pData->uSelectedItem = 0; } else { uOld = 0; }
if(uItem) { // Den neuen Eintrag w�hlen if(iSel) { if(pEntry->uState & TVIS_SELECTED) { uState &= ~TVIS_SELECTED; pEntry->uState &= ~TVIS_SELECTED; if(pData->uSelectedCount) pData->uSelectedCount--; } } else { if(!(pEntry->uState & TVIS_SELECTED)) { uState |= TVIS_SELECTED; pEntry->uState |= TVIS_SELECTED; pData->uSelectedCount += 1; } }
if(uSubItem && uSubItem < pData->uColumnCount) { pExtra = pData->pExtraItems[uSubItem - 1][uItem]; if(!pExtra) { pExtra = new(ExtraItem, 1); memset(pExtra, 0, sizeof(ExtraItem)); pExtra->iImage = TV_NOIMAGE; pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE); pData->pExtraItems[uSubItem - 1][uItem] = pExtra; }
uState = pExtra->uState; uState |= pEntry->uState & TVIS_BASEFLAGS; } else { uState = pEntry->uState; }
if(pEntry->uShowPos) { // Den Eintrag neu zeichnen if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT)) UpdateRow(pData, uItem); else UpdateRect(pData, uItem, uSubItem); }
pData->uSelectedSub = uSubItem; pData->uSelectedItem = uItem; } else { pData->uSelectedItem = 0; pData->uSelectedSub = 0; uState = 0; }
sNotify.hdr.code = TVN_SELCHANGED; sNotify.action = iMode; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = uState; sNotify.itemNew.lParam = lParam; sNotify.itemNew.cChildren = uSubItem; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = uStOld; sNotify.itemOld.lParam = lPaOld; sNotify.itemOld.cChildren = uSub; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData);
if(!(pData->uStyle & TVS_SINGLEEXPAND)) { // Einzelmodus aktiv if(pData->uStyle & TVS_SHOWSELALWAYS) if(pData->uSelectedItem) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); }
return 1; }
//*****************************************************************************
sNotify.hdr.code = TVN_SINGLEEXPAND; sNotify.action = iMode; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = (pEntry) ? pEntry->uState : 0; sNotify.itemNew.cChildren = 0; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = (pTemp) ? pTemp->uState : 0; sNotify.itemOld.cChildren = 0; sNotify.itemOld.pszText = (LPTSTR) - 1; sNotify.itemOld.cchTextMax = -1; sNotify.ptDrag.x = 0; sNotify.ptDrag.y = 0;
UNLOCK(pData); uRet = U(SendNotify(pData, &sNotify.hdr)); // Anfragen ob die Zweige umgeklappt werden d�rfen LOCK(pData);
pTemp = pData->pTreeItems[uOld ]; // Zeiger neu holen falls es �nderungen gab pEntry = pData->pTreeItems[uItem];
while(pTemp && pEntry) { // Beide Zweige sysnchronisieren if(pEntry->uLevel > pTemp->uLevel) { uNext = pEntry->uParent;
if(!(uRet & TVNRET_SKIPNEW)) if(!(pEntry->uState & TVIS_EXPANDED)) { TreeListToggleItem(pData, uItem, 0); }
pEntry = pData->pTreeItems[uNext]; uItem = uNext;
if(!uItem) break;
continue; }
if(uItem == uOld) goto EndSel; // Bis zum gleichen Knoten
uNext = pTemp->uParent;
if(!(uRet & TVNRET_SKIPOLD)) if(pTemp->uState & TVIS_EXPANDED) { TreeListToggleItem(pData, uOld, 0); }
pTemp = pData->pTreeItems[uNext]; uOld = uNext; }
if(!uItem) { if(!(uRet & TVNRET_SKIPOLD)) while(pTemp) { // Alten Zweig zuklappen uNext = pTemp->uParent;
if(pTemp->uState & TVIS_EXPANDED) { TreeListToggleItem(pData, uOld, 0); }
pTemp = pData->pTreeItems[uNext]; uOld = uNext; }
goto EndSel; }
if(!uOld) { if(!(uRet & TVNRET_SKIPNEW)) while(pEntry) { // Neuen Zweig aufklappen uNext = pEntry->uParent;
if(!(pEntry->uState & TVIS_EXPANDED)) { TreeListToggleItem(pData, uItem, 0); }
pEntry = pData->pTreeItems[uNext]; uItem = uNext; } }
EndSel:
if(pData->uStyle & TVS_SHOWSELALWAYS) if(pData->uSelectedItem) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); }
return 2;}
//*****************************************************************************//*//* TreeListSelectChilds//*//*****************************************************************************// W�hlt einen Eintrag aus// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll// iMode : Bit 0 = Untereint�ge auch �ndern// Bit 1 = Eintr�ge abw�hlen// Ergibt 1 wenn die Auswahl funktioniert hat, bzw. 0 bei einem Fehlerstatic int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode) {
BaseItem *pEntry; unsigned uLevel; unsigned uXor;
if(!(pData->uStyleEx & TVS_EX_MULTISELECT)) return 0;
uLevel = 0;
if(uItem == U(TVI_ROOT)) { uItem = pData->uFirstChild; } else { if(uItem > pData->uTreeItemsMax) return 0; }
if(!pData->pTreeItems[uItem]) { return 0; }
uXor = (iMode & TVIS_DESELECT) ? 0 : TVIS_SELECTED; iMode &= TVIS_WITHCHILDS;
for(;;) { pEntry = pData->pTreeItems[uItem];
if((pEntry->uState ^ uXor)&TVIS_SELECTED) { TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN); }
if(iMode && pEntry->uFirstChild) { // Auch Kinder �ndern uItem = pEntry->uFirstChild; uLevel++; continue; }
for(;;) { // Eine Ebene h�her uItem = pEntry->uNextItem; if(uItem != 0) break; if(uLevel == 0) return 1;
uLevel--;
uItem = pEntry->uParent; pEntry = pData->pTreeItems[uItem]; } }}
//*****************************************************************************//*//* TreeListInsertItem//*//*****************************************************************************// F�gt einen Eintrag ins Fenster ein// pData : Zeiger auf die Fensterdaten// pInsert : Zeiger auf die ein zu f�genden Daten// Ergibt die Einf�geposition des neuen Eintrages oder 0 bei einem Fehlerstatic unsigned TreeListInsertItem(TreeListData *pData, TV_INSERTSTRUCT *pInsert) {
char *pTemp; BYTE bFlag; LPCTSTR pText; LPCTSTR pTextTemp; PFNTVSORTEX pCompare; ExtraItem **pExOld[MAX_COLUMNS]; ExtraItem **pExNew[MAX_COLUMNS]; BaseItem *pNew; BaseItem **pOld; BaseItem **pItems; BaseItem *pEntry; BaseItem *pParent; unsigned *pPosNew; unsigned *pPosOld; unsigned *pFirst; unsigned *pLast; unsigned uBefore; unsigned uParent; unsigned uAfter; unsigned uFirst; unsigned uSize; unsigned uBits; unsigned uItem; unsigned uNext; unsigned uMax; unsigned uPos; unsigned uNum; int iCmp; int iNone; int iCount; int iShift;
if(pData->cLockChanges) return 0;
uParent = U(pInsert->hParent); if(uParent > pData->uTreeItemsMax) { // Pr�fe das Elternelement if(pInsert->hParent != TVI_ROOT) { return 0; }
pParent = NULL; } else { pParent = pData->pTreeItems[uParent]; if(!pParent) { if(uParent) return 0; pParent = NULL; } }
if(pData->uTreeItemsCount + 1 > pData->uTreeItemsMax) { // Gr��e der Liste erh�hen pPosOld = pData->pItemPos; pOld = pData->pTreeItems; uMax = pData->uTreeItemsMax; uMax += pData->uTreeItemsMax / 2; uMax += 64; pItems = new(BaseItem*, uMax + 1);
if(!pItems) { return 0; }
pPosNew = new(unsigned, uMax); if(!pPosNew) { delete(pItems); return 0; }
for(uPos = 1; uPos < pData->uColumnCount; uPos++) { pExOld[uPos] = pData->pExtraItems[uPos - 1]; pExNew[uPos] = new(ExtraItem*, uMax + 1);
if(!pExNew[uPos]) { for(uPos--; uPos > 0; uPos--) delete(pExNew[uPos]); delete(pPosNew); delete(pItems); return 0; } }
memcpy(pItems , pData->pTreeItems , sizeof(BaseItem *) * (pData->uTreeItemsMax + 1)); memset(pItems + pData->uTreeItemsMax + 1, 0, sizeof(BaseItem *) * (uMax - pData->uTreeItemsMax)); memcpy(pPosNew, pData->pItemPos , sizeof(unsigned) * (pData->uTreeItemsCount)); memset(pPosNew + pData->uTreeItemsCount, 0, sizeof(unsigned) * (uMax - pData->uTreeItemsCount));
for(uPos = 1; uPos < pData->uColumnCount; uPos++) { memcpy(pExNew[uPos], pExOld[uPos] , sizeof(ExtraItem *) * (pData->uTreeItemsMax + 1)); memset(pExNew[uPos] + pData->uTreeItemsMax + 1, 0, sizeof(ExtraItem *) * (uMax - pData->uTreeItemsMax)); pData->pExtraItems[uPos - 1] = pExNew[uPos]; delete(pExOld[uPos]); }
pData->uTreeItemsMax = uMax; pData->pTreeItems = pItems; pData->pItemPos = pPosNew; delete(pPosOld); delete(pOld); }
//******************** Den neuen Eintrag erzeugen ***************************** pItems = pData->pTreeItems; uPos = pData->uNextSeachPos + 1; pTemp = new(char, sizeof(BaseItem) + pData->uUserDataSize); pNew = (BaseItem *)pTemp;
if(!pNew) { // Konnte der Speicher reserviert werden return 0; }
if(pData->uUserDataSize) { // Die Userdaten auf 0 setzen memset(pTemp + sizeof(BaseItem), 0, pData->uUserDataSize); }
for(;; uPos++) { // Suche freie Position if(uPos > pData->uTreeItemsMax) uPos = 1; if(pItems[uPos] == NULL) break; }
pData->uNextSeachPos = uPos;
memset(pNew, 0, sizeof(BaseItem)); // Erstelle den neuen Eintrag pNew->iImage = TV_NOIMAGE; pNew->iSelectedImage = TV_NOIMAGE;
uBits = pInsert->item.mask;
if(uBits & TVIF_STATE) { pNew->uState = pInsert->item.state & pInsert->item.stateMask; } else { if(pData->uStyle & TVS_CHECKBOXES) if(!(pData->uStyleEx & TVS_EX_BITCHECKBOX)) { pNew->uState = 0x1000; } }
if(uBits & TVIF_PARAM) { pNew->lParam = pInsert->item.lParam; }
if(uBits & TVIF_IMAGE) { pNew->iImage = pInsert->item.iImage; if(pNew->iImage == I_IMAGECALLBACK) pNew->bCallback |= TVIF_IMAGE; }
if(uBits & TVIF_SELECTEDIMAGE) { pNew->iSelectedImage = pInsert->item.iSelectedImage; if(pNew->iSelectedImage == I_IMAGECALLBACK) pNew->bCallback |= TVIF_SELECTEDIMAGE; }
if(uBits & TVIF_CHILDREN) { // Art der Schaltfl�chen switch(pInsert->item.cChildren) { case 0: break; case 1: pNew->bFlags |= TVIX_HASBUTTON; break; case I_CCB: pNew->bCallback |= TVIF_CHILDREN; break; default : pNew->bFlags |= TVIX_VARBUTTON; break; } } else { pNew->bFlags |= TVIX_VARBUTTON; }
if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus pNew->uState &= ~TVIS_EXPANDED; }
if(uBits & TVIF_TEXT) { // Text einf�gen if(pInsert->item.pszText == LPSTR_TEXTCALLBACK) { pNew->bCallback |= TVIF_TEXT; pNew->uTextSize = 0; pNew->pText = 0; } else { pNew->uTextSize = (WORD)str_len(pInsert->item.pszText); pNew->pText = new(TCHAR, pNew->uTextSize + 1); memcpy(pNew->pText, pInsert->item.pszText, sizeof(TCHAR) * (pNew->uTextSize + 1)); } } else { pNew->pText = new(TCHAR, 1); pNew->pText[0] = 0; pNew->uTextSize = 0; }
if(!pParent) { // Einen Root-Eintrag einf�gen pNew->uParent = 0; uParent = 0; bFlag = 0; uFirst = 0xFFFFFFFF; pFirst = &pData->uFirstChild; pLast = &pData->uLastChild; } else { // Einen Tree-Eintrag einf�gen pNew->uParent = uParent; pNew->uLevel = pParent->uLevel + 1; uFirst = pParent->uFirstChild; pFirst = &pParent->uFirstChild; pLast = &pParent->uLastChild; bFlag = pParent->bFlags;
if(pParent->bFlags & TVIX_VARBUTTON) { pParent->bFlags |= TVIX_HASBUTTON; } }
//******************** Eintrage einf�gen ************************************** uAfter = U(pInsert->hInsertAfter);
switch(uAfter) { case U(TVI_BEFORE): // Nach einem Eintrag einf�gen if(pParent) { // Einen Root-Eintrag einf�gen pEntry = pParent; pParent ->bFlags = bFlag; uParent = pParent->uParent; pParent = pItems [uParent];
if(!pParent) { pNew->uParent = 0; pNew->uLevel = 0; uParent = 0; uFirst = 0xFFFFFFFF; pFirst = &pData->uFirstChild; pLast = &pData->uLastChild; } else { // Einen Tree-Eintrag einf�gen pNew->uParent = uParent; pNew->uLevel = pParent->uLevel + 1; uFirst = pParent->uFirstChild; pFirst = &pParent->uFirstChild; pLast = &pParent->uLastChild;
if(pParent->bFlags & TVIX_VARBUTTON) { pParent->bFlags |= TVIX_HASBUTTON; } }
if(pEntry->uPrevItem) { uAfter = pEntry->uPrevItem; goto DoInsert; } }
case U(TVI_FIRST): // Am Anfang einf�gen if(pFirst[0]) { // Gibt es schon Eintr�ge pEntry = pItems[pFirst[0]]; pEntry->uPrevItem = uPos; } else { pFirst[0] = uPos; pLast [0] = uPos; break; }
pNew ->uNextItem = pFirst[0]; // Eintrag einf�gen pFirst[0] = uPos; break;
case U(TVI_ROOT): // Als Root-Eintrag einf�gen pNew->uParent = 0; uParent = 0; pFirst = &pData->uFirstChild; pLast = &pData->uLastChild;
case U(TVI_LAST): // Am Ende einf�gen if(pLast[0]) { // Gibt es schon Eintr�ge pEntry = pItems[pLast[0]]; pEntry->uNextItem = uPos; } else { pFirst[0] = uPos; pLast [0] = uPos; break; }
pNew ->uPrevItem = pLast[0]; // Eintrag einf�gen pLast[0] = uPos; break;
case U(TVI_SORTEX): // Einf�gen mittels Funktion uItem = pFirst[0]; if(!uItem) { // Gibt es keine Kindeintr�ge pFirst[0] = uPos; pLast [0] = uPos; break; }
if(pNew->bCallback & TVIF_TEXT) { // Text �ber Callback holen uSize = 1; LOCK(pData); CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText); UNLOCK(pData); } else { pText = pNew->pText; }
pData->cLockChanges = 1;
pCompare = (PFNTVSORTEX)(pInsert->item.hItem); if(!pCompare) break; uNext = uItem; iCount = 0; uBefore = 0;
while(uNext) { // Z�hle die Eintr�ge iCount++; uNext = pItems[uNext]->uNextItem; }
while(iCount > 0) { // Binary-Seach Algorithnus iShift = iCount / 2; uNext = uItem;
while(iShift > 0) { uNext = pItems[uNext]->uNextItem; iShift--; }
pEntry = pItems[uNext]; if(pEntry->bCallback & TVIF_TEXT) { // Text �ber Callback holen uSize = 0; LOCK(pData); CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp); UNLOCK(pData); } else { pTextTemp = pEntry->pText; }
iCmp = pCompare(pData->hWnd, (HTREEITEM)(ULONG_PTR)uNext, pTextTemp, pText, pEntry->lParam, pInsert->item.lParam); if(iCmp < 0) { iCount -= (iCount + 1) / 2; continue; }
if(iCmp > 0) { iCount -= iCount / 2 + 1; uBefore = uNext; uItem = pItems[uNext]->uNextItem; continue; }
uBefore = pEntry->uPrevItem; uItem = uNext; break; }
pData->cLockChanges = 0;
pNew->uNextItem = uItem; pNew->uPrevItem = uBefore;
if(uBefore) { // Vorherigen Eintrag anpassen pEntry = pItems[uBefore]; pEntry->uNextItem = uPos; } else { // Am Anfang einf�gen pFirst[0] = uPos; }
if(uItem) { // N�chsten Eintrag anpassen pEntry = pItems[uItem]; pEntry->uPrevItem = uPos; } else { // Am Ende anh�ngen pLast[0] = uPos; } break;
case U(TVI_SORT): // Alphapetisch einf�gen uItem = pFirst[0]; if(!uItem) { // Gibt es keine Kindeintr�ge pFirst[0] = uPos; pLast [0] = uPos; break; }
if(pNew->bCallback & TVIF_TEXT) { // Text �ber Callback holen uSize = 1; LOCK(pData); CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText); UNLOCK(pData); } else { pText = pNew->pText; }
pData->cLockChanges = 1;
uNext = uItem; iCount = 0; uBefore = 0;
while(uNext) { // Z�hle die Eintr�ge iCount++; uNext = pItems[uNext]->uNextItem; }
while(iCount > 0) { // Binary-Seach Algorithnus iShift = iCount / 2; uNext = uItem;
while(iShift > 0) { uNext = pItems[uNext]->uNextItem; iShift--; }
pEntry = pItems[uNext]; if(pEntry->bCallback & TVIF_TEXT) { // Text �ber Callback holen uSize = 0; LOCK(pData); CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp); UNLOCK(pData); } else { pTextTemp = pEntry->pText; }
iCmp = str_icmp(pText, pTextTemp);
if(iCmp < 0) { iCount -= (iCount + 1) / 2; continue; }
if(iCmp > 0) { iCount -= iCount / 2 + 1; uBefore = uNext; uItem = pItems[uNext]->uNextItem; continue; }
uBefore = pEntry->uPrevItem; uItem = uNext; break; }
pData->cLockChanges = 0;
pNew->uNextItem = uItem; pNew->uPrevItem = uBefore;
if(uBefore) { // Vorherigen Eintrag anpassen pEntry = pItems[uBefore]; pEntry->uNextItem = uPos; } else { // Am Anfang einf�gen pFirst[0] = uPos; }
if(uItem) { // N�chsten Eintrag anpassen pEntry = pItems[uItem]; pEntry->uPrevItem = uPos; } else { // Am Ende anh�ngen pLast[0] = uPos; } break;
case U(TVI_AFTER): // Nach einem Eintrag einf�gen uAfter = uParent;
if(pParent) { // Einen Root-Eintrag einf�gen pParent ->bFlags = bFlag; uParent = pParent->uParent; pParent = pItems [uParent];
if(!pParent) { pNew->uParent = 0; pNew->uLevel = 0; uParent = 0; uFirst = 0xFFFFFFFF; pFirst = &pData->uFirstChild; pLast = &pData->uLastChild; } else { // Einen Tree-Eintrag einf�gen pNew->uParent = uParent; pNew->uLevel = pParent->uLevel + 1; uFirst = pParent->uFirstChild; pFirst = &pParent->uFirstChild; pLast = &pParent->uLastChild;
if(pParent->bFlags & TVIX_VARBUTTON) { pParent->bFlags |= TVIX_HASBUTTON; } } }
default : // Hinter einen Eintrag einf�genDoInsert: uItem = pFirst[0]; if(!uItem) { // Gibt es keine Kindeintr�ge pFirst[0] = uPos; pLast [0] = uPos; break; }
if(uAfter > pData->uTreeItemsMax) { if((uAfter & 0xFFF00000) == 0xFFE00000) { // In einer genauen Reihe nach Patent einf�gen uAfter &= 0xFFFFF;
uItem = pFirst[0]; if(!uItem) { // Gibt es keine Kindeintr�ge pFirst[0] = uPos; pLast [0] = uPos; break; }
if(uAfter == 0) { // In die erste Reihe einf�gen pEntry = pItems[uItem]; pEntry->uPrevItem = uPos; pNew ->uNextItem = uItem; pFirst[0] = uPos; break; }
uNum = 1; uBefore = 0; // Suche Einf�gereihe for(; uItem; uItem = pItems[uItem]->uNextItem) { uBefore = uItem;
if(uNum == uAfter) { uItem = pItems[uItem]->uNextItem; break; }
uNum++; }
pNew->uNextItem = uItem; pNew->uPrevItem = uBefore;
if(uBefore) { // Vorherigen Eintrag anpassen pEntry = pItems[uBefore]; pEntry->uNextItem = uPos; } else { // Am Anfang einf�gen pFirst[0] = uPos; }
if(uItem) { // N�chsten Eintrag anpassen pEntry = pItems[uItem]; pEntry->uPrevItem = uPos; } else { // Am Ende anh�ngen pLast[0] = uPos; }
break; }
pEntry = NULL; } else { pEntry = pItems[uAfter]; }
if(pEntry && uParent == pEntry->uParent) { // Stimmt der Elterneintrag ? uItem = pEntry->uNextItem; uBefore = uAfter; } else { uItem = 0; uBefore = pLast[0]; pEntry = pItems[uBefore]; }
pNew->uNextItem = uItem; pNew->uPrevItem = uBefore;
if(uBefore) { // Vorherigen Eintrag anpassen pEntry->uNextItem = uPos; } else { // Am Anfang einf�gen pFirst[0] = uPos; }
if(uItem) { // N�chsten Eintrag anpassen pEntry = pItems[uItem]; pEntry->uPrevItem = uPos; } else { // Am Ende anh�ngen pLast[0] = uPos; }
break; }
pItems[uPos] = pNew; pData->uTreeItemsCount++; // Die Anzeigezeilen akualisieren if(!pParent || !uFirst || (pParent->uState & TVIS_EXPANDED)) { uItem = pNew->uPrevItem; if(!uItem) uItem = uParent;
if(!uItem) UpdateItems(pData, 0); else { pEntry = pItems[uItem]; if(pEntry && pEntry->uShowPos) UpdateItems(pData, uItem); } }
if(pNew->uState & TVIS_SELECTED) { // Den ausgew�hlten Eintrag ausw�hlen TreeListSelectItem(pData, uPos, 0, TVC_UNKNOWN); }
return uPos;}
//*****************************************************************************//*//* TreeListSetItem//*//*****************************************************************************// �ndert einen Eintrag im Fenster// pData : Zeiger auf die Fensterdaten// pItem : Zeiger auf die ein zu �ndernden Daten// Ergibt 1 wenn ok oder 0 bei einem Fehlerstatic int TreeListSetItem(TreeListData *pData, const TV_ITEM *pItem) {
BYTE bCall; BYTE bFlags; ExtraItem **pList; ExtraItem *pExtra; BaseItem *pEntry; unsigned uChange; unsigned uMask; unsigned uBits; unsigned uItem; unsigned uSub; unsigned uLen; int iVal; int iRet;
uChange = 0;
uItem = U(pItem->hItem); if(uItem > pData->uTreeItemsMax) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uBits = pItem->mask;
if(uBits & TVIF_SUBITEM) { // Einen Extraeintrag �ndern uSub = pItem->cChildren; if(uSub > 0) { if(uSub >= pData->uColumnCount) return 0; pList = pData->pExtraItems[uSub - 1]; pExtra = pList[uItem];
if(!pExtra) { // Einen neuen Eintrag erzeugen pExtra = new(ExtraItem, 1); memset(pExtra, 0, sizeof(ExtraItem)); pExtra->iImage = TV_NOIMAGE; pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE); pList[uItem] = pExtra; }
if(uBits & TVIF_PARAM) { pEntry->lParam = pItem->lParam; }
if((uBits & TVIF_IMAGE) && pExtra->iImage != pItem->iImage) { if(pData->hImages) uChange = 1; pExtra->iImage = pItem->iImage; if(pExtra->iImage == I_IMAGECALLBACK) pExtra->bCallback |= TVIF_IMAGE; else pExtra->bCallback &= TVIF_IMAGE; }
if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen if(pItem->pszText == LPSTR_TEXTCALLBACK) { if(pExtra->pText) delete(pExtra->pText); pExtra->bCallback |= TVIF_TEXT; pExtra->uTextSize = 0; pExtra->pText = 0; uChange = 1; } else { uLen = str_len(pItem->pszText);
if(uLen > pExtra->uTextSize || !pExtra->pText) { if(pExtra->pText) delete(pExtra->pText); pExtra->pText = new(TCHAR, uLen + 1); }
memcpy(pExtra->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR)); pExtra->bCallback &= ~TVIF_TEXT; pExtra->uTextSize = (WORD)uLen; pExtra->iTextPixels = 0; uChange = 1; } }
if(uBits & TVIF_STATE) { // Den Status �ndern uMask = pItem->stateMask&~TVIS_BASEFLAGS; uBits = uMask & (pExtra->uState ^ pItem->state); uBits |= (pItem->stateMask & TVIS_BASEFLAGS) & (pEntry->uState ^ pItem->state); pExtra->uState &= ~uMask; pExtra->uState |= uMask & pItem->state;
if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && (pData->hImages || pData->aColumn[uSub].bEdit >= TVAX_CHECK)) { uChange = 1; // Ein Icon hats sich ver�ndert }
if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) { pExtra->iTextPixels = 0; uChange = 1; }
if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) { iVal = TreeListToggleItem(pData, uItem, 0); if(iVal < 0) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; }
if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl ge�ndert iVal = (pData->uStyleEx & TVS_EX_SUBSELECT) ? uSub : 0;
if(pItem->state & TVIS_SELECTED) { iRet = TreeListSelectItem(pData, uItem, iVal, TVC_UNKNOWN); } else if(pData->uStyleEx & TVS_EX_MULTISELECT) { TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN); iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN); } else { iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN); }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
if(iRet >= 2) { pList = pData->pExtraItems[uSub - 1]; pExtra = pList[uItem]; if(!pExtra) return 0; } else if(iRet == 1) { uChange = 1; } } }
if(!uChange || !pEntry->uShowPos) return 1; // Neuzeichnen des Eintrages
UpdateRect(pData, uItem, uSub);
return 1; }
uBits &= ~TVIF_CHILDREN; }
//******************** Einen Basis Eintrag �ndern ***************************** if(uBits & TVIF_PARAM) { pEntry->lParam = pItem->lParam; }
if((uBits & TVIF_IMAGE) && pEntry->iImage != pItem->iImage) { pEntry->iImage = pItem->iImage; if(!(pEntry->uState & TVIS_SELECTED) && pData->hImages) uChange = 1; if(pEntry->iImage == I_IMAGECALLBACK) pEntry->bCallback |= TVIF_IMAGE; else pEntry->bCallback &= TVIF_IMAGE; }
if((uBits & TVIF_SELECTEDIMAGE) && pEntry->iSelectedImage != pItem->iSelectedImage) { pEntry->iSelectedImage = pItem->iSelectedImage; if((pEntry->uState & TVIS_SELECTED) && pData->hImages) uChange = 1; if(pEntry->iSelectedImage == I_IMAGECALLBACK) pEntry->bCallback |= TVIF_SELECTEDIMAGE; else pEntry->bCallback &= TVIF_SELECTEDIMAGE; }
if(uBits & TVIF_CHILDREN) { bCall = pEntry->bCallback; bFlags = pEntry->bFlags;
switch(pItem->cChildren) { case 0: pEntry->bCallback &= ~TVIF_CHILDREN; pEntry->bFlags &= ~TVIX_HASBUTTON; pEntry->bFlags |= TVIX_VARBUTTON; break;
case 1: pEntry->bCallback &= ~TVIF_CHILDREN; pEntry->bFlags &= TVIX_VARBUTTON; pEntry->bFlags |= TVIX_HASBUTTON; break;
case I_CCB: pEntry->bCallback |= TVIF_CHILDREN; pEntry->bFlags &= ~TVIX_VARBUTTON; break;
default : pEntry->bCallback &= ~TVIF_CHILDREN; pEntry->bFlags |= TVIX_VARBUTTON;
if(pEntry->uFirstChild) pEntry->bFlags |= TVIX_HASBUTTON; else pEntry->bFlags &= ~TVIX_HASBUTTON; }
if(bCall != pEntry->bCallback || bFlags != pEntry->bFlags) { uChange = 1; } }
if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen if(pItem->pszText == LPSTR_TEXTCALLBACK) { if(pEntry->pText) delete(pEntry->pText); pEntry->bCallback |= TVIF_TEXT; pEntry->uTextSize = 0; pEntry->pText = 0; uChange = 1; } else { uLen = str_len(pItem->pszText);
if(uLen > pEntry->uTextSize) { if(pEntry->pText) delete(pEntry->pText); pEntry->pText = new(TCHAR, uLen + 1); }
memcpy(pEntry->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR)); pEntry->bCallback &= ~TVIF_TEXT; pEntry->uTextSize = (WORD)uLen; pEntry->iTextPixels = 0; uChange = 1; } }
if(uBits & TVIF_STATE) { uMask = pItem->stateMask;
if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus uMask &= ~TVIS_EXPANDED; }
uBits = uMask & (pEntry->uState ^ pItem->state); pEntry->uState &= ~uMask; pEntry->uState |= uMask & pItem->state;
if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && pData->hImages) { uChange = 1; }
if(uBits & TVIS_STATEIMAGEMASK) { // Haben sich die State-Bits ver�ndert if(pData->hStates) { uChange = 1; }
if(pData->uStyleEx & TVS_EX_BITCHECKBOX) { if(pEntry->uState & 0x1000) { pData->uSingleSel = uItem; } else if(pData->uSingleSel == uItem) { pData->uSingleSel = 0; } } else { if((pEntry->uState & TVIS_STATEIMAGEMASK) == 0x2000) { pData->uSingleSel = uItem; } else if(pData->uSingleSel == uItem) { pData->uSingleSel = 0; } } }
if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) { pEntry->iTextPixels = 0; uChange = 1; }
if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl ge�ndert pEntry->uState ^= TVIS_SELECTED;
if(pItem->state & TVIS_SELECTED) { iRet = TreeListSelectItem(pData, uItem, 0, TVC_UNKNOWN); } else if(pData->uStyleEx & TVS_EX_MULTISELECT) { TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN); iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN); } else { iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN); }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
if(iRet == 1) { uChange = 1; } }
if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) { // Sollen Teile auf/zugeklappt werden uMask &= TVIS_EXPANDED | TVIS_EXPANDPARTIAL; pEntry->uState ^= TVIS_EXPANDED; pEntry->uState ^= uBits & uMask; iVal = uMask & pItem->state;
iRet = TreeListToggleItem(pData, uItem, iVal); if(iRet) { // Abbruch oder Fehler beim Auf/Zuklappen if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages UpdateRect(pData, uItem, 0); }
return 0; }
pEntry->uState &= ~uMask; pEntry->uState |= iVal; } }
if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages UpdateRect(pData, uItem, 0); } return 1;}
//*****************************************************************************//*//* TreeListGetItem//*//*****************************************************************************// Daten vone einem Eintrag abfragen// pData : Zeiger auf die Fensterdaten// pItem : Zeiger auf die den Datenspeicher// Ergibt 1 wenn ok oder 0 bei einem Fehlerstatic unsigned TreeListGetItem(TreeListData *pData, TV_ITEM *pItem) {
ExtraItem **pList; ExtraItem *pExtra; BaseItem *pEntry; unsigned uBits; unsigned uItem; unsigned uSub; unsigned uLen;
uItem = U(pItem->hItem); if(uItem > pData->uTreeItemsMax) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uBits = pItem->mask;
if(uBits & TVIF_SUBITEM) { // Einen Extraeintrag abfragen uSub = pItem->cChildren; if(uSub > 0) { if(uSub >= pData->uColumnCount) return 0; pList = pData->pExtraItems[uSub - 1]; pExtra = pList[uItem];
if(!pExtra) { // Einen neuen Eintrag erzeugen pExtra = new(ExtraItem, 1); memset(pExtra, 0, sizeof(ExtraItem)); pExtra->iImage = TV_NOIMAGE; pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE); pList[uItem] = pExtra; }
if(uBits & TVIF_PARAM) { pItem->lParam = pEntry->lParam; }
if(uBits & TVIF_IMAGE) { pItem->iImage = pExtra->iImage; }
if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen if(pExtra->pText == LPSTR_TEXTCALLBACK) { pItem->pszText = LPSTR_TEXTCALLBACK; } else if(uBits & TVIF_TEXTPTR) { if(!pExtra->pText) { pItem->pszText = _T(""); pItem->cchTextMax = 0; } else { pItem->pszText = pExtra->pText; pItem->cchTextMax = pExtra->uTextSize + 1; } } else { if(pExtra->pText) { uLen = pExtra->uTextSize + 1; if(pItem->cchTextMax < (int)uLen) { if(pItem->cchTextMax <= 0) { uLen = 0; } else { uLen = pItem->cchTextMax - 1; pItem->pszText[uLen] = 0; } }
memcpy(pItem->pszText, pExtra->pText, uLen * sizeof(TCHAR)); } else { if(pItem->cchTextMax > 0) { pItem->pszText[0] = 0; } } } }
if(uBits & TVIF_STATE) { pItem->state = pExtra->uState&~TVIS_BASEFLAGS; pItem->state &= pItem->stateMask; }
return 1; }
if(pEntry->bCallback & TVIF_CHILDREN) pItem->cChildren = I_CHILDRENCALLBACK; else pItem->cChildren = (pEntry->uFirstChild) ? 1 : 0;
uBits &= ~TVIF_CHILDREN; }
//******************** Einen Basis Eintrag �ndern ***************************** if(uBits & TVIF_PARAM) { pItem->lParam = pEntry->lParam; }
if(uBits & TVIF_IMAGE) { pItem->iImage = pEntry->iImage; }
if(uBits & TVIF_SELECTEDIMAGE) { pItem->iSelectedImage = pEntry->iSelectedImage; }
if(uBits & TVIF_CHILDREN) { if(pEntry->bCallback & TVIF_CHILDREN) pItem->cChildren = I_CHILDRENCALLBACK; else pItem->cChildren = (pEntry->uFirstChild) ? 1 : 0; }
if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen if(pEntry->pText == LPSTR_TEXTCALLBACK) { pItem->pszText = LPSTR_TEXTCALLBACK; } else if(uBits & TVIF_TEXTPTR) { pItem->pszText = pEntry->pText; pItem->cchTextMax = pEntry->uTextSize + 1; } else { uLen = pEntry->uTextSize + 1; if(pItem->cchTextMax < (int)uLen) { if(pItem->cchTextMax <= 0) { uLen = 0; } else { uLen = pItem->cchTextMax - 1; pItem->pszText[uLen] = 0; } }
memcpy(pItem->pszText, pEntry->pText, uLen * sizeof(TCHAR)); } }
if(uBits & TVIF_STATE) { pItem->state = pEntry->uState; pItem->state &= pItem->stateMask; }
return 1;}
//*****************************************************************************//*//* TreeListDeleteColumn//*//*****************************************************************************// L�scht eine Spalte aus dem Header// pData : Zeiger auf die Fensterdaten// uCol : Ist die Nummer der Spalte die gel�scht werden soll// Ergibt 1 wenn die Spalte gel�scht wurdestatic int TreeListDeleteColumn(TreeListData *pData, unsigned uCol) {
ExtraItem **pList; ExtraItem *pExtra; RECT sRect; BYTE bItem; BYTE bByte; unsigned uPos; unsigned uSub; unsigned uItem; unsigned uIndex; int iDelta; int iXoff; int iNum; int iCnt; int iVar; int iSub; int iAll; int iFix;
if(uCol >= pData->uColumnCount) return 0;
if(uCol && uCol == pData->uSelectedSub) { // Ist die Auswahl in der Spalte TreeListSelectItem(pData, pData->uSelectedItem, 0, TVC_UNKNOWN); }
if(uCol && uCol == pData->uEditSub) { pData->uEditSub = 0; pData->uEditItem = 0; TreeListEndLabelEdit(pData, 0); }
if(uCol && uCol == pData->uFocusSub) { pData->uFocusSub = 0; pData->uFocusItem = 0; }
if(uCol == pData->uTrackedSub) { pData->uTrackedSub = 0; pData->uTrackedItem = 0; }
GetClientRect(pData->hWnd, &sRect);
iDelta = pData->aColumn[uCol].sSize; iSub = pData->aColumn[uCol].bWeight; iCnt = 0; iVar = 0; iFix = 0; iAll = 0;
for(uPos = 0; uPos < pData->uColumnCount; uPos++) { // Z�hlern der variablen Spalten if(uPos == uCol) continue; if(pData->aColumn[uPos].bWeight == 0) { iFix += pData->aColumn[uPos].sSize; continue; }
iVar += pData->aColumn[uPos].sSize; iAll += pData->aColumn[uPos].bWeight; iCnt += 1; }
Header_DeleteItem(pData->hHeader, uCol); pData->uColumnCount--;
if(pData->uColumnCount > 0) { // Liste mit Extraeintr�gen l�schen iNum = uCol - 1; if(iNum < 0) iNum = 0;
pList = pData->pExtraItems[iNum]; if(pList) { for(uItem = 0; uItem <= pData->uTreeItemsMax; uItem++) { // Alle Eintr�ge aus der Liste l�schen pExtra = pList[uItem]; if(!pExtra) continue;
if(pExtra->pText) { pExtra->uTextSize = 0; delete(pExtra->pText); }
delete(pExtra); }
memmove(pData->pExtraItems + iNum, pData->pExtraItems + iNum + 1, sizeof(pList) * (MAX_COLUMNS - 1 - iNum)); pData->pExtraItems[pData->uColumnCount] = NULL; delete(pList); } } else { iNum = MAX_COLUMNS; }
if(pData->aColumn[uCol].bWeight) { pData->uColumnCountVar--; }
if(pData->aColumn[uCol].bMark) { pData->uMarkedCols--; }
uSub = pData->aColumnPos[uCol];
memmove(pData->aColumn + uCol, pData->aColumn + uCol + 1, (MAX_COLUMNS - 1 - uCol)*sizeof(ColumnData));
for(uIndex = 0; uIndex < uSub; uIndex++) { // Zuordnungs-Array anpassen bItem = pData->aColumnPos[uIndex - 1]; if(bItem < uCol) continue;
bItem++; pData->aColumnPos[uIndex] = bItem; }
for(; uIndex <= pData->uColumnCount; uIndex++) { // Spaltenpositionen verschieben bItem = pData->aColumnPos[uIndex + 1];
if(bItem >= uCol) { uCol--; }
pData->aColumnPos[uIndex] = bItem; }
for(uIndex = pData->uColumnCount; uIndex > 0;) { uIndex--; bByte = pData->aColumn[uIndex].bIndex;
if(bByte >= uSub) { bByte--; pData->aColumn[uIndex].bIndex = bByte; }
pData->aColumn[uIndex].bNext = pData->aColumnPos[bByte + 1]; }
pData->iFixSize = iFix; pData->iAllWeight = iAll; pData->aColumn[pData->uColumnCount].bWeight = 0;
if(iCnt && iDelta) { // Variable Breiten anpassen ChangeColSize(pData, iDelta); } else { if(iSub && !iCnt) { pData->iVarSize = 0; } }
if(pData->uSelectedSub > uCol) { // Ist die Auswahl vor der Spalte pData->uSelectedSub--; }
if(pData->uEditSub > uCol) { pData->uEditSub--; }
if(pData->uFocusSub > uCol) { pData->uFocusSub--; }
if(pData->uTrackedSub > uCol) { pData->uTrackedSub--; }
if(!pData->uColumnCount) { // Den Header l�schen DestroyWindow(pData->hHeader); pData->hHeader = NULL; pData->uStartPixel = 0; pData->iRowHeight = 1; UpdateHeight(pData); InvalidateRect(pData->hWnd, &sRect, FALSE); }
iXoff = UpdateColumns(pData); // Hat sich die Spaltenbreiten ver�ndert if(iXoff < 0x10000) { sRect.left = iXoff; sRect.left -= pData->uScrollX; sRect.top = pData->uStartPixel; InvalidateRect(pData->hWnd, &sRect, FALSE); }
UpdateScrollX(pData);
return 1;}
//*****************************************************************************//*//* TreeListInsertColumn//*//*****************************************************************************// Adds a new column in the header// pData : Zeiger auf die Fensterdaten// uCol : Ist die Nummer der Spalte die eingef�gt wird// pInsert : Zeiger auf die ein zu f�genden Daten// Returns the positio of the new column or -1 if an error occurs.static int TreeListInsertColumn(TreeListData *pData, unsigned uCol, TV_COLUMN *pColumn) {
ExtraItem **pList; TV_COLSIZE sNotify; HDITEM sItem; RECT sRect; short sFixed; UINT uIndex; BYTE bByte; BYTE bItem; BYTE bMark; BYTE bMinEx; BYTE bAlign; int iWeight; int iDelta; int iStart; int iSize; int iXoff; int iYoff; int iNum; int iVar; int iAll; int iAdd; int iMin; int iFix;
GetClientRect(pData->hWnd, &sRect);
if(!pData->hHeader) { // Create a new header iStart = bDrawWithTheme ? GetSystemMetrics(SM_CYHSCROLL) : 17; //SM_CYHSCROLL is not enough tall with themes disabled apps; iYoff = sRect.top + iStart;
if(pData->uStyleEx & TVS_EX_HIDEHEADERS) { iYoff = 0; }
pData->hHeader = CreateWindow(WC_HEADER, NULL, WS_VISIBLE | WS_CHILD | HDS_HORZ | HDS_BUTTONS | HDS_DRAGDROP, sRect.left, sRect.top, sRect.right, iYoff, pData->hWnd, (HMENU)1, NULL, NULL); if(!pData->hHeader) return -1;
pData->uStartPixel = (pData->uStyleEx & TVS_EX_HIDEHEADERS) ? 0 : iStart; pData->iRowHeight = 1; UpdateHeight(pData);
InvalidateRect(pData->hWnd, &sRect, FALSE); if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST){ SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg); } else { SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages); } SendMessage(pData->hHeader, WM_SETFONT, (WPARAM)hDefaultFontN, 0);
if(pData->uSizeX <= pData->uStartPixel) pData->uSizeYsub = 0; else pData->uSizeYsub = pData->uSizeX - pData->uStartPixel; }
if(pData->uColumnCount >= MAX_COLUMNS) { // Pr�fe die Anzahl der Spalten return -1; }
memset(&sItem, 0, sizeof(sItem)); // Die Spaltendaten zusammenstellen
if(uCol >= pData->uColumnCount) { uCol = pData->uColumnCount; }
if(pColumn->mask & TVCF_FMT) { // text alignment sItem.mask |= HDI_FORMAT; sItem.fmt = pColumn->fmt;
switch(sItem.fmt & HDF_JUSTIFYMASK) { case HDF_CENTER: bAlign = DT_CENTER; break; case HDF_RIGHT: bAlign = DT_RIGHT; break; default: bAlign = DT_LEFT; break; } } else { bAlign = DT_LEFT; }
if(pColumn->mask & TVCF_IMAGE) { // Hat die Spalte auch ein Icon sItem.mask |= HDI_IMAGE; sItem.iImage = pColumn->iImage; }
if(pColumn->mask & TVCF_TEXT) { // Auch einen Text �bergeben sItem.mask |= HDI_TEXT; sItem.pszText = pColumn->pszText; }
if(pColumn->mask & TVCF_MIN) { // Auch einen Min-Wert �bergeben iMin = pColumn->iOrder; bMinEx = 1;
if(iMin < 0) { iMin = -iMin; bMinEx = 0; } } else { iMin = 16; bMinEx = 0; }
if(pColumn->mask & TVCF_WIDTH) { // Fixe Breite f�r die Spalte iWeight = 0; sItem.mask |= HDI_WIDTH; sItem.cxy = pColumn->cx; iSize = pColumn->cx; iDelta = -pColumn->cx; iAdd = 0; } else { // Variable vordefinierte Breite if(pColumn->mask & TVCF_VWIDTH) iWeight = pColumn->cx; else iWeight = 1;
iVar = pData->iVarSize; iFix = pData->iFixSize; iAll = pData->iAllWeight; iSize = pData->uSizeX - iVar - iFix;
if(iWeight <= 0) iWeight = 1; if(iWeight > 255) iWeight = 255;
if(pData->uColumnCountVar) { // Gibt es schon variable Spalten iSize = (iVar * iWeight) / (iAll + iWeight); iDelta = -iSize; } else { iDelta = 0; }
sItem.mask |= HDI_WIDTH; sItem.cxy = iSize; iAdd = 1;
if(sItem.cxy < iMin) sItem.cxy = iMin; }
uCol = Header_InsertItem(pData->hHeader, uCol, &sItem); if(uCol & 0x80000000) return -1;
if(pData->uColumnCount > 0) { // Liste mit Extraeintr�gen erzeugen pList = new(ExtraItem*, pData->uTreeItemsMax + 1); if(!pList) { Header_DeleteItem(pData->hHeader, uCol); return -1; }
memset(pList, 0, sizeof(ExtraItem *) * (pData->uTreeItemsMax + 1));
iNum = uCol - 1; if(iNum < 0) iNum = 0;
memmove(pData->pExtraItems + iNum + 1, pData->pExtraItems + iNum, sizeof(pList) * (MAX_COLUMNS - 2 - iNum)); pData->pExtraItems[iNum] = pList; }
memmove(pData->aColumn + uCol + 1, pData->aColumn + uCol, (MAX_COLUMNS - 1 - uCol)*sizeof(ColumnData));
for(uIndex = pData->uColumnCount + 2; uIndex > uCol; uIndex--) { // Zuordnungs-Array anpassen bItem = pData->aColumnPos[uIndex - 1]; if(bItem >= uCol) bItem++;
pData->aColumnPos[uIndex] = bItem; }
pData->aColumnPos[uCol] = (BYTE)uCol;
while(uIndex > 0) { uIndex--;
bItem = pData->aColumnPos[uIndex]; if(bItem < uCol) continue;
bItem++; pData->aColumnPos[uIndex] = bItem; }
for(uIndex = pData->uColumnCount;;) { // Folgende Spalten verschieben bByte = pData->aColumn[uIndex].bIndex;
if(bByte >= uCol) { bByte++; pData->aColumn[uIndex].bIndex = bByte; }
if(uIndex == 0) break; uIndex--; }
bMark = 0; sFixed = 0;
if(pColumn->mask & TVCF_MARK) // Ist die Spalte markiert if(pColumn->fmt & TVCFMT_MARK) { bMark = 1; }
if(pColumn->mask & TVCF_FIXED) // Ist die Spalte fixiert if(pColumn->fmt & TVCFMT_FIXED) { sFixed = (short)((sItem.cxy > 0) ? sItem.cxy : 100); }
pData->aColumn[uCol].bWeight = (BYTE)iWeight; pData->aColumn[uCol].sReal = (short)sItem.cxy; pData->aColumn[uCol].sSize = (short)iSize; pData->aColumn[uCol].sMin = (short)iMin; pData->aColumn[uCol].bIndex = (BYTE)uCol; pData->aColumn[uCol].bMinEx = bMinEx; pData->aColumn[uCol].bAlign = bAlign; pData->aColumn[uCol].bMark = bMark; pData->aColumn[uCol].sFixed = sFixed; pData->uMarkedCols += bMark;
for(uIndex = pData->uColumnCount;;) { // N�chste sichtbare Spalten aktualisieren bByte = pData->aColumn[uIndex].bIndex; pData->aColumn[uIndex].bNext = pData->aColumnPos[bByte + 1]; if(uIndex == 0) break; uIndex--; }
if(pData->uColumnCountVar) { // Variable Breiten anpassen if(iDelta) { ChangeColSize(pData, iDelta); pData->iVarSize -= iDelta; } else if(!iAdd) { pData->iFixSize += iSize; } } else { if(iAdd) pData->iVarSize = iSize; else pData->iFixSize += iSize; }
pData->iAllWeight += iWeight; pData->uColumnCountVar += iAdd; pData->uColumnCount += 1;
if(pData->uSelectedSub > 0 && pData->uSelectedSub >= uCol) { pData->uSelectedSub++; }
if(pData->uTrackedSub > 0 && pData->uTrackedSub >= uCol) { pData->uTrackedSub++; }
if(pData->uFocusSub > 0 && pData->uFocusSub >= uCol) { pData->uFocusSub++; }
if(pData->uEditSub > 0 && pData->uEditSub >= uCol) { pData->uEditSub++; }
iXoff = UpdateColumns(pData); // Hat sich die Spaltenbreiten ver�ndert if(iXoff < 0x10000) { sRect.left = iXoff; sRect.left -= pData->uScrollX; sRect.top = pData->uStartPixel; InvalidateRect(pData->hWnd, &sRect, FALSE); }
UpdateScrollX(pData);
if(pData->uInsertMark) { // Fehlende Infomarken einf�gen TV_ITEM sSet; ExtraItem *pExtra;
sSet.mask = TVIF_SUBITEM; sSet.hItem = (HTREEITEM)(ULONG_PTR)pData->uInsertMark; sSet.cChildren = uCol;
TreeListSetItem(pData, &sSet);
pExtra = pData->pExtraItems[uCol - 1][pData->uInsertMark]; if(pExtra) { pExtra->uColorBk = pData->uColors[TVC_INSERT]; pExtra->bFlags |= TVIX_BKCOLOR; } }
if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Ge�nderte Spalten melden sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = uCol; sNotify.uIndex = pData->aColumn[uCol].bIndex; sNotify.uPosX = pData->aColumnXpos[uCol]; sNotify.iSize = pData->aColumn[uCol].sReal;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); }
return uCol;}
//*****************************************************************************//*//* TreeListScanColumn//*//*****************************************************************************// Berechnet die Breite der sichtbaren Eintr�ge einer Spalte// pData : Zeiger auf die Fensterdaten// uSub : Ist die Spalte// Ergibt sie gescannte Breitestatic int TreeListScanColumn(TreeListData *pData, unsigned uSub) {
BaseItem **pList; BaseItem *pEntry; ExtraItem *pExtra; ExtraItem **pItems; unsigned *pPList; unsigned uPos; int iMax; int iPos;
if(uSub >= pData->uColumnCount) return 0;
if(uSub > 0) { // Extraspalte pItems = pData->pExtraItems[uSub - 1]; pPList = pData->pItemPos; iMax = 0;
for(uPos = 0; uPos < pData->uItemPosCount; uPos++) { pExtra = pItems[pPList[uPos]]; if(!pExtra) { if(iMax < 8) iMax = 8; continue; }
if(pData->hSubImg && (pExtra->bFlags & TVIX_HASIMAGE)) iPos = pData->iSubImgXsize; else iPos = 0;
iPos += pExtra->iTextPixels + 8; if(iPos > iMax) iMax = iPos; }
return iMax; }
pList = pData->pTreeItems; pPList = pData->pItemPos; iMax = 0;
for(uPos = 0; uPos < pData->uItemPosCount; uPos++) { // Erste Spalte pEntry = pList[pPList[uPos]];
if(pEntry->bFlags & TVIX_HASIMAGE) iPos = pData->iImagesXsize; else iPos = 0;
iPos += pEntry->uLevel * pData->iIndent; iPos += pEntry->iTextPixels + 8; if(iPos > iMax) iMax = iPos; }
if(pData->uStyleEx & TVS_EX_ITEMLINES) { iMax += 1; }
if(pData->cHasRootRow) { iMax += pData->iIndent; }
if(pData->hStates) { iMax += pData->iStatesXsize; }
return iMax;}
//*****************************************************************************//*//* TreeListHitTest//*//*****************************************************************************// Pr�ft wo eine Koordinate im Fenster ist// pData : Zeiger auf die Fensterdaten// pInfo : Zeiger auf die ein zu f�genden Daten// Ergibt das Item auf dem die Koordinate zeigtstatic unsigned TreeListHitTest(TreeListData *pData, TV_HITTESTINFO *pInfo) {
BaseItem *pEntry; ExtraItem *pExtra; unsigned uItem; unsigned uNext; unsigned uSub; unsigned uCol; int iXpos; int iYpos; int iZpos; int iWidth; int iIcon;
iXpos = pInfo->pt.x; iYpos = pInfo->pt.y;
if((unsigned)iXpos >= pData->uSizeX) { pInfo->hItem = NULL; pInfo->flags = (iXpos < 0) ? TVHT_TOLEFT : TVHT_TORIGHT; return 0; }
iYpos -= pData->uStartPixel;
if((unsigned)iYpos >= pData->uSizeY) { pInfo->hItem = NULL; pInfo->flags = (iYpos < 0) ? TVHT_ABOVE : TVHT_BELOW; return 0; }
iZpos = iYpos / pData->iRowHeight; iZpos += pData->uScrollY;
if((unsigned)iZpos >= pData->uItemPosCount) { pInfo->hItem = NULL; pInfo->flags = TVHT_NOWHERE; return 0; }
iXpos += pData->uScrollX; uItem = pData->pItemPos [iZpos]; pEntry = pData->pTreeItems[uItem]; pInfo->hItem = (HTREEITEM)(ULONG_PTR)uItem;
if(!pEntry) return 0;
uSub = pData->aColumnPos[1];
if(iXpos >= pData->aColumnXpos[uSub]) { // Auf Extraeintrag for(uCol = 1; uCol < pData->uColumnCount; uCol++) { uSub = pData->aColumnPos[uCol ]; uNext = pData->aColumnPos[uCol + 1];
if(iXpos >= pData->aColumnXpos[uNext]) continue; iXpos -= pData->aColumnXpos[uSub ];
pExtra = pData->pExtraItems[uSub - 1][uItem];
if(pData->aColumn[uSub].bEdit >= TVAX_CHECK) { // Hat der Extraeintrag ein Icon iIcon = pData->iChecksXsize; } else if(pExtra && (pExtra->bFlags & TVIX_HASIMAGE)) { iIcon = pData->iImagesXsize; } else { iIcon = 0; }
pInfo->flags = uSub << 24;
if(iXpos < iIcon) { // Auf Icon pInfo->flags |= TVHT_ONSUBICON; return uItem; }
if(!pExtra || !pExtra->uTextSize) { // Auf Text wenn leerer Eintrag pInfo->flags |= TVHT_ONSUBLABEL; return uItem; }
switch(pData->aColumn[uSub].bAlign) { // Textausrichtung default : if(iXpos - iIcon < pExtra->iTextPixels + 5) { pInfo->flags |= TVHT_ONSUBLABEL; return uItem; } break;
case DT_RIGHT: iWidth = pData->aColumnXpos[uNext]; iWidth -= pData->aColumnXpos[uSub ];
if(iXpos >= iWidth - pExtra->iTextPixels - 5) { pInfo->flags |= TVHT_ONSUBLABEL; return uItem; } break;
case DT_CENTER: iWidth = pData->aColumnXpos[uNext]; iWidth -= pData->aColumnXpos[uSub ]; iWidth += iIcon; iWidth /= 2;
if(iXpos >= iWidth - pExtra->iTextPixels / 2 - 3) if(iXpos <= iWidth + pExtra->iTextPixels / 2 + 3) { pInfo->flags |= TVHT_ONSUBLABEL; return uItem; } break; }
pInfo->flags |= TVHT_ONSUBRIGHT;
return uItem; }
pInfo->flags = TVHT_ONRIGHTSPACE;
return uItem; }
if(!pData->cHasRootRow) { // Root-Linien ausgleichen iXpos += pData->iIndent; }
iXpos -= pData->iIndent * pEntry->uLevel;
if(iXpos < pData->iIndent) { // Auf einger�cktem Bereich if(pData->uStyle & TVS_HASBUTTONS) if(pEntry->bFlags & TVIX_HASBUTTON) { if(iXpos >= pData->iShift - 6) if(iXpos <= pData->iShift + 7) { iYpos %= pData->iRowHeight; iYpos -= pData->iRowHeight / 2;
if(iYpos >= -6 && iYpos <= 7) { pInfo->flags = TVHT_ONITEMBUTTON; return uItem; } } }
pInfo->flags = TVHT_ONITEMINDENT; return uItem; }
iXpos -= pData->iIndent;
if(pData->uStyleEx & TVS_EX_ITEMLINES) { iXpos--; }
if(pData->hStates) { // Auf der Auswahl-Box iXpos -= pData->iStatesXsize;
if(iXpos < 0) { pInfo->flags = TVHT_ONITEMSTATEICON; return uItem; } }
if(pEntry->bFlags & TVIX_HASIMAGE) { // Auf dem Icon iXpos -= pData->iImagesXsize;
if(pData->uStyleEx & TVS_EX_ITEMLINES) iXpos--;
if(iXpos < 0) { pInfo->flags = TVHT_ONITEMICON; return uItem; } } // Auf Text if(iXpos < pEntry->iTextPixels + 5 || !pEntry->pText || !pEntry->pText[0]) { pInfo->flags = TVHT_ONITEMLABEL; } else { pInfo->flags = TVHT_ONITEMRIGHT; }
return uItem;}
//*****************************************************************************//*//* TreeListSetTrackItem//*//*****************************************************************************// Setzt das den Einf�geeintrag// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages bei dem eingef�gt werden soll// iMode : 0=davor einf�gen 1=nachher einf�gen// Ergibt 1 wenn der Eintrag eingef�gt wurdestatic unsigned TreeListSetInsertMark(TreeListData *pData, unsigned uItem, int iMode) {
TV_INSERTSTRUCT sInsert; ExtraItem *pExtra; BaseItem *pEntry; unsigned uSub; int iRet;
if(pData->uInsertMark) { iRet = TreeListDeleteItem(pData, pData->uInsertMark, 1); pData->uInsertMark = 0; } else { iRet = 0; }
if(uItem == 0) return iRet; if(uItem > pData->uTreeItemsMax) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
if(iMode) { uItem = pEntry->uPrevItem; if(!uItem) uItem = U(TVI_FIRST); }
sInsert.hParent = (HTREEITEM)(ULONG_PTR)pEntry->uParent; sInsert.hInsertAfter = (HTREEITEM)(ULONG_PTR)uItem; sInsert.item.mask = TVIF_SELECTEDIMAGE | TVIF_IMAGE; sInsert.item.iImage = TV_NOIMAGE; sInsert.item.iSelectedImage = TV_NOIMAGE;
uItem = TreeListInsertItem(pData, &sInsert); if(!uItem) return 0;
pEntry = pData->pTreeItems[uItem]; pEntry->uColorBk = pData->uColors[TVC_INSERT]; pEntry->bFlags |= TVIX_BKCOLOR; sInsert.item.mask |= TVIF_SUBITEM; sInsert.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
for(uSub = 1; uSub < pData->uColumnCount; uSub++) { sInsert.item.cChildren = uSub;
TreeListSetItem(pData, &sInsert.item);
pExtra = pData->pExtraItems[uSub - 1][uItem]; pExtra->uColorBk = pData->uColors[TVC_INSERT]; pExtra->bFlags |= TVIX_BKCOLOR; }
pData->uInsertMark = uItem;
return uItem;}
//*****************************************************************************//*//* TreeListGetItemColor//*//*****************************************************************************// Holt die Farbe eins Feldes// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Ist die Spalte// iMode : 0=Hintergrundfarbe 1=Textfarbe abfragen// Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt warstatic LRESULT TreeListGetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, int iMode) {
COLORREF uColor; ExtraItem *pExtra; BaseItem *pEntry;
if(uItem > pData->uTreeItemsMax) return TV_NOCOLOR;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return TV_NOCOLOR;
if(uSub) { // Extra-Eintrag abfragen if(uSub >= pData->uColumnCount) return TV_NOCOLOR;
pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) return TV_NOCOLOR;
if(iMode) uColor = (pExtra->bFlags & TVIX_TEXTCOLOR) ? pExtra->uColorText : TV_NOCOLOR; else uColor = (pExtra->bFlags & TVIX_BKCOLOR) ? pExtra->uColorBk : TV_NOCOLOR; } else { if(iMode) uColor = (pEntry->bFlags & TVIX_TEXTCOLOR) ? pEntry->uColorText : TV_NOCOLOR; else uColor = (pEntry->bFlags & TVIX_BKCOLOR) ? pEntry->uColorBk : TV_NOCOLOR; }
return (LRESULT)uColor;}
//*****************************************************************************//*//* TreeListSetItemColor//*//*****************************************************************************// Setzt die Farbe eines Feldes// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Ist die Spalte// uColor : Ist die neue Farbe// iMode : 0=Hintergrundfarbe 1=Textfarbe einstellen// Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt warstatic COLORREF TreeListSetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, COLORREF uColor, int iMode) {
TV_ITEM sSet; COLORREF uOld; ExtraItem *pExtra; BaseItem *pEntry;
if(uItem > pData->uTreeItemsMax) return TV_NOCOLOR;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return TV_NOCOLOR;
if(uSub >= 255) { // Die Ganze Zeile �ndern if(pData->uColumnCount) { for(uSub = pData->uColumnCount; uSub > 0; uSub--) { TreeListSetItemColor(pData, uItem, uSub, uColor, iMode); } }
uSub = 0; }
if(uSub) { // Extra-Eintrag ver�ndern if(uSub >= pData->uColumnCount) return TV_NOCOLOR;
pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) { // Extra-Eintrag erzeugen sSet.mask = TVIF_SUBITEM; sSet.hItem = (HTREEITEM)(ULONG_PTR)uItem; sSet.cChildren = uSub;
if(!TreeListSetItem(pData, &sSet)) return TV_NOCOLOR;
pExtra = pData->pExtraItems[uSub - 1][uItem]; }
if(iMode) { // Textfarbe uOld = (pExtra->bFlags & TVIX_TEXTCOLOR) ? pExtra->uColorText : TV_NOCOLOR;
if(uColor == TV_NOCOLOR) { pExtra->bFlags &= ~TVIX_TEXTCOLOR; } else { pExtra->bFlags |= TVIX_TEXTCOLOR; pExtra->uColorText = uColor; } } else { // Hintergrund uOld = (pExtra->bFlags & TVIX_BKCOLOR) ? pExtra->uColorBk : TV_NOCOLOR;
if(uColor == TV_NOCOLOR) { pExtra->bFlags &= ~TVIX_BKCOLOR; } else { pExtra->bFlags |= TVIX_BKCOLOR; pExtra->uColorBk = uColor; } } } else { if(iMode) { // Textfarbe uOld = (pEntry->bFlags & TVIX_TEXTCOLOR) ? pEntry->uColorText : TV_NOCOLOR;
if(uColor == TV_NOCOLOR) { pEntry->bFlags &= ~TVIX_TEXTCOLOR; } else { pEntry->bFlags |= TVIX_TEXTCOLOR; pEntry->uColorText = uColor; } } else { // Hintergrund uOld = (pEntry->bFlags & TVIX_BKCOLOR) ? pEntry->uColorBk : TV_NOCOLOR;
if(uColor == TV_NOCOLOR) { pEntry->bFlags &= ~TVIX_BKCOLOR; } else { pEntry->bFlags |= TVIX_BKCOLOR; pEntry->uColorBk = uColor; } } }
if(uColor != uOld) { // Neu zeichnen UpdateRect(pData, uItem, uSub); }
return uOld;}
//*****************************************************************************//*//* TreeListSetTrackItem//*//*****************************************************************************// Setzt das unterstrichene Item// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uSub : Ist die Spalte// Ergibt 1 wenn der Eintrag unterstrichen wurdestatic int TreeListSetTrackItem(TreeListData *pData, unsigned uItem, unsigned uSub) {
ExtraItem *pExtra; BaseItem *pEntry; int iRet = 1;
if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) { uSub = 0; } else { if(uSub >= pData->uColumnCount) { uItem = 0; uSub = 0; iRet = 0; } }
if(uItem > pData->uTreeItemsMax) { uItem = 0; uSub = 0; iRet = 0; } else { if(uItem == pData->uTrackedItem) if(uSub == pData->uTrackedSub) { return iRet; } }
if(pData->uTrackedItem) { // Den alten Eintrag zur�cksetzen if(pData->uTrackedSub) { pExtra = pData->pExtraItems[pData->uTrackedSub - 1][pData->uTrackedItem]; if(pExtra) { pExtra->bFlags &= ~TVIX_TRACKED; UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub); } } else { pEntry = pData->pTreeItems[pData->uTrackedItem]; if(pEntry) { pEntry->bFlags &= ~TVIX_TRACKED; UpdateRect(pData, pData->uTrackedItem, 0); } } }
if(uItem) { // Den neuen Eintrag setzen if(uSub) { pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) { pData->uTrackedSub = uSub; pData->uTrackedItem = uItem; pExtra->bFlags |= TVIX_TRACKED; UpdateRect(pData, uItem, uSub); } else { iRet = 0; } } else { pEntry = pData->pTreeItems[uItem]; if(pEntry) { pData->uTrackedSub = 0; pData->uTrackedItem = uItem; pEntry->bFlags |= TVIX_TRACKED; UpdateRect(pData, uItem, 0); } else { iRet = 0; } } } else { // Keine Untersteichung pData->uTrackedSub = 0; pData->uTrackedItem = 0; }
return iRet;}
//*****************************************************************************//*//* TreeListGetNextItem//*//*****************************************************************************// Sucht den n�chsten Eintrag// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages// uFlags : Bestimmt nach welchem Eintrag gesucht werden soll// Ergibt 1 wenn der Eintrag unterstrichen wurdestatic unsigned TreeListGetNextItem(TreeListData *pData, unsigned uItem, unsigned uFlags) { BaseItem *pEntry; unsigned uStop; unsigned uPos;
switch(uFlags) { case TVGN_ROOT: return pData->uFirstChild;
case TVGN_NEXT: if(uItem > pData->uTreeItemsMax) { return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return pEntry->uNextItem;
case TVGN_PREVIOUS: if(uItem > pData->uTreeItemsMax) { return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return pEntry->uPrevItem;
case TVGN_PARENT: if(uItem > pData->uTreeItemsMax) { return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return pEntry->uParent;
case TVGN_CHILD: if(uItem > pData->uTreeItemsMax) { if(uItem == U(TVI_ROOT)) return pData->uFirstChild; return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return pEntry->uFirstChild;
case TVGN_LASTCHILD: if(uItem > pData->uTreeItemsMax) { if(uItem == U(TVI_ROOT)) return pData->uLastChild; return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return pEntry->uLastChild;
case TVGN_FIRSTVISIBLE: if(pData->uItemPosCount <= 0) return 0; if(pData->uItemPosCount <= pData->uScrollY) return 0;
uItem = pData->pItemPos[pData->uScrollY];
if(uItem > pData->uTreeItemsMax || !pData->pTreeItems[uItem]) { return 0; }
return uItem;
case TVGN_NEXTVISIBLE: if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0; if(pData->uFirstChild == 0) return 0;
pEntry = pData->pTreeItems[pData->uFirstChild];
uPos = pEntry->uShowPos; if(uPos <= pData->uScrollY) return 0;
return pData->uFirstChild; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uPos = pEntry->uShowPos; if(uPos <= pData->uScrollY) return 0; if(uPos > pData->uScrollY + pData->uPageEnties) return 0;
uItem = pData->pItemPos[uPos];
if(uItem > pData->uTreeItemsMax || !pData->pTreeItems[uItem]) { return 0; }
return uItem;
case TVGN_NEXTSELECTED: if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0;
uItem = pData->uFirstChild;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uState & TVIS_SELECTED) return uItem; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
for(;;) { if(pEntry->uFirstChild) { uItem = pEntry->uFirstChild; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; } else { for(;;) { uItem = pEntry->uParent; pEntry = pData ->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uNextItem) { uItem = pEntry->uNextItem; break; } } }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) break; if(pEntry->uState & TVIS_SELECTED) return uItem; }
return 0;
case TVGN_NEXTSELCHILD: if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0;
uItem = pData->uFirstChild;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uState & TVIS_SELECTED) return uItem;
uStop = 0; } else { pEntry = pData->pTreeItems[uItem]; if(!pEntry || !pEntry->uFirstChild) return 0;
uStop = uItem; }
for(;;) { if(pEntry->uFirstChild) { uItem = pEntry->uFirstChild; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; } else { for(;;) { uItem = pEntry->uParent; if(uItem == uStop) return 0; pEntry = pData ->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uNextItem) { uItem = pEntry->uNextItem; break; } } }
pEntry = pData ->pTreeItems[uItem]; if(!pEntry) break; if(pEntry->uState & TVIS_SELECTED) return uItem; }
return 0;
case TVGN_NEXTITEM: if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0;
uItem = pData->uFirstChild;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
return uItem; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
for(;;) { if(pEntry->uFirstChild) { uItem = pEntry->uFirstChild; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; } else { for(;;) { uItem = pEntry->uParent; pEntry = pData ->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uNextItem) { uItem = pEntry->uNextItem; break; } } }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) break;
return uItem; }
return 0;
case TVGN_PREVIOUSVISIBLE: if(uItem > pData->uTreeItemsMax) { return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uPos = pEntry->uShowPos - 1; if(uPos <= pData->uScrollY) return 0; if(uPos > pData->uScrollY + pData->uPageEnties) return 0;
return pData->pItemPos[uPos - 1];
case TVGN_LASTVISIBLE: uPos = pData->uItemPosCount; if(uPos <= 0) return 0; return pData->pItemPos[uPos - 1];
case TVGN_DROPHILITE: return pData->uTrackedItem;
case TVGN_DROPHILITESUB: return pData->uTrackedSub;
case TVGN_CARET: return pData->uSelectedItem;
case TVGN_CARETSUB: return pData->uSelectedSub;
case TVGN_FOCUS: return (pData->uFocusItem) ? pData->uFocusItem : pData->uSelectedItem;
case TVGN_FOCUSSUB: return (pData->uFocusItem) ? pData->uFocusSub : pData->uSelectedSub; }
return 0;}
//*****************************************************************************//*//* TreeListFindItem//*//*****************************************************************************// Sucht einen Kindeintrag mit einem bestimmten Text// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Elterneintrages// pFind : Die Struktur mit den Suchparametern// Ergibt die Nummer des Eintrages bzw. 0 wenn nicht gefunden wurdestatic unsigned TreeListFindItem(TreeListData *pData, unsigned uItem, TVFIND *pFind) { int iImage; BaseItem *pEntry; ExtraItem *pExtra; LPCTSTR pCmpText; unsigned uTextSize; unsigned uChkParam; unsigned uChkState; unsigned uChkText; unsigned uChkCase; unsigned uTextLen; unsigned uSub;
if(pFind->uFlags & TVIF_CHILD) { // In den Kindern suchen if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0; uItem = pData->uFirstChild; } else { pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uItem = pEntry->uFirstChild; } } else { if(uItem > pData->uTreeItemsMax) { // Ist der Eintrag g�ltig return 0; }
if(pFind->uFlags & TVIF_NEXT) { // Beim n�chsten Eintrag weitersuchen pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
uItem = pEntry->uNextItem; } }
uChkParam = pFind->uFlags & TVIF_PARAM; uChkState = pFind->uFlags & TVIF_STATE; uChkText = pFind->uFlags & TVIF_TEXT; uChkCase = pFind->uFlags & TVIF_CASE; uSub = pFind->uColumn; uTextLen = 0;
if(uChkText) { uTextLen = str_len(pFind->pText); }
for(; uItem; uItem = pEntry->uNextItem) { // Durchlaufe alle Kinder pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
if(uChkParam && pFind->lParam != pEntry->lParam) { // Vergleiche lParam continue; } // Vergleiche die State-Bits if(uChkState && ((pEntry->uState ^ pFind->uState)&pFind->uStateMask)) { continue; }
if(uChkText == 0) break;
if(uSub) { // Text von Spalten if(uSub >= pData->uColumnCount) continue;
pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) { pCmpText = _T(""); uTextSize = 0; } else { pCmpText = pExtra->pText; if(!pCmpText) pCmpText = _T(""); uTextSize = pExtra->uTextSize; } } else { // Text vom Haupteintrag if(pEntry->bCallback & TVIF_TEXT) { CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTextSize, &pCmpText); } else { pCmpText = pEntry->pText; if(!pCmpText) pCmpText = _T(""); uTextSize = pEntry->uTextSize; } }
if(uTextLen != uTextSize) continue;
if(uChkCase) { // Zwischen Gro�/Kleinbuchstaben unterscheiden if(!str_icmp(pCmpText, pFind->pText)) break; } else { if(!memcmp(pCmpText, pFind->pText, uTextSize * sizeof(TCHAR))) break; } }
return uItem;}
//*****************************************************************************//*//* TreeListNextSelUntil//*//*****************************************************************************// Sucht rekursiv ausgew�hlte Eintr�ge// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll// uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll// Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurdestatic unsigned TreeListNextSelUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
BaseItem *pEntry;
if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0;
uItem = pData->uFirstChild;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uState & TVIS_SELECTED) return uItem;
uStop = 0; } else { pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(!pEntry->uFirstChild && uItem == uStop) return 0; }
for(;;) { if(pEntry->uFirstChild) { uItem = pEntry->uFirstChild; if(uItem == uStop) return 0; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; if(uItem == uStop) return 0; } else { for(;;) { uItem = pEntry->uParent; if(uItem == uStop) return 0; pEntry = pData ->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uNextItem) { uItem = pEntry->uNextItem; if(uItem == uStop) return 0; break; } } }
pEntry = pData ->pTreeItems[uItem]; if(!pEntry) break; if(pEntry->uState & TVIS_SELECTED) return uItem; }
return 0;}
//*****************************************************************************//*//* TreeListNextUnselUntil//*//*****************************************************************************// Sucht rekursiv nicht ausgew�hlte Eintr�ge// pData : Zeiger auf die Fensterdaten// uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll// uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll// Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurdestatic unsigned TreeListNextUnselUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
BaseItem *pEntry;
if(uItem > pData->uTreeItemsMax) { if(uItem != U(TVI_ROOT)) return 0;
uItem = pData->uFirstChild;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if((pEntry->uState & TVIS_SELECTED) == 0) return uItem;
uStop = 0; } else { pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(!pEntry->uFirstChild && uItem == uStop) return 0; }
for(;;) { if(pEntry->uFirstChild) { uItem = pEntry->uFirstChild; if(uItem == uStop) return 0; } else if(pEntry->uNextItem) { uItem = pEntry->uNextItem; if(uItem == uStop) return 0; } else { for(;;) { uItem = pEntry->uParent; if(uItem == uStop) return 0; pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0; if(pEntry->uNextItem) { uItem = pEntry->uNextItem; if(uItem == uStop) return 0; break; } } }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) break; if((pEntry->uState & TVIS_SELECTED) == 0) return uItem; }
return 0;}
//*****************************************************************************//*//* TreeListChangeCheckbox//*//*****************************************************************************// Schaltet eine Checkboc um// pData : Zeiger auf die Fensterdaten// uItem : Ist der Eintrag der ge�ndert werden soll// pInfo :static void TreeListChangeCheckbox(TreeListData *pData, UINT uItem, int iPosX, int iPosY) {
BaseItem *pTemp; BaseItem *pEntry; NMTREEVIEW sNotify; TV_ITEM sItem; UINT uBits;
sNotify.itemOld.mask = 0; sNotify.itemOld.hItem = 0;
pEntry = pData->pTreeItems[uItem]; uBits = pEntry->uState & TVIS_STATEIMAGEMASK;
if(pData->uStyleEx & TVS_EX_SINGLECHECKBOX) { // Einzelauswahl pTemp = pData->pTreeItems[pData->uSingleSel];
if(pData->uSingleSel == uItem) { if(pData->uStyleEx & TVS_EX_BITCHECKBOX) { if(uBits & 0x1000) return; } else { if(uBits == 0x2000) return; } } else if(pData->uSingleSel && pTemp) { // Anderer Eintrag gew�hlt sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSingleSel; sItem.mask = TVIF_STATE; sItem.stateMask = TVIS_STATEIMAGEMASK; sItem.state = (pData->uStyleEx & TVS_EX_BITCHECKBOX) ? 0x0000 : 0x1000;
TreeListSetItem(pData, &sItem);
sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT; sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)pData->uSingleSel; sNotify.itemOld.stateMask = 0xFFFFFFFF; sNotify.itemOld.state = pTemp->uState; sNotify.itemOld.lParam = pTemp->lParam; sNotify.itemOld.pszText = pTemp->pText; sNotify.itemOld.cchTextMax = pTemp->uTextSize; sNotify.itemOld.cChildren = 0; } }
sItem.hItem = (HTREEITEM)(ULONG_PTR)uItem; sItem.mask = TVIF_STATE; sItem.stateMask = TVIS_STATEIMAGEMASK;
if(pData->uStyleEx & TVS_EX_BITCHECKBOX) sItem.state = (uBits ^ 0x1000); else sItem.state = (uBits & 0x1000) ? 0x2000 : 0x1000;
TreeListSetItem(pData, &sItem); pData->uSingleSel = uItem;
sNotify.hdr.code = TVN_CBSTATECHANGED; sNotify.action = VK_DBLCLK; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.pszText = pEntry->pText; sNotify.itemNew.cchTextMax = pEntry->uTextSize; sNotify.itemNew.cChildren = 0; sNotify.ptDrag.x = iPosX; sNotify.ptDrag.y = iPosY;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData);}
//*****************************************************************************//*//* TreeListMouseNotify//*//*****************************************************************************// Soll f�r einen Mausklick eine// pData : Zeiger auf die Fensterdaten// uMsg : Message des Mausklicks// wParam : WPARAM des Mausklicks// lParam : LPARAM des Mausklicksstatic void TreeListMouseNotify(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam) {
TV_HITTESTINFO sInfo; NMTREEVIEW sNotify; BaseItem *pEntry; unsigned uItem;
sInfo.flags = (UINT) wParam; sInfo.pt.x = LOWORD(lParam); sInfo.pt.y = HIWORD(lParam); uItem = TreeListHitTest(pData, &sInfo);
if(uItem) { pEntry = pData->pTreeItems[uItem]; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.cChildren = TVHT_SUBTOCOL(sInfo.flags); } else { sNotify.itemNew.stateMask = 0; sNotify.itemNew.state = 0; sNotify.itemNew.lParam = 0; }
sNotify.action = 0; sNotify.hdr.code = uMsg; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = LOWORD(lParam); sNotify.ptDrag.y = HIWORD(lParam);
SendNotify(pData, &sNotify.hdr);
}
//*****************************************************************************//*//* TreeListMouseClick//*//*****************************************************************************// Soll ein Mausklick ausgef�hrt werden. ACHTUNG UNLOCK wird ausgef�hrt// pData : Zeiger auf die Fensterdaten// uMsg : Message des Mausklicks// wParam : WPARAM des Mausklicks// lParam : LPARAM des Mausklicksstatic void TreeListMouseClick(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam) { ExtraItem *pExtra; BaseItem *pEntry; BaseItem *pTemp; TV_HITTESTINFO sInfo; NMTREEVIEW sNotify; unsigned uOldSub; unsigned uOldItem; unsigned uMaskItem; unsigned uMaskSub; unsigned uMsgOld; unsigned uToggle; unsigned uItem; unsigned uLine; unsigned uTemp; unsigned uStop; unsigned uSub; unsigned uSel; unsigned uPos; unsigned uNum; int iMode; int iAdd;
if(!pData->cIsEnabled) { // Ist das Fenster freigegeben return; }
if(!pData->cHasFocus) { // Hat das Fenster den Focus if(GetFocus() != pData->hWnd) { UNLOCK(pData); SetFocus(pData->hWnd); LOCK(pData);
if(GetFocus() != pData->hWnd) { UNLOCK(pData); return; } } else { pData->cHasFocus = 1; } }
sInfo.flags = (UINT) wParam; sInfo.pt.x = LOWORD(lParam); sInfo.pt.y = HIWORD(lParam); uItem = TreeListHitTest(pData, &sInfo); uMsgOld = uMsg; uToggle = 0;
if(uItem) { // Wurde auf einen Eintrag getr�ckt pEntry = pData->pTreeItems[uItem];
if(pData->uStyle & TVS_FULLROWSELECT) { uMaskItem = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON | TVHT_ONITEMRIGHT; uMaskSub = TVHT_ONSUBICON | TVHT_ONSUBLABEL | TVHT_ONSUBRIGHT; } else { uMaskItem = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON; uMaskSub = TVHT_ONSUBICON | TVHT_ONSUBLABEL; }
if(sInfo.flags & TVHT_ONITEMBUTTON) { // Eintrag aufklappen if(uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK) { pEntry = pData->pTreeItems[uItem]; if(pEntry && (pEntry->uState & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) { TreeListToggleItem(pData, uItem, 0); // Von + auf - umschalten } else { uToggle = 1; // Eintrag auflappen } } } else if(sInfo.flags & TVHT_ONITEMSTATEICON) { // Checkbox umschalten if(pData->uStyle & TVS_CHECKBOXES) if(uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK) { TreeListChangeCheckbox(pData, uItem, sInfo.pt.x, sInfo.pt.y); } } else if(sInfo.flags & uMaskItem) { // Eintrag ausw�hlen if(!(pData->uStyle & TVS_DISABLEDRAGDROP)) { if(uMsg == WM_LBUTTONDOWN) { pData->uDragFlags = MK_LBUTTON; pData->uDragItem = uItem; pData->uDragSub = 0; }
if(uMsg == WM_RBUTTONDOWN) { pData->uDragFlags = MK_RBUTTON; pData->uDragItem = uItem; pData->uDragSub = 0; } }
if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Mehrfachauswahl erlaubt if(uMsg == WM_RBUTTONDOWN) // Keine Abwahl wenn mehrer Eintr�ge aus gew�hlt if(pData->uSelectedCount > 1) { pEntry = pData->pTreeItems[uItem]; if(pEntry->uState & TVIS_SELECTED) { goto End; } }
if(uMsg == WM_LBUTTONDOWN) // Spezialsteuerung f�r Multiselect bei Darg if(!(wParam & (MK_CONTROL | MK_SHIFT))) if(pData->uSelectedCount > 0) { pEntry = pData->pTreeItems[uItem]; if(pEntry && (pEntry->uState & TVIS_SELECTED)) { pData->cClickFlag = 1; pData->cClickEdit = 0; goto End; } }
if(uMsg == WM_LBUTTONUP && pData->cClickFlag) { wParam &= ~(MK_CONTROL | MK_SHIFT); uMsg = WM_LBUTTONDOWN; }
if(wParam & MK_SHIFT) { // Bis zum angeklicken Ausw�hlen if(uMsg != WM_LBUTTONDOWN) if(uMsg != WM_LBUTTONDBLCLK) goto End;
pData->cClickEdit = 0;
uTemp = pData->uSelectedItem; if(!uTemp) { uTemp = pData->uFocusItem; if(!uTemp || !pData->cReSelect) goto End; }
pEntry = pData->pTreeItems[uTemp]; uLine = pEntry->uShowPos; if(!uLine) goto End;
pEntry = pData->pTreeItems[uItem]; uStop = pEntry->uShowPos; if(!uStop) goto End;
if(pData->uSelectedCount <= 1) { pData->uSelectedBase = uTemp; }
// Shift-Select neu ausw�hlen if(pData->cReSelect && pData->uSelectedBase) { TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE | TVC_DESELECT); TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
uTemp = pData->uSelectedBase; pTemp = pData->pTreeItems[uTemp]; uStop = uItem;
while(pTemp && pTemp->uShowPos == 0) { pTemp = pData->pTreeItems[pTemp->uParent]; if(!pTemp) break; }
if(pTemp) { if(!(pTemp->uState & TVIS_SELECTED)) { TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); }
if(pTemp->uShowPos < pEntry->uShowPos) { uStop = uItem; } else { uStop = uTemp; uTemp = uItem; }
for(;;) { uTemp = TreeListNextUnselUntil(pData, uTemp, uStop); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); } }
pData->cReSelect = 0; goto End; }
TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE);
iAdd = (uLine > uStop) ? -1 : 1; uPos = uLine;
if(uPos != uStop) { pEntry = pData->pTreeItems[pData->uSelectedBase];
while(pEntry && pEntry->uShowPos == 0) { pEntry = pData->pTreeItems[pEntry->uParent]; }
if(pEntry) { if(iAdd < 0){ if(pEntry->uShowPos > uPos && uPos > uStop) uPos--; } else { if(pEntry->uShowPos < uPos && uPos < uStop) uPos++; } } }
for(;; uPos += iAdd) { // Eintr�ge w�hlen uTemp = pData->pItemPos [uPos - 1]; pEntry = pData->pTreeItems[uTemp ]; uSel = pEntry->uState & TVIS_SELECTED;
if(uTemp != pData->uSelectedBase || !uSel) { TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE); uSel = pEntry->uState & TVIS_SELECTED; }
// Auch unsichtbare Kinder w�hlen pTemp = pData->pTreeItems[pEntry->uFirstChild]; if(pTemp && !pTemp->uShowPos) { if(uSel) { for(uNum = uTemp;;) { // Kinder ausw�hlen uNum = TreeListNextUnselUntil(pData, uNum, uTemp); if(!uNum) break; TreeListXorSelectItem(pData, uNum, TVC_BYMOUSE); } } else { for(uNum = uTemp;;) { // Kinder abw�hlen uNum = TreeListNextSelUntil(pData, uNum, uTemp); if(!uNum) break; TreeListXorSelectItem(pData, uNum, TVC_BYMOUSE); } } }
if(uPos == uStop) break; }
TreeListRemoveFocus(pData);
pEntry = pData->pTreeItems[uItem]; uSub = TVHT_SUBTOCOL(sInfo.flags); if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) uSub = 0;
pData->uFocusSub = uSub; pData->uFocusItem = uItem;
if(uSub) { pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) pExtra->bFlags |= TVIX_FOCUSED; } else { pEntry->bFlags |= TVIX_FOCUSED; }
UpdateRect(pData, uItem, uSub);
TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE); TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
goto End; }
if(wParam & MK_CONTROL) { // Einzelen Eintrag umschalten pData->uSelectedBase = uItem; pData->cReSelect = 1; pData->cClickEdit = 0;
pEntry = pData->pTreeItems[uItem]; if(pEntry && (pEntry->uState & TVIS_SELECTED)) { if(uMsg != WM_LBUTTONDOWN) if(uMsg != WM_LBUTTONDBLCLK) goto End;
TreeListSelectItem(pData, 0, 0, TVC_BYMOUSE);
if(TreeListXorSelectItem(pData, uItem, TVC_BYMOUSE)) { // Auch unsichtbare Kinder abw�hlen pTemp = pData->pTreeItems[pEntry->uFirstChild]; if(pTemp && !pTemp->uShowPos) for(uTemp = uItem;;) { uTemp = TreeListNextSelUntil(pData, uTemp, uItem); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE); } }
uTemp = pData->uFocusItem; if(uTemp) { // Ist ein Focus definiert TreeListRemoveFocus(pData); }
uSub = TVHT_SUBTOCOL(sInfo.flags); if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) uSub = 0;
pData->uFocusItem = uItem; pData->uFocusSub = uSub;
if(uSub) { pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) pExtra->bFlags |= TVIX_FOCUSED; } else { pEntry->bFlags |= TVIX_FOCUSED; }
UpdateRect(pData, uItem, uSub);
goto End; } } }
if(wParam & MK_CONTROL) { // Ist die Ctrl-Taste gedr�ckt iMode = TVC_BYMOUSE; } else { iMode = TVC_BYMOUSE | TVC_DESELECT; }
uOldSub = pData->uSelectedSub; uOldItem = pData->uSelectedItem;
TreeListRemoveFocus(pData); TreeListSelectItem(pData, uItem, 0, iMode); TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); pEntry = pData->pTreeItems[uItem];
if(uMsg == WM_LBUTTONDBLCLK) { // Auto-Edit mit Doppelklick if(pData->aColumn[0].bFlags & TVAE_DBLCLICK && pData->aColumn[0].bEdit) { TreeListStartAutoEdit(pData, 0, VK_DBLCLK, lParam); } else if(TreeListStartNotifyEdit(pData, pData->uSelectedItem, 0, VK_DBLCLK, lParam)) {
} else if(pEntry && (pEntry->uState & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) { TreeListToggleItem(pData, uItem, 0); // Von + auf - umschalten } else { uToggle = 1; // Eintrag auflappen } } else if(uMsgOld == WM_LBUTTONDOWN) { if(pData->uStyleEx & TVS_EX_EDITCLICK) if(!(wParam & (MK_CONTROL | MK_SHIFT))) if(sInfo.flags & uMaskItem&~TVHT_ONITEMICON) if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) { pData->cClickEdit = 1; } } else if(uMsgOld == WM_LBUTTONUP) { if(pData->uStyleEx & TVS_EX_EDITCLICK) if(pData->cClickFlag && !pData->cClickEdit) if(!(wParam & (MK_CONTROL | MK_SHIFT))) if(sInfo.flags & uMaskItem&~TVHT_ONITEMICON) if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) { pData->cClickEdit = 1; }
if(pData->cClickEdit) { pData->cClickEdit = 0;
if(pData->aColumn[0].bEdit) { TreeListStartAutoEdit(pData, 0, VK_EDITCLK, lParam); } else { TreeListStartNotifyEdit(pData, pData->uSelectedItem, 0, VK_EDITCLK, lParam); } } } } else if(sInfo.flags & uMaskSub) { // Extra-Eintrag ausw�hlen if(pData->uStyleEx & TVS_EX_SUBSELECT) uSub = TVHT_SUBTOCOL(sInfo.flags); else uSub = 0;
if(!(pData->uStyle & TVS_DISABLEDRAGDROP)) { if(uMsg == WM_LBUTTONDOWN) { pData->uDragFlags = MK_LBUTTON; pData->uDragItem = uItem; pData->uDragSub = uSub; }
if(uMsg == WM_RBUTTONDOWN) { pData->uDragFlags = MK_RBUTTON; pData->uDragItem = uItem; pData->uDragSub = uSub; } }
if(wParam & MK_CONTROL) { if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Auswahl umschalten pEntry = pData->pTreeItems[uItem]; if(pEntry && (pEntry->uState & TVIS_SELECTED)) { if(uMsg != WM_LBUTTONDOWN) if(uMsg != WM_LBUTTONDBLCLK) goto End;
TreeListSelectItem(pData, 0, 0, TVC_BYMOUSE);
if(TreeListXorSelectItem(pData, uItem, TVC_BYMOUSE)) { // Auch unsichtbare Kinder abw�hlen pTemp = pData->pTreeItems[pEntry->uFirstChild]; if(pTemp && !pTemp->uShowPos) for(uTemp = uItem;;) { uTemp = TreeListNextSelUntil(pData, uTemp, uItem); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE); } }
TreeListRemoveFocus(pData);
pData->cClickEdit = 0; pData->uFocusItem = uItem; pData->uFocusSub = uSub;
if(uSub) { pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra) pExtra->bFlags |= TVIX_FOCUSED; } else { pEntry->bFlags |= TVIX_FOCUSED; }
UpdateRect(pData, uItem, uSub);
goto End; } }
iMode = TVC_BYMOUSE; } else { iMode = TVC_BYMOUSE | TVC_DESELECT; }
uOldSub = pData->uSelectedSub; uOldItem = pData->uSelectedItem;
TreeListRemoveFocus(pData); TreeListSelectItem(pData, uItem, uSub, (wParam & MK_CONTROL) ? TVC_BYMOUSE : TVC_BYMOUSE | TVC_DESELECT); TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); pEntry = pData->pTreeItems[uItem];
if(uMsg == WM_LBUTTONDBLCLK) { if(pData->aColumn[uSub].bEdit && // Auto-Edit mit Doppelklick ((pData->aColumn[uSub].bFlags & TVAE_DBLCLICK) || ((pData->aColumn[uSub].bFlags & TVAE_ICONCLICK) && (sInfo.flags & TVHT_ONSUBICON)))) { TreeListStartAutoEdit(pData, uSub, (sInfo.flags & TVHT_ONSUBICON) ? VK_ICONCLK : VK_DBLCLK, lParam); } else if(TreeListStartNotifyEdit(pData, uItem, uSub, VK_DBLCLK, lParam)) {
} else { uToggle = 1; // Eintrag auflappen } } else if(uMsg == WM_LBUTTONDOWN) { if(pData->aColumn[uSub].bEdit) // Auto-Edit mit Klick auf Icon if(pData->aColumn[uSub].bFlags & TVAE_ICONCLICK) if(sInfo.flags & TVHT_ONSUBICON) { TreeListStartAutoEdit(pData, uSub, VK_ICONCLK, lParam); }
if(pData->uStyleEx & TVS_EX_EDITCLICK) if(uSub && !(wParam & (MK_CONTROL | MK_SHIFT))) if(sInfo.flags & uMaskSub&~TVHT_ONSUBICON) if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) { pData->cClickEdit = 1; } } else if(uMsg == WM_LBUTTONUP) { if(pData->cClickEdit) { pData->cClickEdit = 0;
if(pData->aColumn[uSub].bEdit) { TreeListStartAutoEdit(pData, uSub, VK_EDITCLK, lParam); } else { TreeListStartNotifyEdit(pData, uItem, uSub, VK_EDITCLK, lParam); } } } } } else { pEntry = NULL; uSub = 0; }
End:
switch(uMsgOld) { case WM_LBUTTONUP: sNotify.hdr.code = TVN_LBUTTONUP; break; case WM_LBUTTONDOWN: sNotify.hdr.code = NM_CLICK; break; case WM_LBUTTONDBLCLK: sNotify.hdr.code = NM_DBLCLK; break; case WM_RBUTTONUP: sNotify.hdr.code = TVN_RBUTTONUP; break; case WM_RBUTTONDOWN: sNotify.hdr.code = NM_RCLICK; break; case WM_RBUTTONDBLCLK: sNotify.hdr.code = NM_RDBLCLK; break; default : UNLOCK(pData); return; }
if(pEntry) { sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.cChildren = TVHT_SUBTOCOL(sInfo.flags); } else { sNotify.itemNew.stateMask = 0; sNotify.itemNew.state = 0; sNotify.itemNew.lParam = 0; }
sNotify.action = 0; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = LOWORD(lParam); sNotify.ptDrag.y = HIWORD(lParam);
UNLOCK(pData);
if(!SendNotify(pData, &sNotify.hdr)) { if(uToggle) { // Aufklappen nur wenn Notify nicht abgefangen LOCK(pData); TreeListToggleItem(pData, uItem, 0); UNLOCK(pData); } }
}
//*****************************************************************************//*//* TreeListChar//*//*****************************************************************************// Eingabe von Buchstaben �ber die WM_CHAR Nachricht// pData : Zeiger auf die Fensterdaten// nChar : Ist das Zeichen das eingegeben wurdestatic void TreeListChar(TreeListData *pData, UINT nChar, LPARAM lParam) {
LPTSTR pName; ExtraItem *pExtra; BaseItem *pEntry; unsigned uDelta; unsigned uItem; unsigned uTick; unsigned uSub; unsigned uPos; unsigned uVal; int iNum; int iMax; int i;
if(nChar >= ' ') { if(pData->cKeyIgnore) return; // Taste soll ignoriert werden
iMax = pData->uItemPosCount; uSub = pData->uSelectedSub; i = 0;
if(TVIS_EDIT(pData->aColumn[uSub].bEdit)) // Bei AutoEdit keine Auswahl if(!(pData->aColumn[uSub].bFlags & TVAE_ONLYRETURN)) { TreeListStartAutoEdit(pData, uSub, nChar, 0); return; }
if(TreeListStartNotifyEdit(pData, pData->uSelectedItem, uSub, nChar | VK_ISACHAR, lParam)) { return; }
if(iMax <= 0) return;
iNum = pData->uSelectedItem; // Hole die Startzeile if(iNum > 0) { iNum = pData->pTreeItems[iNum]->uShowPos - 1; if(iNum < 0) iNum = 0; }
if((nChar >= 'a' && nChar <= 'z') || // In Grosbuchstaben umwandeln (nChar >= 224 && nChar <= 254)) { nChar -= 'a' - 'A'; }
if(!(pData->uStyleEx & TVS_EX_NOCHARSELCET)) for(;;) { // Suche Anfangsbuchstaben uTick = GetTickCount(); uDelta = (uKeyPos > 0) ? 750 : 500;
if(uKeyPos >= 3) uDelta = 1000; if(uTick - uKeyLast > uDelta) uKeyPos = 0; if(uKeyPos >= 16) uKeyPos = 0; if(uKeyPos == 1 && cKeyData[0] == (TCHAR)nChar) { uKeyPos = 0; }
cKeyData[uKeyPos] = (TCHAR)nChar; uKeyLast = uTick; uKeyPos += 1;
if(uKeyPos > 1) { iNum--; if(iNum < 0) iNum = iMax - 1; }
if(iMax <= 0) break;
for(i = iNum + 1; i != iNum; i++) { // Suche �bereinstimmung if(i >= iMax) {i = -1; continue;} uItem = pData->pItemPos[i];
if(uSub) {#ifndef __REACTOS__ pExtra = pExtra = pData->pExtraItems[uSub - 1][uItem];#else pExtra = pData->pExtraItems[uSub - 1][uItem];#endif pName = (pExtra && pExtra->pText) ? pExtra->pText : _T(""); } else { pEntry = pData->pTreeItems[uItem]; pName = (pEntry && pEntry->pText) ? pEntry->pText : _T(""); }
for(uPos = 0; uPos < uKeyPos; uPos++) { // Vergleiche die Texte#if UNICODE uVal = pName[uPos];#else uVal = ((unsigned char *)pName)[uPos];#endif
if((uVal >= 'a' && uVal <= 'z') || // In Grosbuchstaben umwandeln (uVal >= 224 && uVal <= 254)) { uVal -= 'a' - 'A'; }
if(cKeyData[uPos] != (TCHAR)uVal) { break; } }
if(uPos < uKeyPos) continue;
if(TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN | TVC_DESELECT)) { TreeListEnsureVisible(pData, uItem, uSub); }
return; }
if(i != iNum) break; if(uKeyPos <= 1) break;
iNum++; if(iNum >= iMax) iNum = iMax - 1;
uKeyPos = 0; } }
}
//*****************************************************************************//*//* TreeListKeyDown//*//*****************************************************************************// Soll ein Tastentruck ausgef�hrt werden. ACHTUNG UNLOCK wird ausgef�hrt// pData : Zeiger auf die Fensterdaten// wParam : WPARAM des Mausklicks// lParam : LPARAM des Mausklicks// Ergibt 0 wenn die Taste verarbeitet wurdestatic void TreeListKeyDown(TreeListData *pData, WPARAM wParam, LPARAM lParam) { BaseItem *pTemp; BaseItem *pEntry; TV_KEYDOWN_EX sNotify; unsigned uTemp; unsigned uItem; unsigned uStop; unsigned uVal; int iLineCmp; int iOldLine; int iOldCol; int iFocus; int iShift; int iBase; int iLine; int iAdd; int iPos; int iSub; int iCol; int iMax; int iDel; int iScr; int iSel;
if(!pData->cIsEnabled) { // Ist das Fenster freigegeben return; }
if(!pData->cHasFocus) { // Hat das Fenster den Focus if(GetFocus() != pData->hWnd) { UNLOCK(pData); SetFocus(pData->hWnd); LOCK(pData);
if(GetFocus() != pData->hWnd) { return; } } else { pData->cHasFocus = 1; } }
if(wParam == VK_RETURN) { // Wurde Enter gedr�ckt UNLOCK(pData);
sNotify.hdr.code = NM_RETURN; sNotify.wVKey = (WORD)(wParam); sNotify.wScan = (WORD)(wParam >> 16); sNotify.flags = (UINT)(lParam);
SendNotify(pData, &sNotify.hdr);
iSub = pData->uSelectedSub;
if(pData->aColumn[iSub].bEdit) { // Auto-Edit starten if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { wParam = VK_ICONCLK; lParam = 0; }
TreeListStartAutoEdit(pData, iSub, wParam, lParam); } else { TreeListStartNotifyEdit(pData, pData->uSelectedItem, iSub, wParam, lParam); }
return; }
pEntry = pData->pTreeItems[pData->uSelectedItem]; iDel = (GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 0 : TVC_DESELECT; iScr = GetAsyncKeyState(VK_CONTROL) & 0x8000;
if(iDel && iScr) // Ende oder Anfang w�hlen if(wParam == VK_HOME || wParam == VK_END) if(pData->uStyleEx & TVS_EX_HOMEENDSELECT) { iDel = TVC_DESELECT; iScr = 0; }
if(iDel && iScr) { // Das Fenster scrollen iLine = pData->uScrollY; iSub = pData->uScrollX;
switch(wParam) { case VK_END: iLine = pData->uTreeItemsCount; // Ans Ende scrollen iLine -= pData->uPageEnties; break;
case VK_HOME: iLine = 0; // Zum Anfang scrollen break;
case VK_LEFT: iSub -= 16; // Links scrollen break;
case VK_RIGHT: iSub += 16; // Rechts scrollen break;
case VK_UP: iLine--; // Nach oben scrollen break;
case VK_DOWN: iLine++; // Nach unten scrollen break;
case VK_PRIOR: iLine -= pData->uSizeX; // Eine Seite nach oben break;
case VK_NEXT: iLine += pData->uSizeX; // Eine Seite nach unten break;
case VK_SPACE: if(pEntry == NULL) break; // Expantieren und schlie�en if(pEntry->bFlags & TVIX_HASBUTTON) { TreeListToggleItem(pData, pData->uSelectedItem, 0); }
break;
default : goto Exit; }
if(iLine != (int)pData->uScrollY) { iMax = pData->uItemPosCount; iMax -= pData->uPageEnties - 1;
if(iLine >= iMax) iLine = iMax; if(iLine < 0) iLine = 0; if(iLine != (int)pData->uScrollY) if(!(pData->uStyle & TVS_NOSCROLL)) { pData->uScrollY = iLine; SetScrollPos(pData->hWnd, SB_VERT, iLine, TRUE); UpdateView(pData); } }
if(iSub != (int)pData->uScrollX) { uVal = pData->uColumnCount; if(uVal) iMax = pData->aColumnXpos[uVal] - pData->uSizeX / 2; else iMax = pData->iMaxSizeX; iMax -= pData->uSizeX - pData->uSizeX / 2;
if(iSub >= iMax) iSub = iMax; if(iSub < 0) iSub = 0; if(iSub != (int)pData->uScrollX) if(!(pData->uStyle & TVS_NOSCROLL)) { pData->uScrollX = iSub; SetScrollPos(pData->hWnd, SB_HORZ, iSub, TRUE); UpdateView(pData);
if(pData->hHeader) { MoveWindow(pData->hHeader, -iSub, 0, pData->uSizeX + iSub, pData->uStartPixel, TRUE); } } } } else { // Einen anderen Eintrag ausw�hlen iSub = pData->uSelectedSub; iCol = pData->aColumn[iSub].bIndex;
if(!pEntry) { iLine = 0; iCol = 0; iOldCol = 0; iOldLine = -1;
uTemp = pData->uFocusItem; if(uTemp) { // Ist ein Focus definiert pTemp = pData->pTreeItems[uTemp];
while(pTemp && !pTemp->uShowPos) { pTemp = pData->pTreeItems[pTemp->uParent]; }
if(pTemp) { iLine = pTemp->uShowPos - 1; iSub = pData->uFocusSub; iCol = pData->aColumn[iSub].bIndex; }
if(pData->uSelectedCount > 1) { iOldCol = iCol; iOldLine = iLine; } else { TreeListRemoveFocus(pData); } } } else { iLine = pEntry->uShowPos - 1; if(iLine < 0) iLine = 0;
uTemp = pData->uSelectedItem; iOldLine = iLine; iOldCol = iCol; }
switch(wParam) { case VK_END: iLine = pData->uItemPosCount - 1; break; case VK_HOME: iLine = 0; break; case VK_LEFT: if(pData->uColumnCount > 1 && (pData->uStyleEx & TVS_EX_SUBSELECT)) { while(iCol > 0) { iCol--; iSub = pData->aColumnPos[iCol]; if(pData->aColumn[iSub].sReal > 0) break; } } else { if(! pEntry) break; if(!(pEntry->uState & TVIS_EXPANDED) || !pEntry->uFirstChild) { pTemp = pData->pTreeItems[pEntry->uParent]; if(pTemp) iLine = pTemp->uShowPos - 1; break; }
if(pEntry->bFlags & TVIX_HASBUTTON) { TreeListToggleItem(pData, pData->uSelectedItem, 0); } }
break;
case VK_RIGHT: if(pData->uColumnCount > 1 && (pData->uStyleEx & TVS_EX_SUBSELECT)) { while(iCol + 1 < (int)pData->uColumnCount) { iCol++; iSub = pData->aColumnPos[iCol]; if(pData->aColumn[iSub].sReal > 0) break; } } else { if(!pEntry) break; if(pEntry->uState & TVIS_EXPANDED) { iLine++; break; }
if(pEntry->bFlags & TVIX_HASBUTTON) { TreeListToggleItem(pData, pData->uSelectedItem, 0); } }
break;
case VK_UP: iLine--; break; case VK_DOWN: iLine++; break;
case VK_PRIOR: iAdd = pData->uPageEnties - 1; // Eine Seite nach oben if(iAdd <= 0) iAdd = 1; iLine -= iAdd; break;
case VK_NEXT: iAdd = pData->uPageEnties - 1; // Eine Seite nach unten if(iAdd <= 0) iAdd = 1; iLine += iAdd; break;
case VK_BACK: // Eine Ebene h�her if(pEntry) { uItem = pEntry->uParent; if(!uItem) iLine = 0; else { iLine = pData->pTreeItems[uItem]->uShowPos - 1; if(iLine < 0) iLine = 0; } }
break;
case VK_SPACE: if(pEntry && iCol == 0 && (pData->uStyle & TVS_CHECKBOXES)) { TreeListChangeCheckbox(pData, pData->uSelectedItem, 0, 0); }
break;
default : goto Exit; }
if(iCol >= (int)pData->uColumnCount) iCol = pData->uColumnCount - 1; if(iCol < 0) iCol = 0; if(iLine >= (int)pData->uItemPosCount) iLine = pData->uItemPosCount - 1; if(iLine < 0) iLine = 0;
if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) iCol = 0;
if(pData->uItemPosCount > 0) if(iLine != iOldLine || iCol != iOldCol) { // Wurde ein anderer Eintrag ausgew�hlt if(pData->uSelectedCount > 1) { TreeListRemoveFocus(pData); } else { pData->uSelectedBase = uTemp; }
iShift = iDel;
if(pData->cReSelect) { // Die Shift-Auswahl neu erstellen iDel = TVC_DESELECT; }
uItem = pData->pItemPos [iLine]; pTemp = pData->pTreeItems[uItem]; iSub = pData->aColumnPos[iCol ]; iFocus = (pTemp && (pTemp->uState & TVIS_SELECTED)) ? TVC_ONLYFOCUS : 0;
TreeListSelectItem(pData, uItem, iSub, TVC_BYKEYBOARD | iDel | iFocus);
if(!(pData->uStyle & TVS_NOSCROLL)) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); }
if(pData->cReSelect && pData->uSelectedBase) { // Shift-Select neu ausw�hlen uTemp = pData->uSelectedBase; pTemp = pData->pTreeItems[uTemp]; uStop = uItem;
while(pTemp && pTemp->uShowPos == 0) { pTemp = pData->pTreeItems[pTemp->uParent]; if(!pTemp) break; }
if(pTemp && !iShift) { if(!(pTemp->uState & TVIS_SELECTED)) { TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); }
iLineCmp = pTemp->uShowPos - 1; if(iLineCmp < iLine) { uStop = uItem; } else { uStop = uTemp; uTemp = uItem; }
for(;;) { uTemp = TreeListNextUnselUntil(pData, uTemp, uStop); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); } }
pData->cReSelect = 0; }
if((pData->uStyleEx & TVS_EX_MULTISELECT) && !iDel) { uVal = pData->uSelectedBase; pTemp = pData->pTreeItems[uVal]; iBase = (pTemp) ? pTemp->uShowPos - 1 : -1;
if(iLine > iOldLine) { // Nach oben oder nach unten iMax = (iOldLine > iBase) ? iOldLine + 1 : iOldLine; if(iMax < 0) iMax = 0; iPos = iLine; } else { iMax = iLine; iPos = (iOldLine < iBase) ? iOldLine - 1 : iOldLine; if(iPos < 0) iPos = 0; }
for(; iPos >= iMax; iPos--) { // �bersprungene Eintr�ge mit aus/abw�hlen uItem = pData->pItemPos[iPos];
if(iPos != iLine && iPos != iBase) { if(!TreeListXorSelectItem(pData, uItem, TVC_BYKEYBOARD)) continue; }
pTemp = pData->pTreeItems[uItem]; // Auch unsichtbare Kinder abw�hlen if(pTemp) { iSel = pTemp->uState & TVIS_SELECTED; pTemp = pData->pTreeItems[pTemp->uFirstChild]; if(!pTemp || pTemp->uShowPos) continue; if(!iSel) { for(uTemp = uItem;;) { uTemp = TreeListNextSelUntil(pData, uTemp, uItem); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); } } else { for(uTemp = uItem;;) { uTemp = TreeListNextUnselUntil(pData, uTemp, uItem); if(!uTemp) break; TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD); } } } } } } }
Exit:
sNotify.hdr.code = TVN_KEYDOWN; sNotify.wVKey = (WORD)(wParam); sNotify.wScan = (WORD)(wParam >> 16); sNotify.flags = (UINT)(lParam);
UNLOCK(pData);
pData->cKeyIgnore = (char)SendNotify(pData, &sNotify.hdr);
}
//*****************************************************************************//*//* TreeListSortItemsEx//*//*****************************************************************************// Sortiert die Kindereintr�ge eines Eintrages mitteles einer Funktion// pData : Zeiger auf die Fensterdaten// pSortData : Ist ein Zeiger auf die Sortiertaten// iMode : 1=Rekursiv sortieren// Ergibt 1 wenn ok sonst 0static int TreeListSortItemsEx(TreeListData *pData, TV_SORTEX *pSortData, int iMode) {
TV_SORTEX sSort; unsigned uNum; unsigned uItem; unsigned uLast; unsigned uFirst; unsigned uParent; BaseItem *pParent; BaseItem *pEntry; BaseItem *pNext; BaseItem **pList;
unsigned *pItemList; unsigned *pItemNew; unsigned uEnties[128]; unsigned uPos; unsigned uMax;
PFNTVCOMPAREEX pCompare; HTREEITEM hItemTemp; LPARAM lParamTemp; LPARAM lParamSort; HWND hTreeWnd; int iLower, iUpper, iMiddle, iCmp; int uMemL[30], uMemU[30]; int iStart, iLast; int iLevel; unsigned uTemp;
pList = pData->pTreeItems;
uParent = U(pSortData->hParent); if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren if(uParent != U(TVI_ROOT)) return 0;
uLast = pData->uLastChild; uFirst = pData->uFirstChild; if(uFirst == 0) return 1; if(uFirst == uLast) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare; TreeListSortItemsEx(pData, &sSort, iMode); return 1; }
pParent = 0; uParent = 0; } else { // Untereintrag sortieren pParent = pList[uParent]; if(pParent == NULL) return 0;
uLast = pParent->uLastChild; uFirst = pParent->uFirstChild; if(uFirst == 0) return 1; if(uFirst == uLast) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare; TreeListSortItemsEx(pData, &sSort, iMode); return 1; } }
if(iMode) { // Sortiere die Untereintr�ge pNext = pList[uFirst]; sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare;
while(pNext) { if(pNext->uFirstChild) { TreeListSortItemsEx(pData, &sSort, SORT_NOUPDATE); }
sSort.hParent = (HTREEITEM)(ULONG_PTR)pNext->uNextItem; pNext = pList[pNext->uNextItem]; } } if(uFirst == uLast) return 1;
//******************** Erzeuge Eintragsliste ********************************** uItem = uFirst; pItemList = uEnties; uMax = 128; uPos = 0;
do { // Alle Kindeintr�ge suchen if(uPos >= uMax) { uMax *= 2; pItemNew = new(unsigned, uMax); memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0])); if(uPos > 128) delete(pItemList); pItemList = pItemNew; }
pItemList[uPos] = uItem; pNext = pList[uItem]; uItem = pNext->uNextItem; uPos++; } while(uItem);
//************************* Qsort-Algorithmus *********************************#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
pData->cLockChanges = 1; UNLOCK(pData);
hTreeWnd = pData->hWnd; pCompare = pSortData->lpfnCompare; lParamSort = pSortData->lParam; iLast = uPos - 1; iStart = 0; iLevel = 0;
for(;;) { iLower = iStart; iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen iUpper = iLast + 1;
XCHANGE_MEM(iMiddle, iLower);
uItem = pItemList[iStart]; hItemTemp = (HTREEITEM)(ULONG_PTR)uItem; lParamTemp = pList[uItem]->lParam;
for(;;) { do { iLower++; if(iLower > iLast) break; uItem = pItemList[iLower]; iCmp = pCompare(hTreeWnd, (HTREEITEM)(ULONG_PTR)uItem, hItemTemp, pList[uItem]->lParam, lParamTemp, lParamSort); } while(iCmp <= 0);
do { iUpper--; if(iUpper <= iStart) break; uItem = pItemList[iUpper]; iCmp = pCompare(hTreeWnd, (HTREEITEM)(ULONG_PTR)uItem, hItemTemp, pList[uItem]->lParam, lParamTemp, lParamSort); } while(iCmp >= 0);
if(iUpper < iLower) break;
XCHANGE_MEM(iUpper, iLower); }
XCHANGE_MEM(iStart, iUpper);
if(iUpper - 1 - iStart >= iLast - iLower) { if(iStart + 1 < iUpper) { uMemL[iLevel] = iStart; uMemU[iLevel] = iUpper - 1; iLevel++; } if(iLower < iLast) { iStart = iLower; continue; } } else { if(iLower < iLast) { uMemL[iLevel] = iLower; uMemU[iLevel] = iLast; iLevel++; }
if(iStart + 1 < iUpper) { iLast = iUpper - 1; continue; } } // Eine Ebene absteigen iLevel--;
if(iLevel >= 0) { // Noch Ebenen vorhanden iStart = uMemL[iLevel]; iLast = uMemU[iLevel]; continue; }
break; }
LOCK(pData); pData->cLockChanges = 0;
//******************** Eintr�ge neu einsortirenen ***************************** uPos--;
pEntry = pList[uParent]; if(!pEntry) { pData->uFirstChild = pItemList[ 0 ]; pData->uLastChild = pItemList[uPos]; } else { pEntry->uFirstChild = pItemList[ 0 ]; pEntry->uLastChild = pItemList[uPos]; }
uLast = 0; uItem = pItemList[0];
for(uNum = 0; uNum < uPos;) { // Kinder neu einh�ngen pEntry = pList[uItem]; pEntry->uPrevItem = uLast;
uNum++; uLast = uItem; uItem = pItemList[uNum];
pEntry->uNextItem = uItem; }
pEntry = pList[uItem]; pEntry->uPrevItem = uLast; pEntry->uNextItem = 0;
if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) { UpdateItems(pData, uParent);
if(pData->uStyle & TVS_SHOWSELALWAYS) if(pData->uSelectedItem) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); } }
if(uMax > 128) delete(pItemList);
return 1;}
//*****************************************************************************//*//* TreeListSortItemsCb//*//*****************************************************************************// Sortiert die Kindereintr�ge eines Eintrages mitteles einer Funktion// pData : Zeiger auf die Fensterdaten// pSortData : Ist ein Zeiger auf die Sortiertaten// iMode : 1=Rekursiv sortieren// Ergibt 1 wenn ok sonst 0static int TreeListSortItemsCb(TreeListData *pData, TV_SORTCB *pSortData, int iMode) {
TV_SORTCB sSort; unsigned uNum; unsigned uItem; unsigned uLast; unsigned uFirst; unsigned uParent; BaseItem *pParent; BaseItem *pEntry; BaseItem *pNext; BaseItem **pList;
unsigned *pItemList; unsigned *pItemNew; unsigned uEnties[128]; unsigned uPos; unsigned uMax;
PFNTVCOMPARE pCompare; LPARAM lParamTemp; LPARAM lParamSort; int iLower, iUpper, iMiddle, iCmp; int uMemL[30], uMemU[30]; int iStart, iLast; int iLevel; unsigned uTemp;
pList = pData->pTreeItems;
uParent = U(pSortData->hParent); if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren if(uParent != U(TVI_ROOT)) return 0;
uLast = pData->uLastChild; uFirst = pData->uFirstChild; if(uFirst == 0) return 1; if(uFirst == uLast) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare; TreeListSortItemsCb(pData, &sSort, iMode); return 1; }
pParent = 0; uParent = 0; } else { // Untereintrag sortieren pParent = pList[uParent]; if(pParent == NULL) return 0;
uLast = pData->uLastChild; uFirst = pParent->uFirstChild; if(uFirst == 0) return 1; if(uFirst == uLast) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare; TreeListSortItemsCb(pData, &sSort, iMode); return 1; } }
if(iMode) { // Sortiere die Untereintr�ge pNext = pList[uFirst]; sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst; sSort.lParam = pSortData->lParam; sSort.lpfnCompare = pSortData->lpfnCompare;
while(pNext) { if(pNext->uFirstChild) { TreeListSortItemsCb(pData, &sSort, SORT_NOUPDATE); }
sSort.hParent = (HTREEITEM)(ULONG_PTR)pNext->uNextItem; pNext = pList[pNext->uNextItem]; } }
if(uFirst == uLast) return 1;
//******************** Erzeuge Eintragsliste ********************************** uItem = uFirst; pItemList = uEnties; uMax = 128; uPos = 0;
do { // Alle Kindeintr�ge suchen if(uPos >= uMax) { uMax *= 2; pItemNew = new(unsigned, uMax); memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0])); if(uPos > 128) delete(pItemList); pItemList = pItemNew; }
pItemList[uPos] = uItem; pNext = pList[uItem]; uItem = pNext->uNextItem; uPos++; } while(uItem);
//************************* Qsort-Algorithmus *********************************#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
pData->cLockChanges = 1; UNLOCK(pData);
pCompare = pSortData->lpfnCompare; lParamSort = pSortData->lParam; iLast = uPos - 1; iStart = 0; iLevel = 0;
for(;;) { iLower = iStart; iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen iUpper = iLast + 1;
XCHANGE_MEM(iMiddle, iLower);
uItem = pItemList[iStart]; lParamTemp = pList[uItem]->lParam;
for(;;) { do { iLower++; if(iLower > iLast) break; uItem = pItemList[iLower]; iCmp = pCompare(pList[uItem]->lParam, lParamTemp, lParamSort); } while(iCmp <= 0);
do { iUpper--; if(iUpper <= iStart) break; uItem = pItemList[iUpper]; iCmp = pCompare(pList[uItem]->lParam, lParamTemp, lParamSort); } while(iCmp >= 0);
if(iUpper < iLower) break;
XCHANGE_MEM(iUpper, iLower); }
XCHANGE_MEM(iStart, iUpper);
if(iUpper - 1 - iStart >= iLast - iLower) { if(iStart + 1 < iUpper) { uMemL[iLevel] = iStart; uMemU[iLevel] = iUpper - 1; iLevel++; } if(iLower < iLast) { iStart = iLower; continue; } } else { if(iLower < iLast) { uMemL[iLevel] = iLower; uMemU[iLevel] = iLast; iLevel++; }
if(iStart + 1 < iUpper) { iLast = iUpper - 1; continue; } } // Eine Ebene absteigen iLevel--;
if(iLevel >= 0) { // Noch Ebenen vorhanden iStart = uMemL[iLevel]; iLast = uMemU[iLevel]; continue; }
break; }
LOCK(pData); pData->cLockChanges = 0;
//******************** Eintr�ge neu einsortirenen ***************************** uPos--;
pEntry = pList[uParent]; if(!pEntry) { pData->uFirstChild = pItemList[ 0 ]; pData->uLastChild = pItemList[uPos]; } else { pEntry->uFirstChild = pItemList[ 0 ]; pEntry->uLastChild = pItemList[uPos]; }
uLast = 0; uItem = pItemList[0];
for(uNum = 0; uNum < uPos;) { // Kinder neu einh�ngen pEntry = pList[uItem]; pEntry->uPrevItem = uLast;
uNum++; uLast = uItem; uItem = pItemList[uNum];
pEntry->uNextItem = uItem; }
pEntry = pList[uItem]; pEntry->uPrevItem = uLast; pEntry->uNextItem = 0;
if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) { UpdateItems(pData, uParent);
if(pData->uStyle & TVS_SHOWSELALWAYS) if(pData->uSelectedItem) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); } }
if(uMax > 128) delete(pItemList);
return 1;}
//*****************************************************************************//*//* TreeListSortItems//*//*****************************************************************************// Sortiert die Kindereintr�ge eines Eintrages via Text// pData : Zeiger auf die Fensterdaten// pSortData : Ist ein Zeiger auf die Sortiertaten// iMode : 1=Rekursiv sortieren// Ergibt 1 wenn ok sonst 0static int TreeListSortItems(TreeListData *pData, unsigned uParent, int iMode) {
unsigned uNum; unsigned uItem; unsigned uLast; unsigned uFirst; BaseItem *pParent; BaseItem *pEntry; BaseItem *pNext; BaseItem **pList;
unsigned *pItemList; unsigned *pItemNew; unsigned uEnties[128]; unsigned uPos; unsigned uMax;
LPCTSTR pTextTemp; LPCTSTR pText; int iLower, iUpper, iMiddle, iCmp; int uMemL[30], uMemU[30]; int iStart, iLast; int iLevel; int iNone; unsigned uSize; unsigned uTemp;
pList = pData->pTreeItems;
if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren if(uParent != U(TVI_ROOT)) return 0;
uLast = pData->uLastChild; uFirst = pData->uFirstChild; if(uFirst == 0) return 1; if(uFirst == pData->uLastChild) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
TreeListSortItems(pData, uFirst, iMode); return 1; }
pList = pData->pTreeItems; pParent = 0; uParent = 0; } else { // Untereintrag sortieren pParent = pList[uParent]; if(pParent == NULL) return 0;
uLast = pParent->uLastChild; uFirst = pParent->uFirstChild; if(uFirst == 0) return 1; if(uFirst == pParent->uLastChild) { // Einzelner Eintrag pNext = pList[uFirst]; if(!pNext->uFirstChild) return 1;
TreeListSortItems(pData, uFirst, iMode); return 1; } }
if(iMode) { // Sortiere die Untereintr�ge uItem = uFirst;
while(uItem) { pNext = pList[uItem]; if(pNext->uFirstChild) { TreeListSortItems(pData, uItem, SORT_NOUPDATE); }
uItem = pNext->uNextItem; } }
if(uLast == uFirst) return 1;
//******************** Erzeuge Eintragsliste ********************************** uItem = uFirst; pItemList = uEnties; uMax = 128; uPos = 0;
do { // Alle Kindeintr�ge suchen if(uPos >= uMax) { uMax *= 2; pItemNew = new(unsigned, uMax); memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0])); if(uPos > 128) delete(pItemList); pItemList = pItemNew; }
pItemList[uPos] = uItem; pNext = pList[uItem]; uItem = pNext->uNextItem; uPos++; } while(uItem);
//************************* Qsort-Algorithmus *********************************#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
pData->cLockChanges = 1; UNLOCK(pData);
iLast = uPos - 1; iStart = 0; iLevel = 0;
for(;;) { iLower = iStart; iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen iUpper = iLast + 1;
XCHANGE_MEM(iMiddle, iLower);
uItem = pItemList[iStart]; pEntry = pList[uItem]; if(pEntry->bCallback & TVIF_TEXT) { uSize = 0; LOCK(pData); CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp); UNLOCK(pData); } else { pTextTemp = pEntry->pText; }
for(;;) { do { iLower++; if(iLower > iLast) break;
uItem = pItemList[iLower]; pEntry = pList[uItem]; if(pEntry->bCallback & TVIF_TEXT) { uSize = 1; LOCK(pData); CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pText); UNLOCK(pData); } else { pText = pEntry->pText; }
iCmp = str_icmp(pText, pTextTemp); } while(iCmp <= 0);
do { iUpper--;
if(iUpper <= iStart) break; uItem = pItemList[iUpper]; pEntry = pList[uItem]; if(pEntry->bCallback & TVIF_TEXT) { LOCK(pData); CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pText); UNLOCK(pData); } else { pText = pEntry->pText; }
iCmp = str_icmp(pText, pTextTemp); } while(iCmp >= 0);
if(iUpper < iLower) break;
XCHANGE_MEM(iUpper, iLower); }
XCHANGE_MEM(iStart, iUpper);
if(iUpper - 1 - iStart >= iLast - iLower) { if(iStart + 1 < iUpper) { uMemL[iLevel] = iStart; uMemU[iLevel] = iUpper - 1; iLevel++; } if(iLower < iLast) { iStart = iLower; continue; } } else { if(iLower < iLast) { uMemL[iLevel] = iLower; uMemU[iLevel] = iLast; iLevel++; }
if(iStart + 1 < iUpper) { iLast = iUpper - 1; continue; } } // Eine Ebene absteigen iLevel--;
if(iLevel >= 0) { // Noch Ebenen vorhanden iStart = uMemL[iLevel]; iLast = uMemU[iLevel]; continue; }
break; }
LOCK(pData); pData->cLockChanges = 0;
//******************** Eintr�ge neu einsortirenen ***************************** uPos--;
pEntry = pList[uParent]; if(!pEntry) { pData->uFirstChild = pItemList[ 0 ]; pData->uLastChild = pItemList[uPos]; } else { pEntry->uFirstChild = pItemList[ 0 ]; pEntry->uLastChild = pItemList[uPos]; }
uLast = 0; uItem = pItemList[0];
for(uNum = 0; uNum < uPos;) { // Kinder neu einh�ngen pEntry = pList[uItem]; pEntry->uPrevItem = uLast;
uNum++; uLast = uItem; uItem = pItemList[uNum];
pEntry->uNextItem = uItem; }
pEntry = pList[uItem]; pEntry->uPrevItem = uLast; pEntry->uNextItem = 0;
if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) { UpdateItems(pData, uParent);
if(pData->uStyle & TVS_SHOWSELALWAYS) if(pData->uSelectedItem) { TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub); } }
if(uMax > 128) delete(pItemList); return 1;}
//*****************************************************************************//*//* TreeListEndLabelEdit//*//*****************************************************************************// Beendet das editiert eines Eintrages// pData : Zeiger auf Fensterdaten// iMode : Gibt an wie das Editieren beendet wurde// 0 = Es gab es einen Abbruch mit ESC// 1 = Eingabe ohne Enter// 2 = Eingabe mit Enter// Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehlerstatic int TreeListEndLabelEdit(TreeListData *pData, int iMode) { TCHAR cText[2052]; NMTVDISPINFO sNotify; TV_ITEM sSet; LRESULT lRet; unsigned uSub; unsigned uItem; ExtraItem *pExtra; BaseItem *pEntry; LPCTSTR *pList; LPCTSTR pText; LPTSTR pGetT; TCHAR cChar; int iAuto; int iIcon; int iLine; int iPos; int iLen; int iMax; int iSel; char cCb;
uItem = pData->uEditItem; uSub = pData->uEditSub; cCb = pData->cEditCb;
pData->uEditItem = 0; pData->uEditSub = 0; pData->cEditCb = 0;
if(uItem > pData->uTreeItemsMax || uSub >= pData->uColumnCount) { return 0; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) { return 0; }
if(iMode) { // Eingabe GetWindowText(pData->hEdit, cText, sizeof(cText) / sizeof(cText[0])); cText[sizeof(cText) / sizeof(cText[0]) - 1] = 0; sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM; sNotify.item.cchTextMax = sizeof(cText) / sizeof(cText[0]) - 1; sNotify.item.pszText = cText;
if(pData->cColumnStart) { // Wurde ein Text eingegeben sNotify.item.mask |= TVIF_TEXTCHANGED; }
if(iMode == 2) { // Wurde der Text mit RETURN eingegeben sNotify.item.mask |= TVIF_RETURNEXIT; } } else { // Abbruch sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_CANCELED | TVIF_SUBITEM; sNotify.item.pszText = NULL; sNotify.item.cchTextMax = 0; }
sNotify.hdr.code = TVN_ENDLABELEDIT; sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.item.stateMask = 0xFFFFFFFF; sNotify.item.cChildren = uSub;
if(uSub) { // Wurde der Text in einer Sub-Spalte ge�ndert pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) { sNotify.item.state = 0; sNotify.item.lParam = 0; } else { sNotify.item.state = pEntry->uState & TVIS_BASEFLAGS; sNotify.item.state |= pExtra->uState; sNotify.item.lParam = pEntry->lParam; } } else { sNotify.item.state = pEntry->uState; sNotify.item.lParam = pEntry->lParam; }
UNLOCK(pData); ShowWindow(pData->hEdit, SW_HIDE); lRet = SendNotify(pData, &sNotify.hdr); LOCK(pData);
if(lRet || !iMode) return 0;
if(cCb) { // Callback aufrufen sNotify.hdr.code = TVN_SETDISPINFO; sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM; sNotify.item.stateMask = (UINT)~TVIS_BASEFLAGS; sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.item.cChildren = uSub;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); } else { // Neuen Text eingeben pGetT = sNotify.item.pszText; sSet.mask = TVIF_SUBITEM | TVIF_TEXT; sSet.cchTextMax = sNotify.item.cchTextMax; sSet.hItem = (HTREEITEM)(ULONG_PTR)uItem; sSet.pszText = pGetT; sSet.cChildren = uSub;
iIcon = pData->aColumn[uSub].iCbIcon; iAuto = pData->aColumn[uSub].bEdit;
if(iIcon >= 0 && iAuto != TVAX_NONE) { // Auch ein Icon zuweisen iPos = -1;
if((1 << iAuto) & ((1 << TVAX_CBLIST) | (1 << TVAX_COMBO))) { iPos = (int)SendMessage(pData->hEdit, CB_GETCURSEL, 0, 0); sSet.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; sSet.iImage = iIcon + iPos; sSet.iSelectedImage = sSet.iImage; }
if(iPos <= -1) { iMax = pData->aColumn[uSub].bCbSize; if(iMax <= 0) iMax = 1024;
iSel = -1;
if(pData->aColumn[uSub].bFlags & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL}; pList = (LPCTSTR *)pData->aColumn[uSub].pCbData;
for(iPos = 0; iPos < iMax; iPos++) { if(!pList[iPos]) break; if(!str_cmp(pGetT, pList[iPos])) iSel = iPos; } } else { // Textliste char *pText="1|2|3"; pText = (LPTSTR)pData->aColumn[uSub].pCbData; cChar = (TCHAR)pData->aColumn[uSub].bCbChar;
for(iPos = 0; iPos < iMax; iPos++) { for(iLen = 0; pText[iLen]; iLen++) { if(pText[iLen] == cChar) break; }
if(str_ncmp(pGetT, pText, iLen) == 0 && !pGetT[iLen]) { iSel = iPos; break; }
pText += iLen; if(pText[0] == cChar) pText++; if(pText[0] == 0) break; } }
sSet.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; sSet.iImage = iIcon + iSel; sSet.iSelectedImage = sSet.iImage; } }
if(pData->aColumn[uSub].bFlags & TVAE_NEXTLINE && // In die n�chste Zeile springen iMode == 2 && iAuto != TVAX_NONE && iAuto != TVAX_STEP) { if(!pData->cColumnStart) { if(uSub) { // Hat sich der Text ver�ndert ? pExtra = pData->pExtraItems[uSub - 1][uItem]; if(pExtra && pExtra->pText) { if(!_tcscmp(pGetT, pExtra->pText)) return 1; } else { if(!*pGetT) return 1; } } else { pEntry = pData->pTreeItems[uItem]; if(pEntry && pEntry->pText) { if(!_tcscmp(pGetT, pEntry->pText)) return 1; } else { if(!*pGetT) return 1; } } }
TreeListSetItem(pData, &sSet);
iLine = pEntry->uShowPos; if(iLine < (int)pData->uItemPosCount) { uItem = pData->pItemPos[iLine]; TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_BYKEYBOARD | TVC_DESELECT); } } else { TreeListSetItem(pData, &sSet); } } return 1;}
//*****************************************************************************//*//* TreeListEditLabel//*//*****************************************************************************// Startet das editiert eines Eintrages// pData : Zeiger auf Fensterdaten// uItem : Item das editiert werden soll// uSub : Spalte die editiert werden soll und andere Flags// TVIR_EDITCOL(n) = Spalte angeben// TVIR_SELAREA(a,b) = Einen Textbereich ausw�hlen// TVIR_SETCURSOR(n) = Den Cursor auf eine bestimmte Textstelle// TVIR_SETAT(n) = Den Cursor auf eine bestimmte Pixelstelle// TVIR_SELALL = Den gesammten Text w�hlen// TVIR_EDITCOMBOLIST = Statt dem Edit-Fenster eine ComboBox nur mit Listenauswahl einblenden// TVIR_EDITFULL = Das Edit-Fenster �ber die volle Breite einblenden// TVIR_EDITCOMBOBOX = Statt dem Edit-Fenster eine ComboBox einblenden// Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehlerstatic HWND TreeListEditLabel(TreeListData *pData, unsigned uItem, unsigned uSub) {
HDC hDc; HWND hWnd; LRESULT lRet; WNDPROC pProc; char cTemp; LPARAM lParam; ExtraItem *pExtra; BaseItem *pEntry; NMTVDISPINFO sNotify; LPCTSTR pText; RECT sRect; SIZE sSize; HFONT hFont; unsigned uCol; unsigned uSel; unsigned uNext; unsigned uBits; unsigned uSize; unsigned uStart; unsigned uState; unsigned uFlags; unsigned uHeight; int iPixels; int iWidth; int iTemp;
uBits = uSub >> 29; uSel = (uSub >> 8) & 0x0FFFFF; uSub &= 0xFF;
if(uSub >= pData->uColumnCount) return NULL; if(uItem > pData->uTreeItemsMax) return NULL; pEntry = pData->pTreeItems[uItem]; if(!pEntry) return NULL;
if(uItem != pData->uSelectedItem || uSub != pData->uSelectedSub) { uCol = (pData->uStyleEx & TVS_EX_SUBSELECT) ? uSub : 0; iTemp = TreeListSelectItem(pData, uItem, uCol, TVC_UNKNOWN); }
TreeListEnsureVisible(pData, uItem, uSub);
if(pData->hEdit) { // Editfenster l�schen DestroyWindow(pData->hEdit); pData->hEdit = 0; }
switch(uBits & 3) { // Editfenster neu erzeugen case 1: pData->hEdit = CreateWindow(_T("COMBOBOX"), NULL, WS_BORDER | WS_CHILD | CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VSCROLL, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL); pData->uEditMode = 1; SendMessage(pData->hEdit, CB_LIMITTEXT, 2048, 0); break;
case 2: pData->hEdit = CreateWindow(_T("COMBOBOX"), NULL, WS_BORDER | WS_CHILD | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | WS_VSCROLL, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL); pData->uEditMode = 2; SendMessage(pData->hEdit, CB_LIMITTEXT, 2048, 0); break;
default : uFlags = ES_LEFT;
if(uBits & 4) { if(pData->aColumn[uSub].bAlign == DT_RIGHT) uFlags = ES_RIGHT; if(pData->aColumn[uSub].bAlign == DT_CENTER) uFlags = ES_CENTER; }
pData->hEdit = CreateWindow(_T("EDIT"), NULL, WS_BORDER | WS_CHILD | ES_AUTOHSCROLL | uFlags, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL); pData->uEditMode = 0; SendMessage(pData->hEdit, EM_SETLIMITTEXT, 2048, 0); break; } if(!pData->hEdit) return NULL;
if(pSetWindowTheme) { // Remove the Visual-Styles (XP+) pSetWindowTheme(pData->hEdit, L"", L""); }
pData->pProcId3 = (WNDPROC)GetWindowLongPtr(pData->hEdit, GWLP_WNDPROC); SetWindowLongPtr(pData->hEdit, GWLP_USERDATA, (LPARAM)pData); SetWindowLongPtr(pData->hEdit, GWLP_WNDPROC , (LPARAM)EditProc);
hWnd = GetWindow(pData->hEdit, GW_CHILD);
while(hWnd) { pProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)pProc); SetWindowLongPtr(hWnd, GWLP_WNDPROC , (LPARAM)EditProc); hWnd = GetNextWindow(hWnd, GW_HWNDNEXT); }
pData->cEditCb = 0;
if(pData->uEditMode >= 1) { // ComboBox leeren SendMessage(pData->hEdit, CB_RESETCONTENT, 0, 0); }
if(uSub == 0) { // Haupteintrag bearbeiten TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
pText = pEntry->pText; uSize = pEntry->uTextSize; iPixels = pEntry->iTextPixels + 10; lParam = pEntry->lParam; uState = pEntry->uState; hFont = (uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
if(pEntry->bCallback & TVIF_TEXT) { CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText); hDc = GetDC(pData->hWnd); SelectObject(hDc, hFont); DrawText(hDc, pText, uSize, &sRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); ReleaseDC(pData->hWnd, hDc); iPixels = sRect.right - sRect.left + 10; pData->cEditCb = 1; }
if(uBits & 4) { // Volle Spaltenbreite if(pEntry->iImage != TV_NOIMAGE) { uNext = pData->aColumnPos[1]; sRect.right = pData->aColumnXpos[uNext]; sRect.right -= pData->uScrollX; }
iPixels = sRect.right - sRect.left - 2; } else { if(pData->uEditMode) { if(iPixels < 60) iPixels = 60; } else { if(iPixels < 48) iPixels = 48; }
if(pText && *pText) { iPixels += str_len(pText); }
if(pData->uEditMode) { iPixels += GetSystemMetrics(SM_CXHSCROLL); } } } else { // Extraeintrag bearbeiten if(uBits & 4) { TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_COLTOSUB(uSub), &sRect);
if(pData->aColumn[uSub].bEdit >= TVAX_CHECK) { sRect.left += pData->iChecksXsize; if(sRect.right < sRect.left) sRect.right = sRect.left + 1; } } else { TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uSub), &sRect); }
pExtra = pData->pExtraItems[uSub - 1][uItem]; if(!pExtra) { pData->cTempText1[0] = 0; pText = pData->cTempText1; uSize = sizeof(pData->cTempText1) / sizeof(pData->cTempText1[0]); iPixels = sRect.right - sRect.left + 10; hFont = pData->hFontN; uState = pEntry->uState & TVIS_BASEFLAGS; lParam = 0; } else { pText = pExtra->pText; uSize = pExtra->uTextSize; iPixels = pExtra->iTextPixels + 10; lParam = pEntry->lParam; uState = pExtra->uState; uState |= pEntry->uState & TVIS_BASEFLAGS; hFont = (uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
if(pExtra->bCallback & TVIF_TEXT) { CallbackExtra(pData, pEntry, pExtra, uItem, uSub, TVIF_TEXT, &iTemp, &uSize, &pText); hDc = GetDC(pData->hWnd); SelectObject(hDc, hFont); DrawText(hDc, pText, uSize, &sRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); ReleaseDC(pData->hWnd, hDc); iPixels = sRect.right - sRect.left; pData->cEditCb = 1; } }
if(uBits & 4) { // Volle Spaltenbreite if(pExtra && pExtra->iImage != TV_NOIMAGE) { sRect.left += pData->iImagesXsize + 1; }
iPixels = sRect.right - sRect.left - 2; } else { if(pData->uEditMode) { if(iPixels < 60) iPixels = 60; } else { if(iPixels < 48) iPixels = 48; }
if(pText && *pText) { iPixels += str_len(pText); }
if(pData->uEditMode) { iPixels += GetSystemMetrics(SM_CXHSCROLL); }
switch(pData->aColumn[uSub].bAlign) { case DT_RIGHT: iWidth = sRect.right - sRect.left; sRect.left += iWidth - iPixels; break;
case DT_CENTER: iWidth = sRect.right - sRect.left; sRect.left += (iWidth - iPixels) / 2; break; } } }
UNLOCK(pData);
sNotify.hdr.code = TVN_BEGINLABELEDIT; sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM; sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.item.pszText = (LPTSTR)pText; sNotify.item.lParam = lParam; sNotify.item.state = uState; sNotify.item.cchTextMax = uSize; sNotify.item.stateMask = 0xFFFFFFFF; sNotify.item.cChildren = uSub;
lRet = SendNotify(pData, &sNotify.hdr);
LOCK(pData);
if(lRet) { // Das Editieren abbrechen TreeListEndLabelEdit(pData, 0); return NULL; }
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return NULL;
if(pData->uToolTipItem) { // Ein offenes Tooltip verstecken UpdateToolTip(pData, 0, 0); } UNLOCK(pData); SetFocus(pData->hEdit); LOCK(pData);
if(pData->uEditMode) { sRect.top--; uHeight = 260; } else { uHeight = pData->iFontHeight + 4; }
if(pData->uEditMode) { if(iPixels < 60) iPixels = 60; } else { if(iPixels < 48) iPixels = 48; }
cTemp = pData->cColumnStart; SetWindowPos(pData->hEdit, HWND_TOP, sRect.left + 2, sRect.top + 1, iPixels, uHeight, SWP_SHOWWINDOW); SendMessage(pData->hEdit, WM_SETFONT, (WPARAM)hFont, 0); SetWindowText(pData->hEdit, pText); pData->cColumnStart = cTemp;
switch(uSel >> 18) { // Welche Textauswahl case 3: uStart = (uSel) & 0x01FF; // Einen Textbereich markieren uSize = (uSel >> 9) & 0x01FF; break;
case 2: uStart = uSel & 0x3FFFF; // Cursor auf eine bestimmte Stelle uSize = uStart; break;
case 1: uSel &= 0x3FFFF; if(uSel > 4) uSel -= 4; hDc = GetDC(pData->hEdit); SelectObject(hDc, hFont); GetTextExtentExPoint(hDc, pText, uSize, uSel, &iWidth, NULL, &sSize);
if(uSize > 0 && iWidth < (int)uSize - 1) { // Halben Buchstaben addieren GetTextExtentExPoint(hDc, pText + iWidth, 1, uSel, NULL, NULL, &sSize); uSel += sSize.cx / 2; GetTextExtentExPoint(hDc, pText, uSize, uSel, &iWidth, NULL, &sSize); }
ReleaseDC(pData->hEdit, hDc);
if(sSize.cx <= (int)uSel) { uStart = 0; break; }
uStart = iWidth; uSize = iWidth; break;
default : uStart = 0; // Alles markieren break; }
switch(pData->uEditMode) { case 0: SendMessage(pData->hEdit, EM_SETSEL, uStart, uSize); break; case 1: SendMessage(pData->hEdit, CB_SETEDITSEL, 0, MAKELPARAM(uStart, uSize)); break; default : uStart = 0; uSize = 0xFFFF; break; }
RedrawWindow(pData->hEdit, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
pData->uLastSel = MAKELPARAM(uStart, uSize); pData->uEditItem = uItem; pData->uEditSub = uSub; return pData->hEdit;}
//*****************************************************************************//*//* TreeListStartAutoEdit//*//*****************************************************************************// Startet die Editierung f�r einen Wert via Notyfy-R�ckfrage.// pData : Zeiger auf die Fensterdaten// uItem : Ist der Eintrag der Editiert werden soll// uSub : Ist die Nummer der Spalte// wParam : Ist der W-Parameter des Tastendrucks// VK_EDITCLK bei einem Clickauf das ausgew�hlte Feld// VK_DBLCLK bei einem Doppelclick// VK_RETURN bei einen Enter-Druck// VK_ISACHAR bei WM_CHAR Nachrichten// <char> bei einer Zeicheneingabe// lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)// Ergibt 1 das Editieren gestartet wurde, ansonsten 0// 0 wenn der Eintrag nicht gew�hlt wurdestatic int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam) {
TCHAR cText[1024]; TV_STARTEDIT sNotify; ExtraItem *pExtra; BaseItem *pEntry; unsigned uBits; unsigned uCnt; unsigned uMax; unsigned uLen; unsigned uNum; LPCTSTR pText; RECT sRect; TCHAR cChar; LRESULT lRet; MSG sMsg; HWND hWnd; INT iSel;
if(!(pData->uStyle & TVS_EDITLABELS)) return 0; if(uItem == 0 || uItem > pData->uTreeItemsMax) return 0; if(uSub > 0 && uSub >= pData->uColumnCount) return 0;
pEntry = pData->pTreeItems[uItem]; if(!pEntry) return 0;
if(wParam < ' ' && wParam != VK_RETURN) { // Falsche Taste return 0; }
if(wParam >= ' ' && wParam <= 0xFFFF) { // Shift und Cltr pr�fen if(GetKeyState(VK_MENU) & 0x8000) { return 0; }
if(GetKeyState(VK_CONTROL) & 0x8000) { return 0; } }
sNotify.hdr.code = TVN_STARTEDIT; sNotify.uAction = (UINT)wParam; sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM; sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem; sNotify.item.stateMask = 0xFFFFFFFF; sNotify.item.lParam = pEntry->lParam; sNotify.item.cChildren = uSub; sNotify.uHeight = 0; sNotify.pTextEntries = 0; sNotify.pTextList = 0; sNotify.uMaxEntries = 255; sNotify.ptAction.x = LOWORD(lParam); sNotify.ptAction.y = HIWORD(lParam);
if(uSub) { // Spalte verwenden pExtra = pData->pExtraItems[uSub - 1][pData->uSelectedItem];
if(pExtra) { sNotify.item.state = pExtra->uState&~TVIS_BASEFLAGS; sNotify.item.pszText = pExtra->pText; sNotify.item.cchTextMax = pExtra->uTextSize; } else { sNotify.item.state = 0; sNotify.item.cchTextMax = 0; sNotify.item.pszText = _T(""); }
sNotify.item.state |= pEntry->uState & TVIS_BASEFLAGS; } else { // Haupteintrag sNotify.item.state = pEntry->uState; sNotify.item.pszText = pEntry->pText; sNotify.item.cchTextMax = pEntry->uTextSize; }
UNLOCK(pData); lRet = SendNotify(pData, &sNotify.hdr); LOCK(pData);
if(!lRet) return 0;
if(wParam == VK_RETURN) { wParam = VK_DBLCLK; uBits = 0; } else if(wParam == VK_EDITCLK) { if(pData->uStyleEx & TVS_EX_NOCURSORSET) { uBits = 0; } else { TreeListGetItemRect(pData, uItem, TVIR_COLTOSUB(uSub) | TVIR_GETCOLUMN | TVIR_TEXT, &sRect); uBits = TVIR_SETAT(LOWORD(lParam) - sRect.left); } } else { uBits = 0; }
cChar = (TCHAR)((lRet >> 8) & 0xFF); uBits |= U(lRet)&TVIR_EDITFULL;
if(U(lRet)&TVIR_EDITCOMBOBOX) { // Eine Combobox anzeigen uBits |= (U(lRet)&TVIR_EDITCOMBOLIST) ? 0x40000000 : 0x20000000; }
hWnd = TreeListEditLabel(pData, uItem, uSub | uBits); if(!hWnd) return 0;
if(lRet & TVIR_EDITCOMBOBOX) { // Die Combobox f�llen uMax = sNotify.uMaxEntries; iSel = -1;
if(sNotify.pTextList) { // Texte �ber Listenfeld for(uCnt = 0; uCnt < uMax; uCnt++) { pText = sNotify.pTextList[uCnt]; if(!pText) break;
SendMessage(hWnd, CB_ADDSTRING, 1, (LPARAM)pText);
if(sNotify.item.pszText && !_tcscmp(pText, sNotify.item.pszText)) { iSel = uCnt; } } } else { // Text mit pText = sNotify.pTextEntries;
if(!pText) pText = _T("\0");
for(uCnt = 0; uCnt < uMax; uCnt++) { for(uLen = 0; pText[uLen]; uLen++) { // Subtextl�nge holen if(pText[uLen] == cChar) break; }
if(!uLen && !pText[uLen]) break;
uNum = uLen; if(uNum >= sizeof(cText) / sizeof(TCHAR)) { uNum = sizeof(cText) / sizeof(TCHAR) - 1; }
memcpy(cText, pText, uNum * sizeof(TCHAR)); cText[uNum] = 0; SendMessage(hWnd, CB_ADDSTRING, 1, (LPARAM)cText);
if(sNotify.item.pszText && wParam >= 0x10000 && !_tcscmp(cText, sNotify.item.pszText)) { iSel = uCnt; }
pText += uLen; if(!cChar || *pText) pText++; }
if(lRet & TVIR_EDITCOMBODEL) { // Den Puffer l�schen delete((TCHAR*)sNotify.pTextEntries); } }
if(iSel >= 0) { // Listeneintrag ausw�hlen SendMessage(hWnd, CB_SETCURSEL, iSel, 0); }
if(sNotify.uHeight) { // H�he der Dropdown-Liste einstellen SendMessage(hWnd, CB_SETDROPPEDWIDTH, sNotify.uHeight, 0); }
if(lRet & TVIR_EDITCOMBODOWN) { // Dropdown-Liste einblenden SendMessage(hWnd, CB_SHOWDROPDOWN, 1, 0); }
if(!(lRet & TVIR_EDITCOMBOLIST)) { // Textauswahl wiederherstellen SetWindowText(hWnd, sNotify.item.pszText); SendMessage(hWnd, CB_SETEDITSEL, 0, pData->uLastSel); } }
if(wParam < 0x10000) { // Taste an Fenster senden pData->cColumnStart = 1; sMsg.hwnd = hWnd; sMsg.lParam = lParam; sMsg.wParam = wParam; sMsg.message = WM_KEYDOWN;
TranslateMessage(&sMsg); } else if(wParam & VK_ISACHAR) { SendMessage(hWnd, WM_CHAR, wParam & 0xFFFF, lParam); } else { pData->cColumnStart = 0; } return 1;}
//*****************************************************************************//*//* TreeListStartAutoEdit//*//*****************************************************************************// Startet die Autoeditierung f�r eine Spalte// pData : Zeiger auf die Fensterdaten// uColumn : Ist die Nummer der Spalte// wParam : Ist der W-Parameter des Tastendrucks// VK_EDITCLK bei einem Clickauf das ausgew�hlte Feld// VK_ICONCLK bei einem Clickauf das Iion// VK_DBLCLK bei einem Doppelclick// lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)// Ergibt 1 das Editieren gestartet wurde, ansonsten 0// 0 wenn der Eintrag nicht gew�hlt wurdestatic int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam) { TCHAR cBuffer[256]; NMTREEVIEW sNotify; ExtraItem *pExtra; BaseItem *pEntry; LPTSTR *pList; LPTSTR pText; TV_ITEM sItem; RECT sRect; TCHAR cChar; unsigned uMode; unsigned uBits; unsigned uFlag; unsigned uMax; unsigned uPos; unsigned uLen; unsigned uSub; HWND hWnd; int iSel; int iRet; int iIcon;
if(pData->uEditItem) return 0; if(pData->uColumnCount <= uColumn) return 0; if(!(pData->uStyle & TVS_EDITLABELS)) return 0;
uBits = pData->aColumn[uColumn].bFlags; uMode = pData->aColumn[uColumn].bEdit;
if(uMode == 0) return 0;
if(uBits & TVAE_STATEENABLE) { // Kann das Editieren gesperrt werden if(uColumn) { pExtra = pData->pExtraItems[uColumn - 1][pData->uSelectedItem]; if(pExtra && (pExtra->uState & TVIS_DISABLEBIT)) return 0; } else { pEntry = pData->pTreeItems[pData->uSelectedItem]; if(!pEntry || (pEntry->uState & TVIS_DISABLEBIT)) return 0; } }
if(wParam != VK_RETURN && wParam < 0x10000) { // Zeicheneingabe if(!TVIS_EDIT(uMode)) return 0; if(uBits & TVAE_ONLYRETURN) return 0; if(wParam <= ' ') return 0; pData->cColumnStart = 1; } else { pData->cColumnStart = 0; } uMax = pData->aColumn[uColumn].bCbSize; if(!uMax) uMax = 1024;
//******************** Weiterschalten mit Return ****************************** if(uMode >= TVAX_STEP) { sItem.mask = TVIF_TEXT | TVIF_SUBITEM | TVIF_TEXTPTR | ((uMode < TVAX_CHECK) ? 0 : TVIF_STATE | TVIF_PARAM); sItem.stateMask = 0xFFFFFFFF; sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem; sItem.cChildren = uColumn;
if(!TreeListGetItem(pData, &sItem)) return 0;
if((uMode & 1) && wParam != VK_ICONCLK) { // Ein Edit-Feld �ffnen uMode = TVAX_EDIT; goto EditField; }
if(uMode >= TVAX_CHECK) { // State-Bits bei Checkboxen setzen if(uBits & TVAE_STATEENABLE) uFlag = sItem.state & (~TVIS_STATEIMAGEMASK | TVIS_DISABLEBIT); else uFlag = sItem.state & (~TVIS_STATEIMAGEMASK);
if(pData->uStyleEx & TVS_EX_BITCHECKBOX) sItem.state = (sItem.state ^ 0x1000); else sItem.state = (sItem.state & 0x1000) ? 0x2000 : 0x1000;
sItem.state |= uFlag; } else { sItem.mask &= ~TVIF_STATE; }
if(uBits & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL}; pList = (LPTSTR *)pData->aColumn[uColumn].pCbData;
if(!pList) { if(uMode < TVAX_CHECK) return 0; sItem.mask &= ~TVIF_TEXT; pText = sItem.pszText; uPos = 0; goto NoTextChange; }
for(uPos = 0;; uPos++) { if(uPos >= uMax || !pList[uPos]){ uPos = 0; break; } if(str_cmp(sItem.pszText, pList[uPos])) continue; uPos++; if(uPos >= uMax || !pList[uPos]) uPos = 0; break; }
pText = pList[uPos]; if(!pText) { if(uMode < TVAX_CHECK) return 0; sItem.mask &= ~TVIF_TEXT; pText = sItem.pszText; } } else { // Textliste char *pText="1|2|3"; pText = (LPTSTR)pData->aColumn[uColumn].pCbData; cChar = (TCHAR)pData->aColumn[uColumn].bCbChar; sItem.cchTextMax--;
if(!pText) { if(uMode < TVAX_CHECK) return 0; sItem.mask &= ~TVIF_TEXT; pText = sItem.pszText; uPos = 0; goto NoTextChange; }
for(uPos = 0;; uPos++) { if(uPos >= uMax) { pText = (LPTSTR)pData->aColumn[uColumn].pCbData; uPos = 0; break; }
for(uLen = 0; pText[uLen]; uLen++) { // Subtextl�nge bestimmen if(pText[uLen] == cChar) break; }
if(sItem.cchTextMax == (int)uLen) // Ist der Subtext der aktulle Text if(str_ncmp(sItem.pszText, pText, uLen) == 0) { uPos++;
if(uPos >= uMax) { pText = (LPTSTR)pData->aColumn[uColumn].pCbData; uPos = 0; break; }
pText += uLen; if(pText[0] == cChar) pText++; if(pText[0] == 0) { pText = (LPTSTR)pData->aColumn[uColumn].pCbData; uPos = 0; }
break; }
pText += uLen; if(pText[0] == cChar) pText++; if(pText[0] == 0) { pText = (LPTSTR)pData->aColumn[uColumn].pCbData; uPos = 0; break; }
}
for(uLen = 0; pText[uLen] && uLen < 256; uLen++) { // Ausgew�hlten Text kopiren if(pText[uLen] == cChar) break; cBuffer[uLen] = pText[uLen]; }
cBuffer[uLen] = 0; pText = cBuffer; }
NoTextChange:
sItem.mask &= ~TVIF_TEXTPTR; sItem.stateMask &= TVIS_STATEIMAGEMASK; sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem; sItem.pszText = pText; sItem.cchTextMax = 256; sItem.cChildren = uColumn; iIcon = pData->aColumn[uColumn].iCbIcon;
if(iIcon >= 0) { // Auch ein Icon zuweisen sItem.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; sItem.iImage = iIcon + uPos; sItem.iSelectedImage = sItem.iImage; }
iRet = TreeListSetItem(pData, &sItem);
sNotify.hdr.code = (uMode < TVAX_CHECK) ? TVN_STEPSTATECHANGED : TVN_CBSTATECHANGED; sNotify.action = (UINT)wParam; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.hItem = sItem.hItem; sNotify.itemNew.state = sItem.state; sNotify.itemNew.lParam = sItem.lParam; sNotify.itemNew.pszText = sItem.pszText; sNotify.itemNew.cchTextMax = sItem.cchTextMax; sNotify.itemNew.cChildren = uColumn; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = LOWORD(lParam); sNotify.ptDrag.y = HIWORD(lParam);
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData);
return iRet; }
//******************** Edit oder Combobox *************************************EditField:
uSub = (uMode - 1) << 29; uSub |= uColumn;
if(uBits & TVAE_FULLWIDTH) { uSub |= TVIR_EDITFULL; }
if(wParam == VK_EDITCLK) // Cursor auf Klickposition if(!(pData->uStyleEx & TVS_EX_NOCURSORSET)) { TreeListGetItemRect(pData, pData->uSelectedItem, TVIR_COLTOSUB(uColumn) | TVIR_GETCOLUMN | TVIR_TEXT, &sRect); uSub |= TVIR_SETAT(LOWORD(lParam) - sRect.left); }
hWnd = TreeListEditLabel(pData, pData->uSelectedItem, uSub); if(!hWnd) return 0;
if(uMode != TVAX_EDIT) { iSel = (uMode != TVAX_CBLIST) ? -1 : 0; sItem.mask = TVIF_TEXT | TVIF_SUBITEM | TVIF_TEXTPTR; sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem; sItem.cChildren = uColumn;
if(!TreeListGetItem(pData, &sItem)) return 0;
if(uBits & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL}; pList = (LPTSTR *)pData->aColumn[uColumn].pCbData;
for(uPos = 0; uPos < uMax; uPos++) { if(!pList[uPos]) break; if(!str_cmp(sItem.pszText, pList[uPos])) iSel = uPos; SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)pList[uPos]); } } else { // Textliste char *pText="1|2|3"; pText = (LPTSTR)pData->aColumn[uColumn].pCbData; cChar = (TCHAR)pData->aColumn[uColumn].bCbChar; sItem.cchTextMax--;
for(uPos = 0; uPos < uMax; uPos++) { for(uLen = 0; pText[uLen]; uLen++) { if(pText[uLen] == cChar) break; }
if(sItem.cchTextMax == (int)uLen) if(str_ncmp(sItem.pszText, pText, uLen) == 0) { iSel = uPos; }
if(cChar) { if(uLen < 256){ memcpy(cBuffer, pText, sizeof(TCHAR)*uLen); cBuffer[uLen] = 0; } else { memcpy(cBuffer, pText, sizeof(TCHAR) * 255); cBuffer[255 ] = 0; } SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)cBuffer); } else { SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)pText); }
pText += uLen; if(pText[0] == cChar) pText++; if(pText[0] == 0) break; } }
if(iSel >= 0) { SendMessage(hWnd, CB_SETCURSEL, iSel, 0); } } if((uBits & TVAE_DROPDOWN) && (uMode&~1) == 2) { // Dropdownliste aufklappen SendMessage(hWnd, CB_SHOWDROPDOWN, 1, 0); }
// Ersten Buchstaben ans Fenster �bergeben if(TVIS_EDIT(uMode) && pData->cColumnStart && wParam != VK_EDITCLK) { SendMessage(hWnd, WM_CHAR, wParam, 0); } return 1;}
//*****************************************************************************//*//* TreeListProc//*//*****************************************************************************// Ist die Fensterfunktion f�r das TreeList Fensterstatic LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { TreeListData *pData; MSG *pMsg; LPARAM lRet; TV_HITTESTINFO sInfo; POINT sPoint; SCROLLINFO sScroll; unsigned uChange; unsigned uDelta; unsigned uTime; unsigned uFlag; unsigned uMode; unsigned uVal; unsigned uOld; int iDif; int iPos; int iMax; HDC hDc; switch(uMsg) { case WM_CREATE: // Das Fenster erzeugen
pData = new(TreeListData, 1); if(!pData) return -1;
memset(pData, 0, sizeof(TreeListData)); pData->pToolTipText = new(TCHAR, 256); pData->uToolTipSize = 256;
if(!pData->pToolTipText) { delete(pData); return -1; }
pData->pTreeItems = new(BaseItem*, 1); if(!pData->pTreeItems) { delete(pData->pToolTipText); delete(pData); return -1; }
pData->pItemPos = new(unsigned, 1); if(!pData->pItemPos) { delete(pData->pToolTipText); delete(pData->pTreeItems); delete(pData); return -1; }
GlobalInit();
pData->pItemPos [0] = 0; pData->pTreeItems[0] = NULL;
SetWindowLongPtr(hWnd, 0, (LONG_PTR)pData); pData->iIndent = DEFAULT_IDENT; pData->iShift = DEFAULT_SHIFT; pData->uStyle = GetWindowLong(hWnd, GWL_STYLE); pData->hSem = CreateSemaphore(0, 1, 0x70000000, 0); pData->hWnd = hWnd; pData->cIsEnabled = (char)IsWindowEnabled(hWnd); pData->iAutoAdd = 1; pData->aColumnPos[0] = 0; pData->aColumnPos[1] = 1;
if(!(pData->uStyle & (TVS_HASBUTTONS | TVS_HASLINES))) { pData->cHasRootRow = 0; } else { pData->cHasRootRow = (char)((pData->uStyle & TVS_LINESATROOT) ? 1 : 0); }
if(!(pData->uStyle & TVS_NOTOOLTIPS)) { CreateToolTip(pData); }
UpdateFont(pData); UpdateHeight(pData); UpdateColorsList(pData); UpdateScrollY(pData);
if(pOpenThemeData) // Soll ein Thema angezeigt werden pData->hTheme = pOpenThemeData(hWnd, L"TREEVIEW"); else pData->hTheme = NULL;
pData->cGlyphOk = (char)((pData->hTheme) ? 1 : 0);
if(pData->uStyle & TVS_CHECKBOXES) { CreateStateImageList(pData, 0); }
return 0;
case WM_DESTROY: // Das Fenster zerst�ren
pData = GetHandle(hWnd);
LOCK(pData);
TreeListDeleteItem(pData, U(TVI_ROOT), 0); if(pData->hStates == THEMEIMGLIST) pData->hStates = 0; if(pData->hChecks == THEMEIMGLIST) pData->hChecks = 0; if(pData->hEdit){ DestroyWindow(pData->hEdit); pData->hEdit = 0; } if(pData->hHeader){ DestroyWindow(pData->hHeader); pData->hHeader = 0; } if(pData->hToolTip){ DestroyWindow(pData->hToolTip); pData->hToolTip = 0; } if(pData->hStates){ ImageList_Destroy(pData->hStates); pData->hStates = 0; }
if(pData->uStyleEx & TVS_EX_SHAREIMAGELISTS) { if(pData->hStates && pData->iStatesMode) { ImageList_Destroy(pData->hStates); pData->hStates = 0; } if(pData->hChecks && pData->iChecksMode) { ImageList_Destroy(pData->hChecks); pData->hChecks = 0; } pData->hImages = 0; pData->hSubImg = 0; pData->hHeadImg = 0; } else { if(pData->hStates){ ImageList_Destroy(pData->hStates); pData->hStates = 0; } if(pData->hChecks){ ImageList_Destroy(pData->hChecks); pData->hChecks = 0; } if(pData->hImages){ ImageList_Destroy(pData->hImages); pData->hImages = 0; } if(pData->hSubImg){ ImageList_Destroy(pData->hSubImg); pData->hSubImg = 0; } if(pData->hHeadImg){ if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST) ImageList_Destroy(pData->hHeadImg); pData->hHeadImg = 0; } }
if(pData->hThemeBt){ pCloseThemeData(pData->hThemeBt); pData->hThemeBt = 0; } if(pData->hTheme){ pCloseThemeData(pData->hTheme); pData->hTheme = 0; }
for(uVal = 1; uVal < pData->uColumnCount; uVal++) { delete(pData->pExtraItems[uVal - 1]); pData->pExtraItems[uVal - 1] = 0; }
if(pData->hFontB){ DeleteObject(pData->hFontB); pData->hFontB = 0; }
pData->uColumnCount = 0;
UNLOCK(pData);
return 0;
case WM_NCDESTROY: // Das Fenster zerst�ren
pData = GetHandle(hWnd);
LOCK(pData);
delete(pData->pToolTipText); delete(pData->pTreeItems); delete(pData->pItemPos);
UNLOCK(pData);
SetWindowLongPtr(hWnd, 0, 0); CloseHandle(pData->hSem); memset(pData, 0, sizeof(TreeListData)); delete(pData);
GlobalDeinit();
return 0;
case WM_SHOWWINDOW: // Fenster ein/ausblenden
if(wParam) { pData = GetHandle(hWnd);
sScroll.cbSize = sizeof(SCROLLINFO); sScroll.fMask = SIF_ALL; sScroll.nMin = 0; sScroll.nMax = 0; sScroll.nPage = 0; sScroll.nPos = 0; sScroll.nTrackPos = 0;
SetScrollInfo(pData->hWnd, SB_VERT, &sScroll, TRUE); SetScrollInfo(pData->hWnd, SB_HORZ, &sScroll, TRUE);
pData->uOldXCount = 0xFFFF; pData->uOldYCount = 0xFFFF;
UpdateScrollY(pData); UpdateScrollX(pData); }
return 0;
case WM_SIZE: // Die Fenstergr��e wurde ver�ndert
pData = GetHandle(hWnd); uFlag = 0;
LOCK(pData);
uVal = LOWORD(lParam); if(uVal && uVal != pData->uSizeX) { uOld = pData->uSizeX; pData->uSizeX = uVal;
if(pData->uColumnCountVar) { // Spalten mit variabler Breite nach f�hren RECT sRect; int iDelta; int iNum;
iDelta = uVal - uOld;
ChangeColSize(pData, iDelta);
iNum = UpdateColumns(pData); GetClientRect(hWnd, &sRect); sRect.left = iNum; sRect.left -= pData->uScrollX; sRect.top = pData->uStartPixel; InvalidateRect(hWnd, &sRect, FALSE); }
if(uVal > uOld) { // Hat sich die Breite vergr��ert RECT sRect;
GetClientRect(hWnd, &sRect); sRect.right = uVal; sRect.left = uOld; InvalidateRect(hWnd, &sRect, FALSE); }
pData->aColumnXpos[pData->uColumnCount + 1] = uVal + 1;
MoveWindow(pData->hHeader, -(int)pData->uScrollX, 0, uVal + pData->uScrollX, pData->uStartPixel, uVal > uOld); UpdateScrollX(pData); }
uVal = HIWORD(lParam); if(uVal && uVal != pData->uSizeY) { if(uVal > pData->uSizeY) { // Hat sich die H�he vergr��ert RECT sRect;
GetClientRect(hWnd, &sRect); uFlag = 1; sRect.bottom = uVal; sRect.top = pData->uSizeY; InvalidateRect(hWnd, &sRect, FALSE); } else { uFlag = 0; }
pData->uSizeY = uVal; pData->uSizeYsub = (uVal <= pData->uStartPixel) ? 0 : uVal - pData->uStartPixel;
if(pData->uSizeY > pData->uStartPixel) { pData->uMaxEnties = pData->uSizeY; pData->uMaxEnties -= pData->uStartPixel; } else { pData->uMaxEnties = 0; }
pData->uPageEnties = pData->uMaxEnties; pData->uMaxEnties += pData->iRowHeight - 1; pData->uMaxEnties /= pData->iRowHeight; pData->uPageEnties /= pData->iRowHeight; // Wenn H�he vergr��ert dann Scroll-Position pr�fen if(uFlag && pData->uPageEnties > 2 && pData->uScrollY > 0) { if(pData->uScrollY + pData->uPageEnties + 1 > pData->uItemPosCount) { iPos = pData->uItemPosCount - pData->uPageEnties + 1; if(iPos < 0) iPos = 0; if(U(iPos) != pData->uScrollY) { pData->uScrollY = iPos; UpdateView(pData); } } } UpdateScrollY(pData); }
UNLOCK(pData);
if(uFlag) { RedrawWindow(pData->hHeader, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE); }
return 0;
case WM_ENABLE: // Das Fenster feischalten oder sperren
pData = GetHandle(hWnd); if(pData->cIsEnabled != ((U(wParam)) ? 1 : 0)) { uVal = GetWindowLong(hWnd, GWL_STYLE); uVal &= (0xFFFF0000 & ~WS_DISABLED); uVal |= (0x0000FFFF | WS_DISABLED) & (pData->uStyle ^ WS_DISABLED); SetWindowLong(hWnd, GWL_STYLE, uVal); }
return 0;
case WM_SETFOCUS: // Das Fenster bekommt den Focus
pData = GetHandle(hWnd); if(!pData->cHasFocus) { NMHDR sNotify;
LOCK(pData); pData->cHasFocus = 1;
if(pData->uSelectedCount <= 1) { if(pData->uSelectedItem) { if(pData->uStyleEx & TVS_EX_FULLROWMARK) UpdateRow(pData, pData->uSelectedItem); else UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub); } } else { UpdateView(pData); }
UNLOCK(pData);
sNotify.code = NM_SETFOCUS; SendNotify(pData, &sNotify); }
return 0;
case WM_KILLFOCUS: // Das Fenster bekommt den Focus
pData = GetHandle(hWnd); if(pData->cHasFocus) { NMHDR sNotify;
LOCK(pData); pData->cHasFocus = 0;
if(pData->uSelectedCount <= 1) { if(pData->uSelectedItem) { if(pData->uStyleEx & TVS_EX_FULLROWMARK) UpdateRow(pData, pData->uSelectedItem); else UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub); } } else { UpdateView(pData); }
UNLOCK(pData);
sNotify.code = NM_KILLFOCUS; SendNotify(pData, &sNotify); }
return 0;
case WM_MOUSEMOVE: // Gab es eine Mausbewegung
pData = GetHandle(hWnd); sInfo.hItem = 0; sInfo.flags = 0;
if(!(pData->uStyle & TVS_NOTOOLTIPS)) { if(!pData->cIsEnabled) { // Ist das Fenster freigegeben return 0; }
LOCK(pData);
sInfo.pt.x = LOWORD(lParam); sInfo.pt.y = HIWORD(lParam); TreeListHitTest(pData, &sInfo); UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags);
UNLOCK(pData); }
if(pData->uStyle & TVS_TRACKSELECT) { if(!pData->cIsEnabled) { // Ist das Fenster freigegeben return 0; }
LOCK(pData);
if(!sInfo.hItem) { sInfo.pt.x = LOWORD(lParam); sInfo.pt.y = HIWORD(lParam); TreeListHitTest(pData, &sInfo); }
if(sInfo.hItem && (sInfo.flags & (TVHT_ONSUBITEM | TVHT_ONSUBLABEL | TVHT_ONITEM))) { TreeListSetTrackItem(pData, U(sInfo.hItem), TVHT_SUBTOCOL(sInfo.flags)); }
UNLOCK(pData); }
if(wParam & pData->uDragFlags) // Drag beginnen if(U(lParam) != pData->uLastMove) { NMTREEVIEW sNotify; BaseItem *pEntry; int iDiffX; int iDiffY;
iDiffX = (short)(lParam) - (short)(pData->uLastMove); iDiffY = (short)(lParam >> 16) - (short)(pData->uLastMove >> 16);
if(iDiffX < 0) iDiffX = -iDiffX; if(iDiffY < 0) iDiffY = -iDiffY;
if(iDiffX <= 2 && iDiffY <= 2) { // Mehr als zwei Pixel-Verschub return 0; }
LOCK(pData);
if(pData->uDragItem > pData->uTreeItemsMax) { UNLOCK(pData); return 0; }
pEntry = pData->pTreeItems[pData->uDragItem]; if(!pEntry) { UNLOCK(pData); return 0; }
sNotify.hdr.code = TVN_BEGINDRAG; sNotify.action = (pEntry->uState & TVIS_EXPANDED) ? TVE_COLLAPSE : TVE_EXPAND; sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER; sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)pData->uDragItem; sNotify.itemNew.stateMask = 0xFFFFFFFF; sNotify.itemNew.state = pEntry->uState; sNotify.itemNew.lParam = pEntry->lParam; sNotify.itemNew.cChildren = pData->uDragSub; sNotify.itemNew.pszText = (LPTSTR) - 1; sNotify.itemNew.cchTextMax = -1; sNotify.itemOld.mask = 0; sNotify.ptDrag.x = LOWORD(lParam); sNotify.ptDrag.y = HIWORD(lParam); pData->uDragFlags = 0; pData->cClickFlag = 0; pData->cClickEdit = 0;
UNLOCK(pData);
SendNotify(pData, &sNotify.hdr); }
pData->uLastMove = U(lParam);
return 0;
case WM_LBUTTONUP: // Linken Mausklick aufheben
pData = GetHandle(hWnd); pData->uDragFlags &= ~MK_LBUTTON;
if(pData->cClickFlag || pData->cClickEdit) { TreeListMouseClick(pData, uMsg, wParam, lParam); pData->cClickFlag = 0; pData->cClickEdit = 0; } else { TreeListMouseNotify(pData, TVN_LBUTTONUP, wParam, lParam); }
return 0;
case WM_RBUTTONUP: // Linken Mausklick aufheben
pData = GetHandle(hWnd); pData->uDragFlags &= ~MK_RBUTTON;
TreeListMouseNotify(pData, TVN_RBUTTONUP, wParam, lParam);
break;
case WM_LBUTTONDOWN: // Mausklick
pData = GetHandle(hWnd);
LOCK(pData);
uTime = GetTickCount();
if(pData->cButtonFlag && pData->uToolTipItem) { // Doppelklick simulieren �ber ToolTip pData->cButtonFlag = 0; uDelta = uTime - pData->uButtonLast;
if(uDelta < 700) { iPos = abs(LOWORD(lParam) - LOWORD(pData->uButtonPos)); iPos += abs(HIWORD(lParam) - HIWORD(pData->uButtonPos));
if(iPos <= 6) { TreeListMouseClick(pData, WM_LBUTTONDBLCLK, wParam, lParam); return 0; } } }
pData->cButtonFlag = 1; pData->uButtonLast = uTime; pData->uButtonPos = U(lParam);
TreeListMouseClick(pData, uMsg, wParam, lParam);
return 0;
case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
pData = GetHandle(hWnd);
LOCK(pData);
pData->cButtonFlag = 0; TreeListMouseClick(pData, uMsg, wParam, lParam);
return 0;
case WM_KEYDOWN: // Tastendruck
pData = GetHandle(hWnd); LOCK(pData); TreeListKeyDown(pData, wParam, lParam);
return 0;
case WM_KEYUP: // Tastendruck
DefWindowProc(hWnd, uMsg, wParam, lParam); return 1;
case WM_CHAR: // Zeicheneingabe
pData = GetHandle(hWnd); iMax = lParam & 0xFFFF;
for(iPos = 0; iPos < iMax; iPos++) { TreeListChar(pData, (UINT)wParam, lParam); }
return 0;
case WM_DRAWITEM: // Weietleiten von OwnerDraw des Headers
if(wParam == 1) { pData = GetHandle(hWnd); return SendMessage(GetParent(hWnd), uMsg, GetWindowLong(hWnd, GWL_ID), lParam); }
return 0;
case WM_MOUSEWHEEL: // Scrollen mit dem Mausrad
if(!(LOWORD(wParam) & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) { pData = GetHandle(hWnd);
if(pData->uEditItem) return 0;
iDif = (short)HIWORD(wParam) / (WHEEL_DELTA / 2);
if(wParam & MK_CONTROL) { iDif *= 9; } else if(wParam & MK_SHIFT) { iDif *= 3; }
iPos = pData->uScrollY - iDif; iMax = pData->uItemPosCount; iMax -= pData->uPageEnties - 1;
if(iPos >= iMax) iPos = iMax; if(iPos < 0) iPos = 0; if(iPos != (int)pData->uScrollY) if(!(pData->uStyle & TVS_NOSCROLL)) { pData->uScrollY = iPos; SetScrollPos(hWnd, SB_VERT, iPos, TRUE); UpdateView(pData); }
return 1; }
return 0;
case WM_HSCROLL: // Vertikalles scrollen
pData = GetHandle(hWnd); iPos = pData->uScrollX;
if(pData->uEditItem) return 0;
switch(LOWORD(wParam)) { case SB_LINEDOWN: iPos += 16; break; case SB_LINEUP: iPos -= 16; break; case SB_PAGEDOWN: iPos += pData->uSizeX; break; case SB_PAGEUP: iPos -= pData->uSizeX; break; case SB_THUMBPOSITION: iPos = HIWORD(wParam); break; case SB_THUMBTRACK: iPos = HIWORD(wParam); break; }
uVal = pData->uColumnCount; if(uVal) iMax = pData->aColumnXpos[uVal] - pData->uSizeX / 2; else iMax = pData->iMaxSizeX; iMax -= pData->uSizeX / 2;
if(iPos >= iMax) iPos = iMax; if(iPos < 0) iPos = 0; if(iPos != (int)pData->uScrollX) { pData->uScrollX = iPos; SetScrollPos(hWnd, SB_HORZ, iPos, TRUE); UpdateView(pData);
if(pData->hHeader) { MoveWindow(pData->hHeader, -iPos, 0, pData->uSizeX + iPos, pData->uStartPixel, TRUE); } }
return 0;
case WM_VSCROLL: // Vertikalles scrollen
pData = GetHandle(hWnd); iPos = pData->uScrollY;
if(pData->uEditItem) return 0;
switch(LOWORD(wParam)) { case SB_LINEDOWN: iPos++; break; case SB_LINEUP: iPos--; break; case SB_PAGEDOWN: iPos += (pData->uPageEnties > 1) ? pData->uPageEnties - 1 : 1; break; case SB_PAGEUP: iPos -= (pData->uPageEnties > 1) ? pData->uPageEnties - 1 : 1; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: if(pData->uItemPosCount < 0x7F00) { iPos = HIWORD(wParam); } else { sScroll.cbSize = sizeof(SCROLLINFO); sScroll.fMask = SIF_TRACKPOS; GetScrollInfo(hWnd, SB_VERT, &sScroll); iPos = sScroll.nTrackPos; } }
iMax = pData->uItemPosCount; iMax -= pData->uPageEnties - 1;
if(iPos >= iMax) iPos = iMax; if(iPos < 0) iPos = 0; if(iPos != (int)pData->uScrollY) { pData->uScrollY = iPos; SetScrollPos(hWnd, SB_VERT, iPos, TRUE); UpdateView(pData); }
return 0;
case WM_SYSCOLORCHANGE: // Wurden die Systemfarben ver�ndert
pData = GetHandle(hWnd);
LOCK(pData);
if(pData->hTheme) { pCloseThemeData(pData->hTheme); pData->hTheme = NULL; }
if(pData->hThemeBt) { pCloseThemeData(pData->hThemeBt); pData->hThemeBt = NULL; }
if(pOpenThemeData) { pData->hTheme = pOpenThemeData(hWnd, L"TREEVIEW"); pData->cGlyphOk = (char)((pData->hTheme) ? 1 : 0); }
if(pData->iStatesMode) CreateStateImageList(pData, 0); if(pData->iChecksMode) CreateStateImageList(pData, 1);
if(pData->hHeader) SendMessage(pData->hHeader, WM_SYSCOLORCHANGE, 0, 0); UpdateColorsList(pData); UNLOCK(pData);
return 0;
case WM_GETFONT: //tell what font we are using { HFONT hFont; pData = GetHandle(hWnd);
LOCK(pData); hFont = pData->hFontN; UNLOCK(pData); return (LRESULT)hFont; }
case WM_SETFONT: // Einen neuen Font zuweisen
pData = GetHandle(hWnd);
LOCK(pData);
if(CreateFontset(pData, (HFONT)wParam)){ if(UpdateFont(pData)) UpdateView(pData); }
UNLOCK(pData);
return 0;
case WM_STYLECHANGED: // Hat sich der Fenstersytle ge�ndert
if(wParam == GWL_STYLE) { pData = GetHandle(hWnd); lParam = ((STYLESTRUCT *)lParam)->styleNew;
LOCK(pData); uChange = U(lParam) ^ pData->uStyle; pData->uStyle = U(lParam);
if(uChange & (TVS_CHECKBOXES | TVS_NONEVENHEIGHT)) { if(lParam & TVS_CHECKBOXES) { if(pData->hStates == NULL) { CreateStateImageList(pData, 0); } } else { if(pData->iStatesMode && pData->hStates) { if(pData->hStates != THEMEIMGLIST) { ImageList_Destroy(pData->hStates); }
pData->hStates = NULL; pData->iStatesMode = 0; } }
UpdateHeight(pData); UpdateScrollY(pData); }
if(uChange & (TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_RTLREADING | TVS_CHECKBOXES | TVS_TRACKSELECT)) { if(!(pData->uStyle & (TVS_HASBUTTONS | TVS_HASLINES))) { pData->cHasRootRow = 0; } else { pData->cHasRootRow = (char)((pData->uStyle & TVS_LINESATROOT) ? 1 : 0); }
UpdateView(pData); }
if(uChange & TVS_NOSCROLL) { pData->uOldYCount = 0xFFFF; pData->uOldXCount = 0xFFFF;
UpdateScrollX(pData); UpdateScrollY(pData); }
if(uChange & TVS_NOTOOLTIPS) { if(pData->uStyle & TVS_NOTOOLTIPS) { UpdateToolTip(pData, 0, 0); } else { CreateToolTip(pData); } }
if(uChange & WS_DISABLED) { pData->cIsEnabled = (char)((pData->uStyle & WS_DISABLED) ? 0 : 1); UpdateView(pData); if(!pData->cIsEnabled) UpdateToolTip(pData, 0, 0); }
UNLOCK(pData); }
return 0;
case WM_PAINT: // Das Fenster zeichnen
if(wParam) { TreeListDraw(hWnd, (HDC)wParam, NULL); } else { PAINTSTRUCT sPaint;
hDc = BeginPaint(hWnd, &sPaint);
if(pBeginBufferedPt && pEndBufferedPt) { RECT sRect; HDC hDcBuffer; HANDLE hBufferedPaint;
GetClientRect(hWnd, &sRect); hBufferedPaint = pBeginBufferedPt(hDc, &sRect, BPBF_COMPATIBLEBITMAP, NULL, &hDcBuffer);
if(hBufferedPaint) { TreeListDraw(hWnd, hDcBuffer, &sRect); pEndBufferedPt(hBufferedPaint, TRUE); } else { TreeListDraw(hWnd, hDc, &sRect); } } else { TreeListDraw(hWnd, hDc, &sPaint.rcPaint); }
EndPaint(hWnd, &sPaint); }
return 0;
case WM_TIMER: // Timer Funktion
if(wParam == ID_TOOLTIPCHECK) { pData = GetHandle(hWnd); if(pData->uToolTipItem) { if(pData->uToolTipShow) { // Verz�gertes einblenden pData->uToolTipShow--; if(pData->uToolTipShow) return 0;
LOCK(pData);
GetCursorPos(&sPoint);
sInfo.pt.x = sPoint.x; sInfo.pt.y = sPoint.y;
ScreenToClient(hWnd, &sInfo.pt);
if(WindowFromPoint(sPoint) == hWnd) { TreeListHitTest(pData, &sInfo); } else { sInfo.hItem = 0; sInfo.flags = 0; }
if(sInfo.flags & TVHT_ONITEM) if(pData->uToolTipItem == U(sInfo.hItem) && pData->uToolTipSub == 0) { TOOLINFO sInfo;
UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
if(pData->uToolTipItem) { SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo); }
SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y)); SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
return 0; }
if(sInfo.flags & TVHT_ONSUBITEM) if(pData->uToolTipItem == U(sInfo.hItem) && TVHT_SUBTOCOL(sInfo.flags) == pData->uToolTipSub) { TOOLINFO sInfo;
UNLOCK(pData);
sInfo.cbSize = sizeof(sInfo); sInfo.hwnd = pData->hWnd; sInfo.uId = (UINT_PTR)pData->hWnd;
if(pData->uToolTipItem) { SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo); }
SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y)); SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
return 0; }
// ToolTip wieder entferenen UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags); UNLOCK(pData); }
LOCK(pData);
GetCursorPos(&sInfo.pt); ScreenToClient(hWnd, &sInfo.pt); TreeListHitTest(pData, &sInfo); UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags);
UNLOCK(pData); } }
return 0;
case WM_COMMAND: // Kommando Nachrichnten
if(wParam == MAKELONG(3, EN_KILLFOCUS) || wParam == MAKELONG(3, EN_RETURN) || wParam == MAKELONG(3, CBN_KILLFOCUS)) { pData = GetHandle(hWnd); if(pData->uEditItem) { LOCK(pData); TreeListEndLabelEdit(pData, (wParam == MAKELONG(3, EN_RETURN)) ? 2 : 1); UNLOCK(pData); if(pData->uEditMode) if(wParam != MAKELONG(3, EN_KILLFOCUS)) { SetFocus(pData->hWnd); } } } else if(wParam == MAKELONG(3, EN_ESCAPE)) { // ESC-Taste in Edit-Fenster pData = GetHandle(hWnd); if(pData->uEditItem) { LOCK(pData); TreeListEndLabelEdit(pData, 0); UNLOCK(pData); if(pData->uEditMode) SetFocus(pData->hWnd); } } // �nderung in Edit-Fenster else if(wParam == MAKELONG(3, EN_CHANGE) || wParam == MAKELONG(3, CBN_EDITCHANGE) || wParam == MAKELONG(3, CBN_SELCHANGE) || wParam == MAKELONG(3, EN_SETTEXT)) { pData = GetHandle(hWnd); pData->cColumnStart = 1; }
return 0;
case WM_NOTIFY: // Notify Nachrichnten
if(wParam == 1) { // Nachricht vom Header NMHEADER *pHdr = (NMHEADER *)lParam; HDITEM sItem; HDITEM sTemp; RECT sRect; int iDelta; int iCode; int iSize; int iNext; int iCol; int iSub;
iCode = pHdr->hdr.code; // Hat sich die Spaltenbreite ver�ndert if(iCode == HDN_ITEMCHANGED && (pHdr->pitem->mask & HDI_WIDTH)) { pData = GetHandle(hWnd); iCol = pHdr->iItem;
if(pData->aColumn[iCol].sReal != pHdr->pitem->cxy) { iCode = HDN_TRACK; } }
if(iCode == HDN_BEGINDRAG) { // Drag&Drop im Header pData = GetHandle(hWnd);
if(!(pData->uStyleEx & TVS_EX_HEADERDRAGDROP) || pHdr->iItem == 0) { return 1; }
return 0; }
if(iCode == HDN_ENDDRAG) { // Drag&Drop im Header fertig if(pHdr->pitem->iOrder == 0 || pHdr->iItem == 0) { return 1; }
pData = GetHandle(hWnd);
if(!(pData->uStyleEx & TVS_EX_HEADERDRAGDROP)) { return 1; }
PostMessage(hWnd, TVM_SETCOLUMNORDERARRAY, FROM_HEADER, 0);
return 0; }
if(iCode == HDN_BEGINTRACK) { // User will die Spaltenbreite �ndern pData = GetHandle(hWnd);
if(!pData->cHasFocus) { SetFocus(pData->hWnd); }
if(pData->uStyleEx & TVS_EX_NOCOLUMNRESIZE) { // Darf der User die Spaltenbreite �ndern return 1; }
if(pData->uStyleEx & TVS_EX_FIXEDCOLSIZE) { // Fixe gesammte Spaltenbreite iNext = pData->aColumn[pHdr->iItem].bIndex;
for(iNext++;; iNext++) { // Suche n�chste ver�nerbare Spalte if(U(iNext) >= pData->uColumnCount) { return 1; }
iSub = pData->aColumnPos[iNext];
if(pData->aColumn[iSub].sFixed == 0) { break; } } }
if(U(pHdr->iItem) < pData->uColumnCount) // Darf die Spalte ver�ndert werden if(pData->aColumn[pHdr->iItem].sFixed) { POINT sPoint; int iCol; int iSub;
if(pData->aColumn[pHdr->iItem].sReal || pHdr->iItem < 0) { return 1; }
GetCursorPos(&sPoint); // Die n�chste ver�nderbare Spalte greifen ScreenToClient(pData->hHeader, &sPoint);
PostMessage(pData->hHeader, WM_LBUTTONUP, 0, MAKELONG(sPoint.x, sPoint.y));
iCol = pData->aColumn[pHdr->iItem].bIndex; iSub = pData->aColumnPos[iCol - 1];
PostMessage(pData->hHeader, WM_LBUTTONDOWN, 0, MAKELONG(pData->aColumnXpos[iSub + 1] - 2, sPoint.y));
return 1; } }
if(iCode == HDN_DIVIDERDBLCLICK) { // Doppelcklick auf Spaltentrenner pData = GetHandle(hWnd);
if(!pData->cHasFocus) { SetFocus(pData->hWnd); }
if(pData->uStyleEx & TVS_EX_NOCOLUMNRESIZE) { // Darf der User die Spaltenbreite �ndern return 0; }
if(U(pHdr->iItem) < pData->uColumnCount) // Darf die Spalte ver�ndert werden if(pData->aColumn[pHdr->iItem].sFixed) { return 0; }
LOCK(pData);
iSize = TreeListScanColumn(pData, pHdr->iItem); if(iSize) { // Spalte auf maximale Textbreite sItem.cxy = iSize; pHdr->pitem = &sItem; iCode = HDN_ENDTRACK;
if(pData->aColumn[pHdr->iItem].bMinEx) // Minimale Breite pr�fen if(pData->aColumn[pHdr->iItem].sMin > sItem.cxy) { sItem.cxy = pData->aColumn[pHdr->iItem].sMin; } }
UNLOCK(pData); }
if(iCode == HDN_TRACK || iCode == HDN_ENDTRACK) { // Wurde die Spaltenbreite ver�ndert pData = GetHandle(hWnd);
if(!pData->cHasFocus && iCode == HDN_ENDTRACK) { SetFocus(pData->hWnd); }
LOCK(pData);
iCol = pHdr->iItem; sItem.mask = HDI_WIDTH; sItem.cxy = pHdr->pitem->cxy;
if(pData->aColumn[iCol].bMinEx) // Minimale Breite pr�fen if(pData->aColumn[iCol].sMin > sItem.cxy) { sItem.cxy = pData->aColumn[iCol].sMin; pHdr->pitem->cxy = sItem.cxy;
if(sItem.cxy == pData->aColumn[iCol].sSize) { UNLOCK(pData); return 0; } }
if(pData->uStyleEx & TVS_EX_FIXEDCOLSIZE) { // Fixe gesammte Spaltenbreite if(iCol == 0 && sItem.cxy <= 0) { sItem.cxy = 1; pHdr->pitem->cxy = 1;
if(sItem.cxy == pData->aColumn[iCol].sSize) { UNLOCK(pData); return 0; } }
iNext = pData->aColumn[iCol].bIndex;
for(iNext++;; iNext++) { // �berspringe fixierte Spalten if(U(iNext) >= pData->uColumnCount) { UNLOCK(pData); return 0; }
iSub = pData->aColumnPos[iNext];
if(pData->aColumn[iSub].sFixed == 0) { break; } }
iDelta = pData->aColumn[iCol].sReal - sItem.cxy; sTemp.cxy = pData->aColumn[iSub].sReal + iDelta;
if(iDelta < 0) { // N�chste Spalte wird zu klein if(sTemp.cxy < 0) { sTemp.cxy = 0; iDelta = -pData->aColumn[iSub].sReal; sItem.cxy = pData->aColumn[iCol].sReal - iDelta; }
if(pData->aColumn[iSub].bMinEx) // Minimale Breite pr�fen if(pData->aColumn[iSub].sMin > sTemp.cxy) { iDelta += pData->aColumn[iSub].sMin - sTemp.cxy; sTemp.cxy = pData->aColumn[iSub].sMin; sItem.cxy = pData->aColumn[iCol].sReal - iDelta; }
pHdr->pitem->cxy = sItem.cxy;
if(iDelta >= 0) { // Keine �nderung UNLOCK(pData); return 0; } }
if(pData->aColumn[iSub].bWeight) { // Variable Spalte pData->iVarSize -= pData->aColumn[iSub].sSize; pData->iVarSize += sTemp.cxy; } else { // Fixe Spalte pData->iFixSize -= pData->aColumn[iSub].sSize; pData->iFixSize += sTemp.cxy; }
sTemp.mask = HDI_WIDTH;
iDif = pData->aColumn[iSub].sReal; pData->aColumn[iSub].sSize = (short)sTemp.cxy; pData->aColumn[iSub].sReal = (short)sTemp.cxy; Header_SetItem(pData->hHeader, iSub, &sTemp);
// Breite ver�ndert if(iDif != sTemp.cxy && (pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY)) { TV_COLSIZE sNotify;
sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = iSub; sNotify.uIndex = pData->aColumn[iSub].bIndex; sNotify.uPosX = pData->aColumnXpos[iSub]; sNotify.iSize = sTemp.cxy;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); } }
if(pData->aColumn[iCol].bWeight) { // Ist es eine variable Spalte pData->iVarSize -= pData->aColumn[iCol].sSize; pData->iVarSize += sItem.cxy; } else { // Fixe Spalte pData->iFixSize -= pData->aColumn[iCol].sSize; pData->iFixSize += sItem.cxy; }
iDif = pData->aColumn[iCol].sReal; pData->aColumn[iCol].sSize = (short)sItem.cxy; pData->aColumn[iCol].sReal = (short)sItem.cxy; Header_SetItem(pData->hHeader, iCol, &sItem);
iSize = UpdateColumns(pData); if(iSize < 0x10000) { // Spalten neu zeichnen GetClientRect(hWnd, &sRect); sRect.left = iSize; sRect.left -= pData->uScrollX; InvalidateRect(hWnd, &sRect, FALSE); }
UpdateScrollX(pData); UNLOCK(pData);
// Breite ver�ndert if(iDif != sItem.cxy && (pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY)) { TV_COLSIZE sNotify;
sNotify.hdr.code = TVN_COLUMNCHANGED; sNotify.uColumn = iCol; sNotify.uIndex = pData->aColumn[iCol].bIndex; sNotify.uPosX = pData->aColumnXpos[iCol]; sNotify.iSize = sItem.cxy;
UNLOCK(pData); SendNotify(pData, &sNotify.hdr); LOCK(pData); } } // Weiterleiten an Elternfenster if(iCode == HDN_ITEMCLICK || iCode == HDN_ITEMDBLCLICK) { pData = GetHandle(hWnd);
if(!pData->cHasFocus) { SetFocus(pData->hWnd); }
SendNotify(pData, &pHdr->hdr); } } else { NMHDR *pHdr = (NMHDR *)lParam; NMTTDISPINFO *pInfo;
switch(pHdr->code) { case TTN_GETDISPINFO:
pData = GetHandle(hWnd); pInfo = (NMTTDISPINFO *)pHdr; pInfo->lpszText = pData->pToolTipText; SendMessage(pData->hToolTip, WM_SETFONT, (WPARAM)pData->hFontT, 0); break; } }
return 0;
case WM_GETDLGCODE: // Welche Tasten werden im Dialog benutzt
pMsg = (MSG *)lParam; if(pMsg && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { return DLGC_WANTALLKEYS; }
return DLGC_WANTCHARS | DLGC_WANTARROWS;
case WM_PASTE: // Weiterleiten an Edit-Control case WM_CLEAR: case WM_COPY: case WM_CUT:
pData = GetHandle(hWnd);
if(pData->hEdit) { PostMessage(pData->hEdit, uMsg, 0, 0); return 0; }
break;
case TVM_SETIMAGELIST: // Die Image-Liste einstellen
pData = GetHandle(hWnd);
LOCK(pData);#ifdef _DEBUG char dbg[255]; sprintf(dbg, "TVM_SETIMAGELIST %d", (int)wParam); OutputDebugStringA(dbg);#endif switch((int)wParam) { case TVSIL_NORMAL: lRet = (LPARAM)pData->hImages; if(lRet == lParam) break;
pData->hImages = (HIMAGELIST)lParam; if(!pData->hImages) { pData->iImagesXsize = 0; pData->iImagesYsize = 0; } else { IMAGEINFO sInfo; ImageList_GetImageInfo(pData->hImages, 0, &sInfo); pData->iImagesXsize = sInfo.rcImage.right - sInfo.rcImage.left; pData->iImagesYsize = sInfo.rcImage.bottom - sInfo.rcImage.top; if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST) == 0)) SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages); }
if(!pData->iSubImgMode || pData->hSubImg == pData->hImages) { pData->iSubImgMode = 0; pData->hSubImg = pData->hImages; pData->iSubImgXsize = pData->iImagesXsize; pData->iSubImgYsize = pData->iImagesXsize; }
if(!pData->cFixedHeight) { pData->iRowHeight = 1; UpdateHeight(pData); UpdateScrollY(pData); } else { UpdateView(pData); }
break;
case TVSIL_HEADER: lRet = pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST; if(lRet == 0) break;
lRet = (LPARAM)pData->hHeadImg; if(lRet == lParam) break;
pData->hHeadImg = (HIMAGELIST)lParam;
if(pData->hHeader) SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg);
if(!pData->cFixedHeight) { pData->iRowHeight = 1; UpdateHeight(pData); UpdateScrollY(pData); } else { UpdateView(pData); } break;
case TVSIL_STATE: lRet = (LPARAM)pData->hStates; if(lRet == lParam) break;
if(pData->iStatesMode) { if(pData->hStates != THEMEIMGLIST) { ImageList_Destroy(pData->hStates); }
pData->iStatesMode = 0; }
pData->hStates = (HIMAGELIST)lParam; if(!pData->hStates) { pData->iStatesXsize = 0; pData->iStatesYsize = 0;
if(pData->uStyle & TVS_CHECKBOXES) { CreateStateImageList(pData, 0); } } else if(pData->hStates == THEMEIMGLIST) { pData->iStatesXsize = 16; pData->iStatesYsize = 16; pData->iStatesMode = 1; if(!pData->hThemeBt) CreateStateImageList(pData, 0); } else { IMAGEINFO sInfo; ImageList_GetImageInfo(pData->hStates, 0, &sInfo); pData->iStatesXsize = sInfo.rcImage.right - sInfo.rcImage.left; pData->iStatesYsize = sInfo.rcImage.bottom - sInfo.rcImage.top; pData->iStatesMode = 0; }
if(!pData->cFixedHeight) { pData->iRowHeight = 1; UpdateHeight(pData); UpdateScrollY(pData); } else { UpdateView(pData); }
break;
case TVSIL_CHECK: lRet = (LPARAM)pData->hChecks; if(lRet == lParam) break;
if(pData->iChecksMode) { if(pData->hChecks != THEMEIMGLIST) { ImageList_Destroy(pData->hChecks); }
pData->iChecksMode = 0; }
pData->hChecks = (HIMAGELIST)lParam; if(!pData->hChecks) { pData->iChecksXsize = 0; pData->iChecksYsize = 0;
for(uVal = 0; uVal < pData->uColumnCount; uVal++) { if(pData->aColumn[uVal].bEdit < TVSIL_CHECK) continue; CreateStateImageList(pData, 1); break; } } else if(pData->hChecks == THEMEIMGLIST) { pData->iChecksXsize = 16; pData->iChecksYsize = 16; pData->iChecksMode = 1; if(!pData->hThemeBt) CreateStateImageList(pData, 1); } else { IMAGEINFO sInfo; ImageList_GetImageInfo(pData->hChecks, 0, &sInfo); pData->iChecksXsize = sInfo.rcImage.right - sInfo.rcImage.left; pData->iChecksYsize = sInfo.rcImage.bottom - sInfo.rcImage.top; pData->iChecksMode = 0; }
if(!pData->cFixedHeight) { pData->iRowHeight = 1; UpdateHeight(pData); UpdateScrollY(pData); } else { UpdateView(pData); }
break;
case TVSIL_SUBIMAGES: lRet = (LPARAM)pData->hSubImg; if(lRet == lParam) break;
if(pData->iSubImgMode) { ImageList_Destroy(pData->hSubImg); pData->iSubImgMode = 0; }
pData->hSubImg = (HIMAGELIST)lParam; if(!pData->hSubImg || pData->hSubImg == pData->hImages) { pData->iSubImgMode = 0; pData->hSubImg = pData->hImages; pData->iSubImgXsize = pData->iImagesXsize; pData->iSubImgYsize = pData->iImagesXsize; } else { IMAGEINFO sInfo; ImageList_GetImageInfo(pData->hSubImg, 0, &sInfo); pData->iSubImgXsize = sInfo.rcImage.right - sInfo.rcImage.left; pData->iSubImgYsize = sInfo.rcImage.bottom - sInfo.rcImage.top; pData->iSubImgMode = 1; }
if(!pData->cFixedHeight) { pData->iRowHeight = 1; UpdateHeight(pData); UpdateScrollY(pData); } else { UpdateView(pData); }
break;
default: lRet = 0; }
UNLOCK(pData);
return lRet;
case TVM_GETIMAGELIST: // Die Image-Liste abfragen
pData = GetHandle(hWnd); if(!pData) return 0;
switch((int)wParam) { case TVSIL_NORMAL: lRet = (LPARAM)pData->hImages; break; case TVSIL_STATE: lRet = (LPARAM)pData->hImages; break; case TVSIL_CHECK: lRet = (LPARAM)pData->hChecks; break; case TVSIL_HEADER: lRet = (LPARAM)pData->hHeadImg; break; default : lRet = 0; }
return lRet;
case TVM_GETSETOPTION: // Diverse Optionen einstellen
pData = GetHandle(hWnd); lRet = 0;
switch(U(wParam) & ~TVOP_WRITEOPTION) { case TVOP_AUTOEXPANDOFF: // Icon Offset f�r TVS_EX_AUTOEXPANDICON
lRet = pData->iAutoAdd;
if((wParam & TVOP_WRITEOPTION) && lParam != lRet) { LOCK(pData);
pData->iAutoAdd = (int)lParam; if(pData->uItemPosCount > 0) { UpdateView(pData); }
UNLOCK(pData); }
break; }
return lRet;
case TVM_GETITEMSTATE: // Die Statusbits eines Eintrags abfragen
pData = GetHandle(hWnd); LOCK(pData);
if(U(wParam) <= pData->uTreeItemsMax) { BaseItem *pEntry;
pEntry = pData->pTreeItems[U(wParam)]; if(!pEntry) lRet = 0; { lRet = pEntry->uState; } } else { lRet = 0; }
UNLOCK(pData);
return lRet;
case TVM_GETITEM: // Eintr�ge abfragen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListGetItem(pData, (TV_ITEM *)lParam); UNLOCK(pData);
return lRet;
case TVM_SETITEM: // Eintr�ge einf�gen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListSetItem(pData, (TV_ITEM *)lParam); UNLOCK(pData);
return lRet;
case TVM_INSERTITEM: // Eintr�ge einf�gen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListInsertItem(pData, (TV_INSERTSTRUCT *)lParam); UNLOCK(pData);
return lRet;
case TVM_DELETEITEM: // Eintr�ge l�schen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListDeleteItem(pData, U(lParam), (U(wParam) == 0x88) ? 2 : 1); UNLOCK(pData);
return lRet;
case TVM_FINDITEM: // Eintr�ge suchen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListFindItem(pData, U(wParam), (TV_FIND *)lParam); UNLOCK(pData);
return lRet;
case TVM_DELETECOLUMN: // L�schen einer Salte im Header
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListDeleteColumn(pData, U(wParam)); UNLOCK(pData);
return lRet;
case TVM_INSERTCOLUMN: // Einf�gen einer Salte im Header
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListInsertColumn(pData, (int)wParam, (TV_COLUMN *)lParam); UNLOCK(pData);
return lRet;
case TVM_GETCOLUMNCOUNT: // Abfragen der Spaltenanzahl
pData = GetHandle(hWnd); return (LRESULT)pData->uColumnCount;
case TVM_GETHEADER: // Abfragen des Header-Fensters
pData = GetHandle(hWnd); return (LRESULT)pData->hHeader;
case TVM_GETEXTENDEDSTYLE: // Abfragen der erweiterten Style-Bits
pData = GetHandle(hWnd); return pData->uStyleEx;
case TVM_SETEXTENDEDSTYLE: // Einstellen der erweiterten Style-Bits
pData = GetHandle(hWnd); if(!wParam) wParam = 0xFFFFFFFF;
uVal = pData->uStyleEx & ~U(wParam); uVal |= U(lParam) & U(wParam);
if(pData->uStyleEx != uVal) { // Has it changed? LOCK(pData); uChange = pData->uStyleEx ^ uVal; pData->uStyleEx = uVal;
if(uChange & TVS_EX_AUTOHSCROLL) { UpdateScrollX(pData); }
if((uChange & TVS_EX_GRAYEDDISABLE) && !pData->cIsEnabled) { UpdateView(pData); }
if(uChange & TVS_EX_ITEMLINES) { UpdateHeight(pData); UpdateScrollY(pData); }
if(uChange & (TVS_EX_ALTERNATECOLOR | TVS_EX_SUBSELECT | TVS_EX_MULTISELECT | TVS_EX_FULLROWMARK | TVS_EX_FULLROWITEMS)) { UpdateView(pData); }
if((uChange&~U(lParam)) & TVS_EX_SUBSELECT) { TreeListSelectItem(pData, pData->uSelectedItem, 0, TVC_UNKNOWN); }
if(pData->hHeader){ if((uChange & TVS_EX_HIDEHEADERS) || (uChange & TVS_EX_HEADEROWNIMGLIST)) { pData->uStartPixel = (pData->uStyleEx & TVS_EX_HIDEHEADERS) ? 0 : bDrawWithTheme ? GetSystemMetrics(SM_CYHSCROLL) : 17; MoveWindow(pData->hHeader, -(int)pData->uScrollX, 0, pData->uSizeX + pData->uScrollX, pData->uStartPixel, TRUE); if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST){ SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg); } else { SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages); }
UpdateView(pData); } }
UNLOCK(pData); }
return uVal;
case TVM_GETINSERTMARKCOLOR: // Farben abfragen wParam = TVC_INSERT; goto ColGet; case TVM_GETLINECOLOR: wParam = TVC_LINE; goto ColGet; case TVM_GETTEXTCOLOR: wParam = TVC_TEXT; case TVM_GETBKCOLOR:
ColGet: if(wParam < 0 || wParam >= MAX_COLORS) return 0xFFFFFFFF; pData = GetHandle(hWnd); return pData->uColors[U(wParam)];
case TVM_SETINSERTMARKCOLOR: // Farben einstellen wParam = TVC_INSERT; goto ColSet; case TVM_SETLINECOLOR: wParam = TVC_LINE; goto ColSet; case TVM_SETTEXTCOLOR: wParam = TVC_TEXT; case TVM_SETBKCOLOR:
ColSet: if(wParam < 0 || wParam >= MAX_COLORS) return 0xFFFFFFFF;
pData = GetHandle(hWnd);
LOCK(pData);
lRet = pData->uColors[U(wParam)];
if((COLORREF)lParam == TV_NOCOLOR) { // Standartfarbe einstellen if(pData->cColorChanged[U(wParam)]) { pData->cColorChanged[U(wParam)] = 0; UpdateColorsList(pData); UpdateView(pData); } } else { pData->cColorChanged[U(wParam)] = 1; pData->uColors [U(wParam)] = (COLORREF)lParam;
if(lRet != lParam) { UpdateColorsList(pData); UpdateView(pData); } }
UNLOCK(pData);
return lRet;
case TVM_HITTEST: // Abfragen von Koortinatenpositionen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListHitTest(pData, (LPTV_HITTESTINFO)lParam); UNLOCK(pData);
return lRet;
case TVM_SELECTCHILDS: // Mehrere Eintr�ge ausw�hlen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSelectChilds(pData, U(lParam), U(wParam)); UNLOCK(pData);
return lRet;
case TVM_SELECTSUBITEM: // Einen (Sub)Eintrag ausw�hlen
pData = GetHandle(hWnd);
LOCK(pData); if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) wParam = 0; lRet = TreeListSelectItem(pData, U(lParam), U(wParam), TVC_UNKNOWN); if(lRet > 1) lRet = 1; UNLOCK(pData);
return lRet;
case TVM_SELECTDROP: // Den unterstrichenen Eintrags ausw�hlen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSetTrackItem(pData, U(lParam), U(wParam)); UNLOCK(pData);
return lRet;
case TVM_SELECTITEM: // Einen Eintrag ausw�hlen
pData = GetHandle(hWnd);
LOCK(pData);
switch(wParam) { case TVGN_CARET: lRet = TreeListSelectItem(pData, U(lParam), 0, TVC_UNKNOWN); if(lRet > 1) lRet = 1; break; case TVGN_DROPHILITE: lRet = TreeListSetTrackItem(pData, U(lParam), 0); break;
case TVGN_FIRSTVISIBLE: lRet = TreeListEnsureVisible(pData, U(lParam), FIRST_LINE); lRet = (lRet < 0) ? 0 : 1; break;
default : lRet = 0; }
UNLOCK(pData);
return lRet;
case TVM_GETCOLUMNORDERARRAY: // Spaltensortierung abfragen
if(!lParam) return 0;
pData = GetHandle(hWnd);
if(!pData->hHeader) return 0;
return Header_GetOrderArray(pData->hHeader, U(wParam), lParam);
case TVM_SETCOLUMNORDERARRAY: // Spalten sortieren
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListSetOrderArray(pData, U(wParam), (unsigned *)lParam); UNLOCK(pData);
return lRet;
case TVM_GETCOUNT: // Anzahl der Eintr�ge abfragen
pData = GetHandle(hWnd); return pData->uTreeItemsCount;
case TVM_GETINDENT: // Einr�ckung abfragen
pData = GetHandle(hWnd); return pData->iIndent;
case TVM_SETINDENT: // Einr�ckung einstellen
pData = GetHandle(hWnd); lRet = pData->iIndent; if(wParam < 5) wParam = 5; if(wParam > 64) wParam = 64; if(lRet != (LPARAM)wParam) { LOCK(pData); pData->iIndent = (int)wParam; UpdateView(pData); UNLOCK(pData); }
return lRet;
case TVM_GETITEMHEIGHT: // Zeilenh�he abfragen
pData = GetHandle(hWnd); return pData->iRowHeight;
case TVM_SETITEMHEIGHT: // Zeilenh�he abfragen
pData = GetHandle(hWnd); lRet = pData->iRowHeight;
if(wParam == -1) { LOCK(pData); pData->cFixedHeight = 0; UpdateHeight(pData); UpdateScrollY(pData); UNLOCK(pData); return lRet; }
if(wParam & 1) if(!(pData->uStyleEx & TVS_NONEVENHEIGHT)) wParam--; if(wParam < 1) wParam = 1; if(wParam > 256) wParam = 256;
if(lRet != (LPARAM)wParam) { LOCK(pData); pData->cFixedHeight = 1; pData->iRowHeight = (int)wParam; UpdateView(pData); UNLOCK(pData); }
return lRet;
case TVM_GETVISIBLECOUNT: // Abfragen der sichtbaren Zeilen
pData = GetHandle(hWnd); return pData->uPageEnties;
case TVM_ENSUREVISIBLE: // Einen Eintrag ins Sichtfenster legen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListEnsureVisible(pData, U(lParam), (int)wParam); UNLOCK(pData);
return lRet;
case TVM_ISITEMVISIBLE: // Ist ein Eintrag sichtbar
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListIsVisible(pData, U(lParam), (int)wParam); UNLOCK(pData);
return lRet;
case TVM_GETNEXTITEM: // Einen Eintrag suchen
pData = GetHandle(hWnd); LOCK(pData); lRet = TreeListGetNextItem(pData, U(lParam), (int)wParam); UNLOCK(pData);
return lRet;
case TVM_GETITEMRECT: // Das Rechteck eines Eintrages abfragen
pData = GetHandle(hWnd); LOCK(pData); uVal = *(unsigned *)lParam; lRet = TreeListGetItemRect(pData, uVal, U(wParam), (RECT *)lParam); UNLOCK(pData);
return lRet;
case TVM_EXPAND: // Einen Eintrag umklappen
pData = GetHandle(hWnd); LOCK(pData); lRet = 0;NextExp: if(U(lParam) <= pData->uTreeItemsMax) { BaseItem *pEntry;#ifndef __REACTOS__ POINT sPoint;#endif
pEntry = pData->pTreeItems[U(lParam)]; if(pEntry) { sPoint.x = 0; sPoint.y = 0;
if(wParam & TVE_EXPANDNEXT) { // Bei erstem Eltereneintrag beginnen if(!pEntry->uParent) { UNLOCK(pData); return 1; }
lParam = pEntry->uParent; pEntry = pData->pTreeItems[U(lParam)]; wParam &= ~TVE_EXPANDNEXT; }
switch(wParam & 0x0F) { case TVE_COLLAPSE: if(pEntry->uState & TVIS_EXPANDED) { lRet = (TreeListToggleItem(pData, U(lParam), 0)) ? 0 : 1; } else { // Nur Flag l�schen pEntry->uState &= ~TVIS_EXPANDPARTIAL; lRet = 1; } // Kinder l�schen if(wParam & TVE_COLLAPSERESET) { pEntry->uState &= TVIS_EXPANDEDONCE;
while(pEntry->uLastChild) { if(!TreeListDeleteItem(pData, pEntry->uLastChild, 1)) break; pEntry = pData->pTreeItems[U(lParam)]; } } // Auch Eltern zuklappen if(!(wParam & TVE_EXPANDRECURSIVE)) { break; }
if(!pEntry->uParent) { break; }
lParam = pEntry->uParent; goto NextExp; break;
case TVE_EXPAND: if(!(pEntry->uState & TVIS_EXPANDED)) { uVal = (wParam & TVE_EXPANDPARTIAL) ? TVIS_EXPANDPARTIAL : 0; lRet = (TreeListToggleItem(pData, U(lParam), uVal)) ? 0 : 1; } else { // Schon aufgeklappt lRet = 1;
if(wParam & TVE_EXPANDPARTIAL) { if(!(wParam & TVE_EXPANDFORCE)) if((pEntry->uState & (TVIS_EXPANDPARTIAL | TVIS_EXPANDEDONCE)) != (TVIS_EXPANDPARTIAL | TVIS_EXPANDEDONCE)) { lRet = (TreeListToggleItem(pData, U(lParam), TVE_EXPAND | TVIS_EXPANDPARTIAL)) ? 0 : 1; } } else { if(pEntry->uState & TVIS_EXPANDPARTIAL) { lRet = (TreeListToggleItem(pData, U(lParam), TVE_EXPAND)) ? 0 : 1; } } } // Auch Eltern aufklappen if(!(wParam & TVE_EXPANDRECURSIVE)) { break; }
if(!pEntry->uParent) { break; }
lParam = pEntry->uParent; goto NextExp; break;
case TVE_TOGGLE: lRet = (TreeListToggleItem(pData, U(lParam), 0)) ? 0 : 1; break; }
// Aktion auch auf alle Kinder anwenden if((wParam & TVE_ALLCHILDS) && pEntry->uFirstChild) { lParam = pEntry->uFirstChild; wParam &= ~(TVE_EXPANDRECURSIVE | TVE_EXPANDNEXT | TVE_ONLYCHILDS); sPoint.x = 0; sPoint.y = 0;
for(;;) { UNLOCK(pData);
TreeListProc(hWnd, uMsg, wParam, lParam);
LOCK(pData);
if(U(lParam) > pData->uTreeItemsMax) { break; }
pEntry = pData->pTreeItems[U(lParam)]; if(!pEntry || !pEntry->uNextItem) break;
lParam = pEntry->uNextItem; } } } }
UNLOCK(pData);
return lRet;
case TVM_SETINSERTMARK: // Einf�gemarke eintellen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSetInsertMark(pData, U(lParam), (int)wParam); UNLOCK(pData);
return lRet;
case TVM_SETITEMBKCOLOR: // Hintergrundfarbe eines Eintrages �ndern
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSetItemColor(pData, U(wParam & 0xFFFFFF), U(wParam) >> 24, (COLORREF)lParam, 0); UNLOCK(pData);
return lRet;
case TVM_SETITEMTEXTCOLOR: // Textfarbe eines Eintrages �ndern
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSetItemColor(pData, U(wParam & 0xFFFFFF), U(wParam) >> 24, (COLORREF)lParam, 1); UNLOCK(pData);
return lRet;
case TVM_GETITEMBKCOLOR: // Hintergrundfarbe eines Eintrages abfragen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListGetItemColor(pData, U(wParam), U(lParam), 0); UNLOCK(pData);
return lRet;
case TVM_GETITEMTEXTCOLOR: // Textfarbe eines Eintrages abfragen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListGetItemColor(pData, U(wParam), U(lParam), 1); UNLOCK(pData);
return lRet;
case TVM_SORTCHILDRENEX: // Sortieren mit Funktion
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSortItemsEx(pData, (TV_SORTEX *)lParam, (int)wParam); UNLOCK(pData);
return lRet;
case TVM_SORTCHILDRENCB: // Sortieren mit Funktion
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSortItemsCb(pData, (TV_SORTCB *)lParam, (int)wParam); UNLOCK(pData);
return lRet;
case TVM_SORTCHILDREN: // Sortieren der Kindereintr�ge
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSortItems(pData, U(lParam), (int)wParam); UNLOCK(pData);
return lRet;
case TVM_GETITEMOFROW: // Hole den Eintrag von einer Reihe
pData = GetHandle(hWnd);
LOCK(pData); if(U(lParam) < pData->uItemPosCount) lRet = pData->pItemPos[U(lParam)]; else lRet = 0; UNLOCK(pData);
return lRet;
case TVM_GETROWCOUNT: // Hole die Anzahl der sichtbaren Reihen
pData = GetHandle(hWnd);
return pData->uItemPosCount;
case TVM_GETCOUNTPERPAGE: // Hole die Anzahl der darstelbaren Reihen
pData = GetHandle(hWnd);
return pData->uMaxEnties;
case TVM_GETROWOFITEM: // Suche Reihe zu einem Eintrag
pData = GetHandle(hWnd);
LOCK(pData); if(U(lParam) <= pData->uTreeItemsMax) { BaseItem *pEntry;
pEntry = pData->pTreeItems[U(lParam)]; if(!pEntry) lRet = -1; else lRet = pEntry->uShowPos - 1; } else { lRet = -1; } UNLOCK(pData);
return lRet;
case TVM_EDITLABEL: // Einen Eintrag editieren
pData = GetHandle(hWnd); if(!(pData->uStyle & TVS_EDITLABELS)) return 0;
LOCK(pData);
if((wParam & 0xFFFFFF00) == TVLE_DONOTIFY) { // Notify starten lRet = TreeListStartNotifyEdit(pData, U(lParam), TVIR_EDITCOL(wParam), VK_RETURN, 0); } else { pData->cColumnStart = 0; lRet = (LRESULT)TreeListEditLabel(pData, U(lParam), U(wParam)); }
UNLOCK(pData);
return lRet;
case TVM_GETEDITCONTROL: // Das Handle des Edit-Fensters abfragen
pData = GetHandle(hWnd); return (LRESULT)pData->hEdit;
case TVM_GETTOOLTIPS: // Das Handle des ToolTip-Fensters abfragen
pData = GetHandle(hWnd); return (LRESULT)pData->hToolTip;
case TVM_SETTOOLTIPS: // Das Handle f�r das ToolTip-Fensters setzen
pData = GetHandle(hWnd); lRet = (LRESULT)pData->hToolTip; pData->hToolTip = (HWND)wParam; return lRet;
case TVM_SETUSERDATASIZE: // Einstellen der Gr��e der User-Daten
if(lParam < 0 || lParam > 0x1000000) return -1; pData = GetHandle(hWnd);
LOCK(pData);
if(pData->uTreeItemsCount > 0) { lRet = 0; } else { pData->uUserDataSize = U(lParam); lRet = lParam; }
UNLOCK(pData);
return lRet;
case TVM_GETUSERDATASIZE: // Abfragen der Gr��e der User-Daten
pData = GetHandle(hWnd); return pData->uUserDataSize;
case TVM_GETUSERDATA: // Einen Zeiger auf die User-Daten holen
pData = GetHandle(hWnd);
if(pData->uUserDataSize && U(lParam) <= pData->uTreeItemsMax) { BaseItem *pEntry;
pEntry = pData->pTreeItems[U(lParam)]; if(pEntry) return (LRESULT)(pEntry + 1); }
return 0;
case TVM_SETCOLUMN: // Einen Spalten-Header einstellen
pData = GetHandle(hWnd);
if(pData->hHeader && U(wParam) < pData->uColumnCount) { HDITEM sItem; unsigned uBit; unsigned uCol; TV_COLUMN *pCol;
pCol = (TV_COLUMN *)lParam; uCol = U(wParam);
uVal = pCol->cx; if(uVal == TVCF_LASTSIZE) { // Breite vor Fixierung benutzen if(pData->aColumn[uCol].sFixed > 0) { uVal = pData->aColumn[uCol].sFixed; } else { uVal = pData->aColumn[uCol].sReal; } }
if(pCol->mask & TVCF_FIXED) { // Die Spalte fixieren uBit = pCol->fmt & TVCFMT_FIXED;
if(uBit != 0 && pData->aColumn[uCol].sFixed == 0) { pData->aColumn[uCol].sFixed = pData->aColumn[uCol].sReal; if(!pData->aColumn[uCol].sFixed) pData->aColumn[uCol].sFixed = 100; }
if(uBit == 0 && pData->aColumn[uCol].sFixed != 0) { pData->aColumn[uCol].sFixed = 0; } }
sItem.mask = 0; if(pCol->mask & TVCF_FMT){ sItem.mask |= HDI_FORMAT; sItem.fmt = pCol->fmt | HDF_STRING; } if(pCol->mask & TVCF_IMAGE){ sItem.mask |= HDI_IMAGE; sItem.iImage = pCol->iImage; } if(pCol->mask & TVCF_WIDTH){ sItem.mask |= HDI_WIDTH; sItem.cxy = uVal; pData->aColumn[uCol].sSize = (short)sItem.cxy; } if(pCol->mask & TVCF_TEXT){ sItem.mask |= HDI_TEXT; sItem.pszText = pCol->pszText; sItem.cchTextMax = pCol->cchTextMax; }
if(sItem.mask) { lRet = SendMessage(pData->hHeader, HDM_SETITEM, uCol, (LPARAM)&sItem); } else { lRet = 1; }
if(lRet && (pCol->mask & TVCF_FMT)) { // Hat sich die Ausrichtung ver�ndert BYTE bAlign;
switch(pCol->fmt) { case TVCFMT_CENTER: bAlign = DT_CENTER; break; case TVCFMT_RIGHT: bAlign = DT_RIGHT; break; default: bAlign = DT_LEFT; break; }
if(pData->aColumn[uCol].bAlign != bAlign) { pData->aColumn[uCol].bAlign = bAlign; UpdateColRect(pData, uCol); } }
if(lRet && (pCol->mask & TVCF_MARK)) { // Die Spalte markieren RECT sRect; unsigned uNext;
uVal = (pCol->fmt & TVCFMT_MARK) ? 1 : 0; if(uVal != pData->aColumn[uCol].bMark) { pData->aColumn[uCol].bMark = (BYTE)uVal; pData->uMarkedCols += uVal * 2 - 1;
uNext = pData->aColumn [uCol ].bNext; sRect.left = pData->aColumnXpos[uCol ]; sRect.right = pData->aColumnXpos[uNext] + 1; sRect.bottom = pData->uScrollX; sRect.top = pData->uSizeY; InvalidateRect(pData->hWnd, &sRect, FALSE); } } } else { lRet = 0; }
return lRet;
case TVM_GETCOLUMN: // Einen Spalten-Header abfragen
pData = GetHandle(hWnd); if(pData->hHeader) { HDITEM sItem; TV_COLUMN *pCol = (TV_COLUMN *)lParam; int bWantMark; unsigned uCol; uCol = U(wParam); sItem.mask = 0; if(pCol->mask & TVCF_FMT) { sItem.mask |= HDI_FORMAT; bWantMark = pCol->fmt & TVCFMT_MARK; //memorize if we want the marked state } if(pCol->mask & TVCF_IMAGE){ sItem.mask |= HDI_IMAGE; } if(pCol->mask & TVCF_WIDTH){ sItem.mask |= HDI_WIDTH; } if(pCol->mask & TVCF_TEXT){ sItem.mask |= HDI_TEXT; sItem.pszText = pCol->pszText; sItem.cchTextMax = pCol->cchTextMax; }
lRet = SendMessage(pData->hHeader, HDM_GETITEM, wParam, (LPARAM)&sItem);
pCol->mask = 0;
if(sItem.mask & HDI_FORMAT) { pCol->mask |= TVCF_FMT; pCol->fmt = sItem.fmt;
if(bWantMark && pData->aColumn[uCol].bMark) pCol->fmt |= TVCFMT_MARK; if(!pData->aColumn[uCol].sReal && pData->aColumn[uCol].sFixed) pCol->fmt |= TVCFMT_FIXED; } if(sItem.mask & HDI_IMAGE){ pCol->mask |= TVCF_IMAGE; pCol->iImage = sItem.iImage; } if(sItem.mask & HDI_WIDTH){ pCol->mask |= TVCF_WIDTH; pCol->cx = sItem.cxy; } if(sItem.mask & HDI_TEXT){ pCol->mask |= TVCF_TEXT; pCol->pszText = sItem.pszText; pCol->cchTextMax = sItem.cchTextMax; }
} else { lRet = 0; }
return lRet;
case TVM_SETFOCUSITEM: // Focus einstellen
pData = GetHandle(hWnd);
LOCK(pData); lRet = TreeListSetFocus(pData, U(lParam), U(wParam)); UNLOCK(pData);
return lRet;
case TVM_SETCOLUMNWIDTH: // Die Spaltenbreite einstellen
pData = GetHandle(hWnd);
if(pData->hHeader && U(wParam) < pData->uColumnCount && (int)lParam >= 0) { HDITEM sItem;
sItem.mask = HDI_WIDTH; sItem.cxy = (int)lParam; lRet = SendMessage(pData->hHeader, HDM_SETITEM, wParam, (LPARAM)&sItem); } else { lRet = 0; }
return lRet;
case TVM_COLUMNAUTOEDIT: // AutoEdit f�r eine Spalte einstellen
pData = GetHandle(hWnd); uVal = (wParam >> 11) & 0x3F;
if(uVal >= pData->uColumnCount) { return 0; }
uMode = (U(wParam) >> TVAE_MODEPOS) & 7;
if(uMode == TVAX_NONE) { wParam = 0; } else if(uVal == 0 && uMode >= TVAX_CHECK) { // Checkboxes are not allowed in the first column return 0; }
LOCK(pData);
uChange = pData->aColumn[uVal].bEdit << TVAE_MODEPOS; uChange |= pData->aColumn[uVal].bFlags & TVAE_STATEENABLE;
pData->aColumn[uVal].bEdit = (BYTE)(uMode); pData->aColumn[uVal].bFlags = (BYTE)(wParam); pData->aColumn[uVal].bCbChar = (BYTE)(wParam >> 17); pData->aColumn[uVal].bCbSize = (BYTE)(wParam >> 25); pData->aColumn[uVal].pCbData = (void *)lParam; pData->aColumn[uVal].iCbIcon = -1;
if(uMode >= TVAX_CHECK) { // Sollen Checkboxen dargestetllt werden if(!pData->hChecks) { CreateStateImageList(pData, 1); UpdateHeight(pData); }
if((uChange ^ wParam) & ((TVAE_MODEMASK ^ TVAE_CHECK ^ TVAE_CHECKED) | TVAE_STATEENABLE)) { UpdateColRect(pData, uVal); } } else if((uChange & TVAE_MODEMASK) >= TVAE_CHECK) { // Waren Checkboxen dargestetllt if((uChange ^ wParam) & ((TVAE_MODEMASK ^ TVAE_CHECK ^ TVAE_CHECKED) | TVAE_STATEENABLE)) { UpdateColRect(pData, uVal); } }
UNLOCK(pData);
return 1;
case TVM_COLUMNAUTOICON: // Icons f�r AutoEdit einstellen
pData = GetHandle(hWnd); uVal = U(wParam);
if(uVal >= pData->uColumnCount || !pData->aColumn[uVal].bEdit) { return 0; }
LOCK(pData);
pData->aColumn[uVal].iCbIcon = (int)lParam;
UNLOCK(pData);
return 1;
case TVM_GETCOLUMNWIDTH: // Die Spaltenbreite abfragen
pData = GetHandle(hWnd); if(pData->hHeader) { HDITEM sItem;
sItem.mask = HDI_WIDTH; sItem.cxy = (int)lParam; SendMessage(pData->hHeader, HDM_GETITEM, wParam, (LPARAM)&sItem); lRet = sItem.cxy; } else { lRet = 0; }
return lRet;
case TVM_CREATEDRAGIMAGE: // Ein Drag-Image erzeugen
pData = GetHandle(hWnd); LOCK(pData); lRet = (LRESULT)CreateDragImage(pData, U(lParam), U(wParam)); UNLOCK(pData); return lRet;
case TVM_ENDEDITLABELNOW: // Die aktuelle Eingabe abbrechen
pData = GetHandle(hWnd); LOCK(pData); lRet = (TreeListEndLabelEdit(pData, (wParam) ? 0 : 1)) ? 1 : 0; UNLOCK(pData); return 0;
case TVM_GETISEARCHSTRING: // Holt den aktuellen Suchtext
uDelta = GetTickCount() - uKeyLast;
if(!lParam) { return (uDelta <= 750) ? uKeyPos : 0; }
if(uDelta > 750) { ((TCHAR *)lParam)[0] = 0; return FALSE; }
memcpy((TCHAR *)lParam, cKeyData, uKeyPos * sizeof(TCHAR)); ((TCHAR *)lParam)[uKeyPos] = 0; return TRUE;
case TVM_GETUNICODEFORMAT: // Wird gerade UNI-Code verwendet
#if UNICODE return 1;#else return 0;#endif
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);}
//*****************************************************************************//*//* TreeListDraw//*//*****************************************************************************// Zeichnet das Fensterstatic void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect) {
COLORREF uEcColor; COLORREF uEvColor; COLORREF uBkColor; COLORREF uBtColor; COLORREF uOdColor; COLORREF uOcColor; COLORREF uFrColor; COLORREF uInColor; COLORREF uOldColor; COLORREF uOutColor; COLORREF uNextColor; COLORREF uTempColor; HRGN hRgnMain; HRGN aRgn[MAX_COLUMNS + 1]; SIZE sSize; RECT sRect; RECT sArea; RECT sButton; TreeListData *pData; BaseItem *pTemp; BaseItem *pEntry; ExtraItem *pExtra; LPCTSTR pText; HIMAGELIST hImgList; unsigned uTextSize; unsigned uRgnCount; unsigned uAutoMask; unsigned uFirstPos; unsigned uStyleEx; unsigned uColMark; unsigned uColumn; unsigned uState; unsigned uStyle; unsigned uExtra; unsigned uNext; unsigned uMark; unsigned uItem; unsigned uBits; unsigned uPos; unsigned uMax; int *pOffsets; int iRnType[MAX_COLUMNS + 1]; int iXscroll; int iHeight; int iIndent; int iDelta; int iImage; int iShift; int iStart; int iCount; int iLevel; int iLast; int iSize; int iXpos; int iYpos; int iMaxX; int iAdd; int i;
pData = GetHandle(hWnd);
LOCK(pData);
GetClientRect(hWnd, &sRect);
if(!pRect) pRect = &sRect;
iXscroll = -(int)pData->uScrollX; pOffsets = pData->aColumnXpos; hRgnMain = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
uMax = pData->uColumnCount; if(!uMax) { aRgn [ 0 ] = CreateRectRgn(sRect.left, sRect.top, sRect.right, sRect.bottom); iRnType[ 0 ] = CombineRgn(aRgn[0], aRgn[0], hRgnMain, RGN_AND); uRgnCount = 1; } else { for(uPos = 0; uPos < uMax; uPos++) { uExtra = pData->aColumnPos[uPos ]; uNext = pData->aColumnPos[uPos + 1]; aRgn [uExtra] = CreateRectRgn(sRect.left + pOffsets[uExtra] + iXscroll, sRect.top, sRect.left + pOffsets[uNext] + iXscroll, sRect.bottom); iRnType[uExtra] = CombineRgn(aRgn[uExtra], aRgn[uExtra], hRgnMain, RGN_AND); }
aRgn [uPos] = CreateRectRgn(sRect.left + pOffsets[uPos] + iXscroll, sRect.top, sRect.right, sRect.bottom); iRnType[uPos] = CombineRgn(aRgn[uPos], aRgn[uPos], hRgnMain, RGN_AND);
uRgnCount = uMax + 1; } iHeight = pData->iRowHeight; uStyleEx = pData->uStyleEx; uStyle = pData->uStyle; iIndent = pData->iIndent; iShift = pData->iShift; uPos = pData->uScrollY; uMax = pData->uMaxEnties + uPos; uNext = (pData->uColumnCount <= 1) ? 1 : pData->aColumn[1].bIndex; uFirstPos = pData->aColumnXpos[uNext];
if(iRnType[0] == NULLREGION) iMaxX = pData->iMaxSizeX; else iMaxX = uFirstPos - 1;
if(uStyleEx & TVS_EX_ITEMLINES) { iHeight--; }
if(uStyleEx & TVS_EX_AUTOEXPANDICON) { uAutoMask = TVIS_EXPANDED; } else { uAutoMask = 0; }
if(uMax > pData->uItemPosCount) { uMax = pData->uItemPosCount; }
uBkColor = pData->uColors[TVC_BK ]; uFrColor = pData->uColors[TVC_FRAME];
if(pData->uStyleEx & TVS_EX_ALTERNATECOLOR) { // Abwechselnde Farben uOdColor = pData->uColors[TVC_ODD ]; uEvColor = pData->uColors[TVC_EVEN ]; uOcColor = pData->uColors[TVC_COLODD ]; uEcColor = pData->uColors[TVC_COLEVEN]; } else { uOdColor = uBkColor; uEvColor = uBkColor; uOcColor = pData->uColors[TVC_COLBK]; uEcColor = pData->uColors[TVC_COLBK]; }
if(!pData->cIsEnabled) // Wenn Fenster gessperrt grau zeichnen if(pData->uStyleEx & TVS_EX_GRAYEDDISABLE) { uBkColor = pData->uColors[TVC_GRAYED]; uEvColor = uEcColor; uOdColor = uOcColor; }
uInColor = pData->uColors[TVC_LINE]; uBtColor = pData->uColors[TVC_BOX ]; iStart = 0; iLast = 0; sArea.top = sRect.top + pData->uStartPixel; SelectObject(hDc, pData->hFontN); SelectObject(hDc, hPatternPen); SetBkColor(hDc, uBkColor); SetBkMode(hDc, TRANSPARENT); SetTextAlign(hDc, TA_LEFT | TA_TOP); SetTextColor(hDc, pData->uColors[TVC_TEXT]);
//******************** Eintr�ge zeichnen ************************************** for(; uPos < uMax; uPos++) { // Alle Eintr�ge ausgeben uItem = pData->pItemPos[uPos];
pEntry = pData->pTreeItems[uItem]; if(!pEntry) break;
if((pEntry->uState & TVIS_SELECTED) && (uStyleEx & TVS_EX_FULLROWMARK)) { if(uStyleEx & TVS_EX_ALTERNATECOLOR) uOutColor = (uPos & 1) ? pData->uColors[TVC_MARKODD] : pData->uColors[TVC_MARKEVEN]; else uOutColor = pData->uColors[TVC_MARK];
uMark = (unsigned)~TVIS_BKCOLOR; uColMark = 0; } else if(uPos & 1) { // Farbe wechselweise �ndern uColMark = pData->aColumn[0].bMark; uOutColor = (uColMark) ? uOcColor : uOdColor; uMark = 0xFFFFFFFF; } else { uColMark = pData->aColumn[0].bMark; uOutColor = (uColMark) ? uEcColor : uEvColor; uMark = 0xFFFFFFFF; }
sArea.bottom = sArea.top + pData->iRowHeight; sArea.left = iXscroll; iLevel = pEntry->uLevel;
if(iRnType[0] == NULLREGION) { goto ExtraDraw; }
uBits = pEntry->uState & 0xFFFF; uBits |= pEntry->bFlags << 16; uBits &= uMark; iImage = (uBits & LVIS_SELECTED) ? pEntry->iSelectedImage : pEntry->iImage; pText = pEntry->pText; uTextSize = pEntry->uTextSize;
if(pData->uSelectedSub && uItem == pData->uSelectedItem) { if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_SUBSELECT)) { uBits &= ~TVIS_SELECTED; } }
if(pEntry->bCallback) { CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTextSize, &pText);
pEntry = pData->pTreeItems[uItem]; if(!pEntry) break; }
SelectObject(hDc, aRgn[0]);
if((uStyleEx & (TVS_EX_ITEMLINES | TVS_EX_FULLROWITEMS)) == (TVS_EX_ITEMLINES | TVS_EX_FULLROWITEMS)) { sButton.left = 0; sButton.right = iIndent * (iLevel + 1) + 2; sButton.bottom = sArea.bottom + 1; sButton.top = sArea.bottom - 2;
SetBkColor(hDc, uFrColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL); }
if(pData->aColumn[0].bMark) { // Ist die erste Spalte markiert uBkColor = pData->uColors[TVC_COLBK]; }
SetBkColor(hDc, (uStyleEx & TVS_EX_FULLROWITEMS) ? uOutColor : uBkColor);
if(pData->cHasRootRow) iLevel++;
if(iLevel <= 0) goto NoRootLines;
if(uStyle & (TVS_HASBUTTONS | TVS_HASLINES)) { iLevel--; }
if(uStyleEx & TVS_EX_FULLROWITEMS) { sArea.bottom--; iAdd = 1; } else { iAdd = 0; }
if(uStyle & TVS_HASLINES) { pTemp = pData->pTreeItems[pEntry->uParent]; sArea.right = sArea.left + 1; // Eine leerer Pixelreihe am Anfang ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.left += iIndent * iLevel + 1;
for(i = iLevel; i > 0; i--) { // Bereich vor Schaltfl�chen sArea.right = sArea.left; sArea.left -= iIndent;
ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
iXpos = sArea.left + iShift;
if(pTemp) { if(pTemp->uNextItem) { // Zeichne vertikale Linien MoveToEx(hDc, iXpos, sArea.top | 1, NULL); LineTo(hDc, iXpos, sArea.bottom + iAdd); }
pTemp = pData->pTreeItems[pTemp->uParent]; } }
sArea.left += iIndent * iLevel; } else { // Ohne Linien zeichnen if(iLevel > 0) { sArea.right = sArea.left + iIndent * iLevel; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.left += sArea.right; } }
if(uStyle & TVS_HASBUTTONS) { // Fenster mit Schaltfl�chen ? sArea.right = sArea.left + iIndent; iXpos = sArea.left + iShift; iYpos = sArea.top + pData->iRowHeight / 2;
ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
if(uStyle & TVS_HASLINES) { // Linien unter Schaltfl�chen MoveToEx(hDc, iXpos, sArea.top | 1, NULL);
if(pEntry->uNextItem) LineTo(hDc, iXpos, sArea.bottom + iAdd); else LineTo(hDc, iXpos, iYpos + 1);
MoveToEx(hDc, iXpos + 1 + (iYpos & 1), iYpos, NULL); LineTo(hDc, sArea.right , iYpos); }
if(pEntry->bFlags & TVIX_HASBUTTON) { // Schaltfl�chen zeichnen sButton.left = iXpos - 4; sButton.top = iYpos - 4; sButton.right = iXpos + 5; sButton.bottom = iYpos + 5;
if(pData->cGlyphOk) { // Thema benutzen uState = ((uBits ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) ? GLPS_CLOSED : GLPS_OPENED; pDrawThemeBackg(pData->hTheme, hDc, TVP_GLYPH, uState, &sButton, 0); } else { SetBkColor(hDc, uBtColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
sButton.left += 1; sButton.top += 1; sButton.right -= 1; sButton.bottom -= 1;
SetBkColor(hDc, pData->uColors[TVC_BOXBG]); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
sButton.left = iXpos - 2; sButton.top = iYpos ; sButton.right = iXpos + 3; sButton.bottom = iYpos + 1;
SetBkColor(hDc, uInColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
// '+' statt '-' Schaltfl�sche zeichnenen if((uBits ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) { sButton.left = iXpos ; sButton.top = iYpos - 2; sButton.right = iXpos + 1; sButton.bottom = iYpos + 3; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL); } }
SetBkColor(hDc, uBkColor); }
sArea.left += iIndent; } else if(uStyle & TVS_HASLINES) { // Nur Linien zeichnen ohne Schaltfl�chen sArea.right = sArea.left + iIndent; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
iYpos = sArea.top + pData->iRowHeight / 2; iXpos = sArea.left + iShift; MoveToEx(hDc, iXpos, sArea.top | 1, NULL);
if(pEntry->uNextItem) LineTo(hDc, iXpos, sArea.bottom); else LineTo(hDc, iXpos, iYpos + 1);
MoveToEx(hDc, iXpos + 1 + (iYpos & 1), iYpos, NULL); LineTo(hDc, sArea.right , iYpos);
sArea.left += iIndent; }
if(uStyleEx & TVS_EX_FULLROWITEMS) sArea.bottom++;
NoRootLines:
if(uStyleEx & TVS_EX_ITEMLINES) { // Linien um den Eintrag zeichnen iAdd = 1; sArea.right = sArea.left + 1;
if(uStyleEx & TVS_EX_FULLROWITEMS) { iStart = sArea.left; iAdd = 0; } else if(iLevel >= 0) { SetBkColor(hDc, uFrColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
sArea.left++; sArea.bottom--; iStart = sArea.left; } else { ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
sArea.left++; sArea.bottom--; iStart = sArea.left - 1; } } else { iAdd = 0; }
SetBkColor(hDc, (uBits & TVIS_BKCOLOR) ? pEntry->uColorBk : uOutColor); SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
if(pData->hStates) { // State-Icons anzeigen sArea.right = sArea.left + pData->iStatesXsize; iYpos = sArea.top + (iHeight - pData->iStatesYsize) / 2; i = (uBits & LVIS_STATEIMAGEMASK) >> 12;
sArea.right += iAdd; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.left += iAdd;
if(pData->hStates == THEMEIMGLIST) { // Mit Thema zeichnen if(pData->uStyleEx & TVS_EX_BITCHECKBOX) i++;
if(i >= 1 && i <= 2) { uState = (i == 1) ? CBS_UNCHECKEDNORMAL : CBS_CHECKEDNORMAL; pDrawThemeBackg(pData->hThemeBt, hDc, BP_CHECKBOX, uState, &sArea, 0); } } else { ImageList_Draw(pData->hStates, i, hDc, sArea.left, iYpos, ILD_TRANSPARENT); }
sArea.left += pData->iStatesXsize; iAdd = 0; }
if(pData->hImages && iImage != TV_NOIMAGE) { // Icon zeichnen vom Haupteintrag if(iImage >= TV_SECONDICON) { // Sub-Image-Liste verwenden if(iImage & TV_NOAUTOEXPAND) { iImage &= ~TV_NOAUTOEXPAND; // Kein Auto-Expant bei diesem Icon } else if((pEntry->uState & uAutoMask) && pEntry->uFirstChild) { iImage += 1; // Auto-Expant aktivieren }
iImage -= TV_SECONDICON; sArea.right = sArea.left + pData->iSubImgXsize; iYpos = sArea.top + (iHeight - pData->iSubImgYsize) / 2; pEntry->bFlags |= TVIX_HASIMAGE;
sArea.right += iAdd; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.left += iAdd; ImageList_Draw(pData->hSubImg, iImage, hDc, sArea.left, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT)));
sArea.left += pData->iSubImgXsize; iAdd = 0; } else { // Haup-Image-Liste verwenden if(iImage & TV_NOAUTOEXPAND) { iImage &= ~TV_NOAUTOEXPAND; // Kein Auto-Expant bei diesem Icon } else if((pEntry->uState & uAutoMask) && pEntry->uFirstChild) { iImage += pData->iAutoAdd; // Auto-Expant aktivieren }
sArea.right = sArea.left + pData->iImagesXsize; iYpos = sArea.top + (iHeight - pData->iImagesYsize) / 2; pEntry->bFlags |= TVIX_HASIMAGE;
sArea.right += iAdd; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.left += iAdd; ImageList_Draw(pData->hImages, iImage, hDc, sArea.left, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT)));
sArea.left += pData->iImagesXsize; iAdd = 0; } } else { pEntry->bFlags &= ~TVIX_HASIMAGE; }
sArea.right = uFirstPos; // Text ausgeben vom Haupteintrag iYpos = sArea.top + (iHeight - pData->iFontHeight) / 2;
if(uBits & (TVIS_SELECTED | TVIS_DROPHILITED | TVIS_UNDERLINE | TVIS_TRACKED | TVIS_TEXTCOLOR | TVIS_FOCUSED)) { // Das Feld speziel zeichnen TCHAR *pPtr = (TCHAR *)new(TCHAR, uTextSize + 4); INT *pPos = (INT *)new(INT, uTextSize + 4);
ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sArea, NULL, 0, NULL);
sButton.top = iYpos; sButton.left = sArea.left + 4; sButton.right = sArea.right; sButton.bottom = iYpos + pData->iFontHeight + 2;
if(!uTextSize) { // Feld ohne Text ? sButton.right -= 2; sButton.bottom--; pEntry->iTextPixels = 0; } else { if(pData->uStyleEx & TVS_EX_FULLROWMARK) if(pData->cHasFocus == 0 || uItem != pData->uSelectedItem || pData->uSelectedSub) if((uBits & TVIS_SELECTED) && !(uBits & (TVIS_DROPHILITED | TVIS_FOCUSED))) { sButton.left -= 1; }
DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); pEntry->iTextPixels = sButton.right - sButton.left; }
// Passt der Text in die Spalte if(sButton.left + pEntry->iTextPixels >= (int)(sArea.right - pData->uScrollX)) { iSize = sArea.right - pData->uScrollX - sButton.left - 2; iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN; if(iSize < 3) { iCount = 0; } else { GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize); } // Tempor�ren Text mit "..." erzeugen memcpy(pPtr , pText, iCount * sizeof(TCHAR)); memcpy(pPtr + iCount, _T("..."), 4 * sizeof(TCHAR));
pText = pPtr; uTextSize = iCount + 3; sButton.right = sArea.right - 2; }
// Das Feld selektiert zeichnen if((uBits & TVIS_SELECTED) && pData->cHasFocus && uItem == pData->uSelectedItem && !pData->uSelectedSub) { uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else { if(uBits & TVIS_DROPHILITED) { uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); SelectObject(hDc, GetStockObject(NULL_PEN)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else if(uBits & TVIS_SELECTED) { // Ist das Feld ohne Focus ausgew�hlt if(pData->cHasFocus) { uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); SelectObject(hDc, GetStockObject(NULL_PEN)); } else { if(uBits & TVIS_TEXTCOLOR) uTempColor = pEntry->uColorText; else uTempColor = pData ->uColors[TVC_TEXT];
if(pData->uStyleEx & TVS_EX_FULLROWMARK) SelectObject(hDc, GetStockObject(NULL_BRUSH)); else SelectObject(hDc, GetSysColorBrush(COLOR_3DFACE));
SelectObject(hDc, GetStockObject(NULL_PEN)); }
Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else { // Das Feld normal zeichnen if(uBits & TVIS_TRACKED) uTempColor = pData ->uColors[TVC_TRACK]; else if(uBits & TVIS_TEXTCOLOR) uTempColor = pEntry->uColorText; else uTempColor = pData ->uColors[TVC_TEXT ]; sButton.right--; sButton.left --; }
SelectObject(hDc, hPatternPen);
if(uBits & TVIS_FOCUSED) { // Einen punktierten Rahmen um den Text zeichnen SelectObject(hDc, GetStockObject(NULL_BRUSH)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } }
SetTextColor(hDc, uTempColor); sButton.left += pData->iFontOff; DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
if(uBits & (TVIS_UNDERLINE | TVIS_TRACKED)) // Text unterstreichen if(pText && *pText) { sButton.left -= pData->iFontOff; sButton.right -= pData->iFontOff + 1; sButton.top += pData->iFontLine; sButton.bottom = sButton.top + 1; uOldColor = SetBkColor(hDc, uTempColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sButton, NULL, 0, NULL); SetBkColor(hDc, uOldColor); }
SetTextColor(hDc, pData->uColors[TVC_TEXT]);
delete(pPos); delete(pPtr); } else { // Das Feld normal ausgeben if(!pEntry->iTextPixels && uTextSize) { sButton.top = iYpos; sButton.left = sArea.left + 4; sButton.right = sArea.right; sButton.bottom = iYpos + pData->iFontHeight + 2; // Textbreite berechen DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
pEntry->iTextPixels = sButton.right - sButton.left; }
// Ist der Text gr��er als die Spalte if(sArea.left + pEntry->iTextPixels >= (int)(sArea.right - pData->uScrollX)) { INT *pPos = (INT *)new(INT, uTextSize);
iSize = sArea.right - sArea.left - pData->uScrollX; iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN; if(iSize < 3) { iCount = 0; } else { GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize); }
if(iCount > 0) { // Passen noch Buchstaben vor "..." sButton.right = sArea.right; sArea.right = sArea.left + 2 + pPos[iCount - 1];
ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, iCount, NULL);
sArea.left = sArea.right; sArea.right = sButton.right;
ExtTextOut(hDc, sArea.left , iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL); } else { ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL); }
delete(pPos); } else { ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL); } }
i = sArea.left - iXscroll; i += pEntry->iTextPixels + 5; if(i > iMaxX) iMaxX = i;
if(uStyleEx & TVS_EX_ITEMLINES) { // Linien um den Eintrag zeichnen SetBkColor(hDc, uFrColor);
if(iLast > iStart) { // Ist das Feld nach links einger�ckt gegen�ber dem oberen sArea.top--; sArea.bottom = sArea.top + 1; sArea.left = iStart - 1; ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); sArea.top++; }
iLast = iStart; // Linie unter Feld zeichnen sArea.top += iHeight; sArea.left = iStart; sArea.bottom = sArea.top + 1;
ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
sArea.top -= iHeight; }
//************ Extraeintr�ge zeichnen *********************************
ExtraDraw:
uNextColor = uOutColor; // Hintergrundfarbe f�r die n�chste Spalte
if(pData->aColumn[0].bMark) { // Ist die erste Spalte markiert uBkColor = pData->uColors[TVC_BK]; }
for(uColumn = 1; uColumn <= pData->uColumnCount; uColumn++) { // Extra Spalten zeichnen uExtra = pData->aColumnPos[uColumn ]; uNext = pData->aColumnPos[uColumn + 1];
if(pData->aColumn[uExtra].sReal == 0) // Ist die Spalte sichtbar if(uColumn < pData->uColumnCount) { continue; }
if(uColMark != pData->aColumn[uExtra].bMark) // Ist die Spalte anderst markiert if(!(pEntry->uState & TVIS_SELECTED) || !(uStyleEx & TVS_EX_FULLROWMARK)) { if(uPos & 1) { uColMark = pData->aColumn[uExtra].bMark; uOutColor = (uColMark) ? uOcColor : uOdColor; } else { uColMark = pData->aColumn[uExtra].bMark; uOutColor = (uColMark) ? uEcColor : uEvColor; } }
GetRgnBox(aRgn[uExtra], &sButton);
if(iRnType[uExtra] == NULLREGION) continue;
SelectObject(hDc, aRgn[uExtra]);
sArea.left = pData->aColumnXpos[uExtra]; sArea.left += iXscroll;
if(uStyleEx & TVS_EX_ITEMLINES) { // Linie um den Eintrag zeichnen SetBkColor(hDc, uFrColor); // Linke Linie sArea.right = sArea.left + 1; sArea.bottom += 1;
ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
sArea.left += 1; // Untere Linie sArea.top += iHeight; sArea.bottom = sArea.top + 1; sArea.right = pData->aColumnXpos[uNext]; if(uColumn < pData->uColumnCount) sArea.right += iXscroll;
ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
sArea.top -= iHeight; sArea.bottom -= 1; iAdd = 1; }
if(sArea.left > (int)pData->uSizeX) break; // Noch im sichtbaren Bereich
sArea.right = pData->aColumnXpos[uNext];
if(uColumn < pData->uColumnCount) { // Ist es die letze Spalte ? sArea.right += iXscroll; pExtra = pData->pExtraItems[uExtra - 1][uItem]; if(!pExtra) uNextColor = uOutColor; } else { pExtra = 0; }
if(!pExtra) { // Leeres Feld zeichnen SetBkColor(hDc, uNextColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL); } else { iSize = pData->iSubImgXsize; hImgList = pData->hSubImg; iImage = pExtra->iImage; pText = pExtra->pText; uTextSize = pExtra->uTextSize; uBits = (pExtra->uState & 0xFFFF); uBits |= (pExtra->bFlags << 16); uBits |= pEntry->uState & TVIS_BASEFLAGS; uBits &= uMark;
if(uExtra != pData->uSelectedSub) { uBits &= ~TVIS_SELECTED; }
if(pExtra->bCallback) { // Text �ber Callback holen CallbackExtra(pData, pEntry, pExtra, uItem, uExtra, pExtra->bCallback, &iImage, &uTextSize, &pText); pExtra = pData->pExtraItems[uExtra - 1][uItem]; if(!pExtra) break; }
uNextColor = (uBits & TVIS_BKCOLOR) ? pExtra->uColorBk : uOutColor; SetBkColor(hDc, uNextColor);
if(pData->aColumn[uExtra].bEdit >= TVAX_CHECK) { // Checkboxen statt Icons hImgList = pData->hChecks; iSize = pData->iChecksXsize; iImage = (pExtra->uState & TVIS_STATEIMAGEMASK) >> 12; uBits &= ~TVIS_OVERLAYMASK;
if(iImage & 8) if(pData->aColumn[uExtra].bFlags & TVAE_STATEENABLE) { iImage &= 7; } }
if(hImgList && iImage > TV_NOIMAGE) { // Icon zeichnen sArea.right = sArea.left + iSize + 2; iYpos = sArea.top + (iHeight - iSize) / 2; pExtra->bFlags |= TVIX_HASIMAGE;
SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
if(hImgList == THEMEIMGLIST) { // Mit Thema zeichnen if(pData->uStyleEx & TVS_EX_BITCHECKBOX) iImage++;
if(iImage == 1 || iImage == 2) { uState = (iImage == 1) ? CBS_UNCHECKEDNORMAL : CBS_CHECKEDNORMAL; pDrawThemeBackg(pData->hThemeBt, hDc, BP_CHECKBOX, uState, &sArea, 0); } } else { ImageList_Draw(hImgList, iImage, hDc, sArea.left + 1, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT))); }
sArea.left += iSize + 1; sArea.right = pData->aColumnXpos[uNext]; sArea.right += iXscroll; } else { pExtra->bFlags &= ~TVIX_HASIMAGE; }
iYpos = sArea.top + (iHeight - pData->iFontHeight) / 2; SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
if(uBits & (TVIS_SELECTED | TVIS_DROPHILITED | TVIS_UNDERLINE | TVIS_TRACKED | TVIS_TEXTCOLOR | TVIS_FOCUSED)) { // Text ausgeben in spezilem Format TCHAR *pPtr = (TCHAR *)new(TCHAR, uTextSize + 4); INT *pPos = (INT *)new(INT, uTextSize + 4);
ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sArea, NULL, 0, NULL);
sButton.top = iYpos; sButton.left = sArea.left + 4; sButton.right = sArea.right; sButton.bottom = iYpos + pData->iFontHeight + 2;
if(!uTextSize) { sButton.left--; sButton.right -= 2; sButton.bottom--; pExtra->iTextPixels = 0; } else { if(pData->uStyleEx & TVS_EX_FULLROWMARK) if(pData->cHasFocus == 0 || uItem != pData->uSelectedItem) if((uBits & TVIS_SELECTED) && !(uBits & (TVIS_DROPHILITED | TVIS_FOCUSED))) { sButton.left -= 2; }
DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); pExtra->iTextPixels = sButton.right - sButton.left; }
// Passt der Text in die Spalte if(sButton.left + pExtra->iTextPixels >= sArea.right) { if(uTextSize > 253) uTextSize = 253;
iSize = sArea.right - sButton.left - 2; iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN; if(iSize < 3) { iCount = 0; } else { GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize); }
memcpy(pPtr , pText, iCount * sizeof(TCHAR)); memcpy(pPtr + iCount, _T("..."), 4 * sizeof(TCHAR));
pText = pPtr; uTextSize = iCount + 3; sButton.right = sArea.right - 2; }
switch(pData->aColumn[uExtra].bAlign) { // Textausrichtung ausgleichen case DT_CENTER: iDelta = sArea .right - sArea .left; iDelta -= sButton.right - sButton.left; iDelta -= 6; iDelta /= 2; sButton.right += iDelta; sButton.left += iDelta; break;
case DT_RIGHT: iDelta = sArea .right - sArea .left; iDelta -= sButton.right - sButton.left; iDelta -= 6; sButton.right += iDelta; sButton.left += iDelta; break;
} // Ist das Feld ohne Focus ausgew�hlt if((uBits & TVIS_SELECTED) && pData->cHasFocus && uItem == pData->uSelectedItem) { uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else { if(uBits & TVIS_DROPHILITED) { uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT); SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT)); SelectObject(hDc, GetStockObject(NULL_PEN)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else if(uBits & TVIS_SELECTED && uItem == pData->uSelectedItem) { if(uBits & TVIS_TEXTCOLOR) uTempColor = pEntry->uColorText; else uTempColor = pData->uColors[TVC_TEXT];
if(pData->uStyleEx & TVS_EX_FULLROWMARK) SelectObject(hDc, GetStockObject(NULL_BRUSH)); else SelectObject(hDc, GetSysColorBrush(COLOR_3DFACE));
SelectObject(hDc, GetStockObject(NULL_PEN)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } else { if(uBits & TVIS_TRACKED) uTempColor = pData ->uColors[TVC_TRACK]; else if(uBits & TVIS_TEXTCOLOR) uTempColor = pExtra->uColorText; else uTempColor = pData ->uColors[TVC_TEXT ]; sButton.right--; sButton.left --; }
SelectObject(hDc, hPatternPen);
if(uBits & TVIS_FOCUSED) { // Punktierten Rahmen um Text zeichnen SelectObject(hDc, GetStockObject(NULL_BRUSH)); Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1); } }
SetTextColor(hDc, uTempColor); sButton.left += pData->iFontOff;
DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
if(uBits & (TVIS_UNDERLINE | TVIS_TRACKED)) // Text unterstreichen if(pText && *pText) { sButton.left -= pData->iFontOff; sButton.right -= pData->iFontOff + 1; sButton.top += pData->iFontLine; sButton.bottom = sButton.top + 1; uOldColor = SetBkColor(hDc, uTempColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sButton, NULL, 0, NULL); SetBkColor(hDc, uOldColor); }
SetTextColor(hDc, pData->uColors[TVC_TEXT]);
delete(pPos); delete(pPtr); } else { // Den Text ganz normal ausgeben if(!pExtra->iTextPixels) { sButton.top = iYpos; sButton.left = sArea.left + 4; sButton.right = sArea.right; sButton.bottom = iYpos + pData->iFontHeight + 2;
if(uTextSize) { // Textbreite berechen DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); pExtra->iTextPixels = sButton.right - sButton.left; } else { pExtra->iTextPixels = 0; } } // Ist der Text gr��er als die Spalte if(sArea.left + pExtra->iTextPixels >= sArea.right) { INT *pPos = (INT *)new(INT, uTextSize);
iSize = sArea.right - sArea.left; iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN; if(iSize < 3) { iCount = 0; } else { GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize); }
if(iCount > 0) { // Passen noch Buchstaben vor "..." sButton.right = sArea.right; sArea.right = sArea.left + 2 + pPos[iCount - 1];
ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, iCount, NULL);
sArea.left = sArea.right; sArea.right = sButton.right;
ExtTextOut(hDc, sArea.left , iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL); } else { ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL); }
delete(pPos); } else { switch(pData->aColumn[uExtra].bAlign) { // Textausrichtung case DT_CENTER: SetTextAlign(hDc, TA_CENTER | TA_TOP); ExtTextOut(hDc, (sArea.right + sArea.left) / 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL); SetTextAlign(hDc, TA_LEFT | TA_TOP); break;
case DT_RIGHT: SetTextAlign(hDc, TA_RIGHT | TA_TOP); ExtTextOut(hDc, sArea.right - 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL); SetTextAlign(hDc, TA_LEFT | TA_TOP); break;
default : ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL); break; } } } } }
sArea.top += pData->iRowHeight; }
if(sArea.top < sRect.bottom) { // Untere Fl�che ohne Eintr�ge f�llen SelectObject(hDc, hRgnMain);
// Gibt es markierte Spalten if(pData->uMarkedCols > 0 && (pData->cIsEnabled || !(pData->uStyleEx & TVS_EX_GRAYEDDISABLE))) { sRect.right = 0 - pData->uScrollX;
for(uColumn = 0; uColumn < pData->uColumnCount; uColumn++) { uExtra = pData->aColumnPos[uColumn ]; uNext = pData->aColumnPos[uColumn + 1]; uMark = pData->aColumn[uExtra].bMark; sRect.top = sArea.top; sRect.left = sRect.right; sRect.right = pData->aColumnXpos[uNext] + uMark; sRect.right -= pData->uScrollX; if(sRect.right == sRect.left + 1) uMark = 0; SetBkColor(hDc, (uMark) ? pData->uColors[TVC_COLBK] : uBkColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL); }
sRect.top = sArea.top; sRect.left = sRect.right; sRect.right = pData->uSizeX; SetBkColor(hDc, uBkColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL); } else { // Keine markierten Spalten sRect.top = sArea.top; SetBkColor(hDc, uBkColor); ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL); } }
if(pData->iMaxSizeX != iMaxX) { // X-Scrollbar aktuallisieren pData->iMaxSizeX = iMaxX; if(pData->uColumnCount == 0) if(pData->iMaxSizeX != (int)pData->uOldXCount) { UpdateScrollX(pData); } }
UNLOCK(pData);
DeleteObject(hRgnMain);
for(uPos = 0; uPos < uRgnCount; uPos++) { DeleteObject(aRgn[uPos]); }
}