123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158 |
- { MP }
- unit TB2Item;
- {
- Toolbar2000
- Copyright (C) 1998-2005 by Jordan Russell
- All rights reserved.
- The contents of this file are subject to the "Toolbar2000 License"; you may
- not use or distribute this file except in compliance with the
- "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
- TB2k-LICENSE.txt or at:
- https://jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
- Alternatively, the contents of this file may be used under the terms of the
- GNU General Public License (the "GPL"), in which case the provisions of the
- GPL are applicable instead of those in the "Toolbar2000 License". A copy of
- the GPL may be found in GPL-LICENSE.txt or at:
- https://jrsoftware.org/files/tb2k/GPL-LICENSE.txt
- If you wish to allow use of your version of this file only under the terms of
- the GPL and not to allow others to use your version of this file under the
- "Toolbar2000 License", indicate your decision by deleting the provisions
- above and replace them with the notice and other provisions required by the
- GPL. If you do not delete the provisions above, a recipient may use your
- version of this file under either the "Toolbar2000 License" or the GPL.
- $jrsoftware: tb2k/Source/TB2Item.pas,v 1.277 2005/06/23 21:55:44 jr Exp $
- }
- interface
- {$I TB2Ver.inc}
- {x$DEFINE TB2K_NO_ANIMATION}
- { Enabling the above define disables all menu animation. For debugging
- purpose only. }
- {x$DEFINE TB2K_USE_STRICT_O2K_MENU_STYLE}
- { Enabling the above define forces it to use clBtnFace for the menu color
- instead of clMenu, and disables the use of flat menu borders on Windows
- XP with themes enabled. }
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, CommCtrl, Menus, ActnList, ImgList, TB2Anim, UITypes;
- const
- WM_TB2K_POPUPSHOWING = WM_USER + 554;
- { Parameter in LParam of WM_TB2K_POPUPSHOWING }
- TPS_ANIMSTART = 1; // animation query: if Result <> 0, do not animate!
- TPS_ANIMFINISHED = 2; // only fired when animation thread is done
- TPS_NOANIM = 3; // fired when animation is done, or if showing with no animation
- type
- TTBCustomItem = class;
- TTBCustomItemClass = class of TTBCustomItem;
- TTBCustomItemActionLink = class;
- TTBCustomItemActionLinkClass = class of TTBCustomItemActionLink;
- TTBItemViewer = class;
- TTBItemViewerClass = class of TTBItemViewer;
- TTBPopupWindow = class;
- TTBPopupWindowClass = class of TTBPopupWindow;
- TTBView = class;
- TTBDoneAction = (tbdaNone, tbdaCancel, tbdaClickItem, tbdaOpenSystemMenu,
- tbdaHelpContext { MP }, tbdaHelpKeyword { /MP });
- PTBDoneActionData = ^TTBDoneActionData;
- TTBDoneActionData = record
- DoneAction: TTBDoneAction;
- case TTBDoneAction of
- tbdaClickItem: (ClickItem: TTBCustomItem; Sound: Boolean);
- tbdaOpenSystemMenu: (Wnd: HWND; Key: Cardinal);
- tbdaHelpContext: (ContextID: Integer);
- { MP }
- tbdaHelpKeyword: (HelpKeyword: String[100]);
- end;
- TTBInsertItemProc = procedure(AParent: TComponent; AItem: TTBCustomItem) of object;
- TTBItemChangedAction = (tbicInserted, tbicDeleting, tbicSubitemsChanged,
- tbicSubitemsBeginUpdate, tbicSubitemsEndUpdate, tbicInvalidate,
- tbicInvalidateAndResize, tbicRecreateItemViewers, tbicNameChanged,
- tbicSubMenuImagesChanged);
- TTBItemChangedProc = procedure(Sender: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem) of object;
- TTBItemData = record
- Item: TTBCustomItem;
- end;
- PTBItemDataArray = ^TTBItemDataArray;
- TTBItemDataArray = array[0..$7FFFFFFF div SizeOf(TTBItemData)-1] of TTBItemData;
- TTBItemDisplayMode = (nbdmDefault, nbdmTextOnly, nbdmTextOnlyInMenus, nbdmImageAndText);
- TTBItemOption = (tboDefault, tboDropdownArrow, tboImageAboveCaption,
- tboLongHintInMenuOnly, tboNoAutoHint, tboNoRotation, tboSameWidth,
- tboShowHint, tboToolbarStyle, tboToolbarSize);
- TTBItemOptions = set of TTBItemOption;
- TTBItemStyle = set of (tbisSubmenu, tbisSelectable, tbisSeparator,
- tbisEmbeddedGroup, tbisClicksTransparent, tbisCombo, tbisNoAutoOpen,
- tbisSubitemsEditable, tbisNoLineBreak, tbisRightAlign, tbisDontSelectFirst,
- tbisRedrawOnSelChange, tbisRedrawOnMouseOverChange, tbisStretch);
- TTBPopupAlignment = (tbpaLeft, tbpaRight, tbpaCenter);
- TTBPopupEvent = procedure(Sender: TTBCustomItem; FromLink: Boolean) of object;
- TTBSelectEvent = procedure(Sender: TTBCustomItem; Viewer: TTBItemViewer;
- Selecting: Boolean) of object;
- ETBItemError = class(Exception);
- TTBImageChangeLink = class(TChangeLink)
- private
- FLastWidth, FLastHeight: Integer;
- end;
- TTBPopupPositionRec = record
- PositionAsSubmenu: Boolean;
- Alignment: TTBPopupAlignment;
- Opposite: Boolean;
- MonitorRect: TRect;
- ParentItemRect: TRect;
- NCSizeX: Integer;
- NCSizeY: Integer;
- X, Y, W, H: Integer;
- AnimDir: TTBAnimationDirection;
- PlaySound: Boolean;
- end;
- TTBCustomItem = class(TComponent)
- private
- FActionLink: TTBCustomItemActionLink;
- FAutoCheck: Boolean;
- FCaption: String;
- FChecked: Boolean;
- FDisplayMode: TTBItemDisplayMode;
- FEnabled: Boolean;
- FEffectiveOptions: TTBItemOptions;
- FGroupIndex: Integer;
- FHelpContext: THelpContext;
- { MP }
- FHelpKeyword: String;
- FHint: String;
- FImageIndex: TImageIndex;
- FImages: TCustomImageList;
- FImagesChangeLink: TTBImageChangeLink;
- FItems: PTBItemDataArray;
- FItemCount: Integer;
- FItemStyle: TTBItemStyle;
- FLinkParents: TList;
- FMaskOptions: TTBItemOptions;
- FOptions: TTBItemOptions;
- FInheritOptions: Boolean;
- FNotifyList: TList;
- FOnClick: TNotifyEvent;
- FOnPopup: TTBPopupEvent;
- FOnSelect: TTBSelectEvent;
- FParent: TTBCustomItem;
- FParentComponent: TComponent;
- FRadioItem: Boolean;
- FShortCut: TShortCut;
- FSubMenuImages: TCustomImageList;
- FSubMenuImagesChangeLink: TTBImageChangeLink;
- FLinkSubitems: TTBCustomItem;
- FVisible: Boolean;
- procedure DoActionChange(Sender: TObject);
- function ChangeImages(var AImages: TCustomImageList;
- const Value: TCustomImageList; var AChangeLink: TTBImageChangeLink): Boolean;
- class procedure ClickWndProc(var Message: TMessage);
- function FindItemWithShortCut(AShortCut: TShortCut;
- var ATopmostParent: TTBCustomItem): TTBCustomItem;
- function FixOptions(const AOptions: TTBItemOptions): TTBItemOptions;
- function GetAction: TBasicAction;
- function GetItem(Index: Integer): TTBCustomItem;
- procedure ImageListChangeHandler(Sender: TObject);
- procedure InternalNotify(Ancestor: TTBCustomItem; NestingLevel: Integer;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- function IsAutoCheckStored: Boolean;
- function IsCaptionStored: Boolean;
- function IsCheckedStored: Boolean;
- function IsEnabledStored: Boolean;
- function IsHelpContextStored: Boolean;
- function IsHintStored: Boolean;
- function IsImageIndexStored: Boolean;
- function IsOnClickStored: Boolean;
- function IsShortCutStored: Boolean;
- function IsVisibleStored: Boolean;
- procedure Notify(Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- procedure RefreshOptions;
- procedure SetAction(Value: TBasicAction);
- procedure SetCaption(Value: String);
- procedure SetChecked(Value: Boolean);
- procedure SetDisplayMode(Value: TTBItemDisplayMode);
- procedure SetEnabled(Value: Boolean);
- procedure SetGroupIndex(Value: Integer);
- procedure SetImageIndex(Value: TImageIndex);
- procedure SetImages(Value: TCustomImageList);
- procedure SetInheritOptions(Value: Boolean);
- procedure SetLinkSubitems(Value: TTBCustomItem);
- procedure SetMaskOptions(Value: TTBItemOptions);
- procedure SetOptions(Value: TTBItemOptions);
- procedure SetRadioItem(Value: Boolean);
- procedure SetSubMenuImages(Value: TCustomImageList);
- procedure SetVisible(Value: Boolean);
- procedure SubMenuImagesChanged;
- procedure TurnSiblingsOff;
- protected
- procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); dynamic;
- procedure Change(NeedResize: Boolean); virtual;
- function CreatePopup(const ParentView: TTBView; const ParentViewer: TTBItemViewer;
- const PositionAsSubmenu, SelectFirstItem, Customizing: Boolean;
- const APopupPoint: TPoint; const Alignment: TTBPopupAlignment): TTBPopupWindow; virtual;
- procedure DoPopup(Sender: TTBCustomItem; FromLink: Boolean); virtual;
- procedure EnabledChanged; virtual;
- function GetActionLinkClass: TTBCustomItemActionLinkClass; dynamic;
- function GetChevronParentView: TTBView; virtual;
- procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
- function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; virtual;
- procedure GetPopupPosition(ParentView: TTBView;
- PopupWindow: TTBPopupWindow; var PopupPositionRec: TTBPopupPositionRec); virtual;
- function GetPopupWindowClass: TTBPopupWindowClass; virtual;
- procedure IndexError;
- procedure Loaded; override;
- function NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean; virtual;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- function OpenPopup(const SelectFirstItem, TrackRightButton: Boolean;
- const PopupPoint: TPoint; const Alignment: TTBPopupAlignment;
- const ReturnClickedItemOnly: Boolean; PositionAsSubmenu: Boolean): TTBCustomItem;
- procedure RecreateItemViewers;
- procedure SetChildOrder(Child: TComponent; Order: Integer); override;
- procedure SetName(const NewName: TComponentName); override;
- procedure SetParentComponent(Value: TComponent); override;
- property ActionLink: TTBCustomItemActionLink read FActionLink write FActionLink;
- property ItemStyle: TTBItemStyle read FItemStyle write FItemStyle;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function HasParent: Boolean; override;
- function GetParentComponent: TComponent; override;
- function GetTopComponent: TComponent;
- procedure Add(AItem: TTBCustomItem);
- procedure Clear;
- procedure Click; virtual;
- function ContainsItem(AItem: TTBCustomItem): Boolean;
- procedure Delete(Index: Integer);
- function GetShortCutText: String;
- function IndexOf(AItem: TTBCustomItem): Integer;
- procedure InitiateAction; virtual;
- procedure Insert(NewIndex: Integer; AItem: TTBCustomItem);
- function IsShortCut(var Message: TWMKey): Boolean;
- procedure Move(CurIndex, NewIndex: Integer);
- function Popup(X, Y: Integer; TrackRightButton: Boolean;
- Alignment: TTBPopupAlignment = tbpaLeft;
- ReturnClickedItemOnly: Boolean = False;
- PositionAsSubmenu: Boolean = False): TTBCustomItem;
- procedure PostClick;
- procedure RegisterNotification(ANotify: TTBItemChangedProc);
- procedure Remove(Item: TTBCustomItem);
- procedure UnregisterNotification(ANotify: TTBItemChangedProc);
- procedure ViewBeginUpdate;
- procedure ViewEndUpdate;
- procedure ChangeScale(M, D: Integer); virtual;
- property Action: TBasicAction read GetAction write SetAction;
- property AutoCheck: Boolean read FAutoCheck write FAutoCheck stored IsAutoCheckStored default False;
- property Caption: String read FCaption write SetCaption stored IsCaptionStored;
- property Count: Integer read FItemCount;
- property Checked: Boolean read FChecked write SetChecked stored IsCheckedStored default False;
- property DisplayMode: TTBItemDisplayMode read FDisplayMode write SetDisplayMode default nbdmDefault;
- property EffectiveOptions: TTBItemOptions read FEffectiveOptions;
- property Enabled: Boolean read FEnabled write SetEnabled stored IsEnabledStored default True;
- property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
- property HelpContext: THelpContext read FHelpContext write FHelpContext stored IsHelpContextStored default 0;
- { MP }
- property HelpKeyword: String read FHelpKeyword write FHelpKeyword stored IsHelpContextStored;
- property Hint: String read FHint write FHint stored IsHintStored;
- property ImageIndex: TImageIndex read FImageIndex write SetImageIndex stored IsImageIndexStored default -1;
- property Images: TCustomImageList read FImages write SetImages;
- property InheritOptions: Boolean read FInheritOptions write SetInheritOptions default True;
- property Items[Index: Integer]: TTBCustomItem read GetItem; default;
- property LinkSubitems: TTBCustomItem read FLinkSubitems write SetLinkSubitems;
- property MaskOptions: TTBItemOptions read FMaskOptions write SetMaskOptions default [];
- property Options: TTBItemOptions read FOptions write SetOptions default [];
- property Parent: TTBCustomItem read FParent;
- property ParentComponent: TComponent read FParentComponent write FParentComponent;
- property RadioItem: Boolean read FRadioItem write SetRadioItem default False;
- property ShortCut: TShortCut read FShortCut write FShortCut stored IsShortCutStored default 0;
- property SubMenuImages: TCustomImageList read FSubMenuImages write SetSubMenuImages;
- property Visible: Boolean read FVisible write SetVisible stored IsVisibleStored default True;
- property OnClick: TNotifyEvent read FOnClick write FOnClick stored IsOnClickStored;
- property OnPopup: TTBPopupEvent read FOnPopup write FOnPopup;
- property OnSelect: TTBSelectEvent read FOnSelect write FOnSelect;
- end;
- TTBCustomItemActionLink = class(TActionLink)
- protected
- FClient: TTBCustomItem;
- procedure AssignClient(AClient: TObject); override;
- function IsAutoCheckLinked: Boolean; virtual;
- function IsCaptionLinked: Boolean; override;
- function IsCheckedLinked: Boolean; override;
- function IsEnabledLinked: Boolean; override;
- function IsHelpContextLinked: Boolean; override;
- { MP }
- function IsHelpLinked: Boolean; override;
- function IsHintLinked: Boolean; override;
- function IsImageIndexLinked: Boolean; override;
- function IsShortCutLinked: Boolean; override;
- function IsVisibleLinked: Boolean; override;
- function IsOnExecuteLinked: Boolean; override;
- procedure SetAutoCheck(Value: Boolean); override;
- procedure SetCaption(const Value: String); override;
- procedure SetChecked(Value: Boolean); override;
- procedure SetEnabled(Value: Boolean); override;
- procedure SetHelpContext(Value: THelpContext); override;
- { MP }
- procedure SetHelpKeyword(const Value: string); override;
- procedure SetHint(const Value: String); override;
- procedure SetImageIndex(Value: Integer); override;
- procedure SetShortCut(Value: TShortCut); override;
- procedure SetVisible(Value: Boolean); override;
- procedure SetOnExecute(Value: TNotifyEvent); override;
- end;
- TTBBaseAccObject = class(TInterfacedObject, IDispatch)
- public
- procedure ClientIsDestroying; virtual; abstract;
- { IDispatch }
- function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
- function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
- function GetIDsOfNames(const IID: TGUID; Names: Pointer;
- NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
- function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
- Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
- end;
- TTBItemViewer = class
- private
- FBoundsRect: TRect;
- FClipped: Boolean;
- FGroupLevel: Integer;
- FItem: TTBCustomItem;
- FOffEdge: Boolean;
- FShow: Boolean;
- FView: TTBView;
- procedure AccSelect(const AExecute: Boolean);
- function GetIndex: Integer;
- protected
- FAccObjectInstance: TTBBaseAccObject;
- procedure CalcSize(const Canvas: TCanvas; var AWidth, AHeight: Integer);
- virtual;
- function CaptionShown: Boolean; dynamic;
- function DoExecute: Boolean; virtual;
- procedure DrawItemCaption(const Canvas: TCanvas; ARect: TRect;
- const ACaption: String; ADrawDisabledShadow: Boolean; AFormat: UINT); virtual;
- procedure Entering(OldSelected: TTBItemViewer); virtual;
- function GetAccRole: Integer; virtual;
- function GetAccValue(var Value: WideString): Boolean; virtual;
- function GetCaptionText: String; virtual;
- procedure GetCursor(const Pt: TPoint; var ACursor: HCURSOR); virtual;
- function GetImageList: TCustomImageList;
- function ImageShown: Boolean;
- function IsRotated: Boolean;
- function IsToolbarSize: Boolean; virtual;
- function IsPtInButtonPart(X, Y: Integer): Boolean; virtual;
- procedure KeyDown(var Key: Word; Shift: TShiftState); virtual;
- procedure Leaving; virtual;
- procedure LosingCapture; virtual;
- procedure MouseDown(Shift: TShiftState; X, Y: Integer;
- var MouseDownOnMenu: Boolean); virtual;
- procedure MouseMove(X, Y: Integer); virtual;
- procedure MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean); virtual;
- procedure MouseWheel(WheelDelta: Integer; X, Y: Integer); virtual;
- procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
- IsSelected, IsPushed, UseDisabledShadow: Boolean); virtual;
- procedure PostAccSelect(const AExecute: Boolean);
- function UsesSameWidth: Boolean; virtual;
- public
- State: set of (tbisInvalidated, tbisLineSep);
- property BoundsRect: TRect read FBoundsRect;
- property Clipped: Boolean read FClipped;
- property Index: Integer read GetIndex;
- property Item: TTBCustomItem read FItem;
- property OffEdge: Boolean read FOffEdge;
- property Show: Boolean read FShow;
- property View: TTBView read FView;
- constructor Create(AView: TTBView; AItem: TTBCustomItem; AGroupLevel: Integer); virtual;
- destructor Destroy; override;
- procedure Execute(AGivePriority: Boolean);
- function GetAccObject: IDispatch;
- function GetHintText: String;
- function IsAccessible: Boolean;
- function IsToolbarStyle: Boolean; virtual;
- function ScreenToClient(const P: TPoint): TPoint;
- end;
- PTBItemViewerArray = ^TTBItemViewerArray;
- TTBItemViewerArray = array[0..$7FFFFFFF div SizeOf(TTBItemViewer)-1] of TTBItemViewer;
- TTBViewOrientation = (tbvoHorizontal, tbvoVertical, tbvoFloating);
- TTBEnterToolbarLoopOptions = set of (tbetMouseDown, tbetExecuteSelected,
- tbetFromMSAA);
- TTBViewState = set of (vsModal, vsMouseInWindow, vsDrawInOrder, vsOppositePopup,
- vsIgnoreFirstMouseUp, vsShowAccels, vsDropDownMenus, vsNoAnimation);
- TTBViewStyle = set of (vsMenuBar, vsUseHiddenAccels, vsAlwaysShowHints);
- TTBViewTimerID = (tiOpen, tiClose, tiScrollUp, tiScrollDown);
- TTBViewClass = class of TTBView;
- TTBView = class(TComponent)
- private
- FActiveTimers: set of TTBViewTimerID;
- FBackgroundColor: TColor;
- FBaseSize: TPoint;
- FCapture: Boolean;
- FCaptureWnd: HWND;
- FChevronOffset: Integer;
- FChevronParentView: TTBView;
- FChevronSize: Integer;
- FCurParentItem: TTBCustomItem;
- FCustomizing: Boolean;
- FDoneActionData: TTBDoneActionData;
- FInternalViewersAtEnd: Integer;
- FInternalViewersAtFront: Integer;
- FIsPopup: Boolean;
- FIsToolbar: Boolean;
- FMaxHeight: Integer;
- FMonitorRect: TRect;
- FMouseOverSelected: Boolean;
- FNewViewersGetHighestPriority: Boolean;
- FOpenViewer: TTBItemViewer;
- FOpenViewerView: TTBView;
- FOpenViewerWindow: TTBPopupWindow;
- FParentView: TTBView;
- FParentItem: TTBCustomItem;
- FPriorityList: TList;
- FOrientation: TTBViewOrientation;
- FScrollOffset: Integer;
- FSelected: TTBItemViewer;
- FSelectedViaMouse: Boolean;
- FShowDownArrow: Boolean;
- FShowUpArrow: Boolean;
- FState: TTBViewState;
- FStyle: TTBViewStyle;
- FUpdating: Integer;
- FUsePriorityList: Boolean;
- FValidated: Boolean;
- FViewerCount: Integer;
- FViewers: PTBItemViewerArray;
- FWindow: TWinControl;
- FWrapOffset: Integer;
- procedure DeletingViewer(Viewer: TTBItemViewer);
- procedure DrawItem(Viewer: TTBItemViewer; DrawTo: TCanvas; Offscreen: Boolean);
- procedure FreeViewers;
- procedure ImagesChanged;
- function InsertItemViewers(const NewIndex: Integer;
- const AItem: TTBCustomItem; const AGroupLevel: Integer;
- const AddToPriorityList, TopOfPriorityList: Boolean): Integer;
- procedure ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- procedure LinkNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- procedure RecreateItemViewer(const I: Integer);
- procedure Scroll(ADown: Boolean);
- procedure SetCustomizing(Value: Boolean);
- procedure SetSelected(Value: TTBItemViewer);
- procedure SetUsePriorityList(Value: Boolean);
- procedure StartTimer(const ATimer: TTBViewTimerID; const Interval: Integer);
- procedure StopAllTimers;
- procedure StopTimer(const ATimer: TTBViewTimerID);
- procedure UpdateCurParentItem;
- protected
- FAccObjectInstance: TTBBaseAccObject;
- procedure AutoSize(AWidth, AHeight: Integer); virtual;
- function CalculatePositions(const CanMoveControls: Boolean;
- const AOrientation: TTBViewOrientation;
- AWrapOffset, AChevronOffset, AChevronSize: Integer;
- var ABaseSize, TotalSize: TPoint;
- var AWrappedLines: Integer): Boolean;
- procedure DoUpdatePositions(var ASize: TPoint); virtual;
- function GetChevronItem: TTBCustomItem; virtual;
- procedure GetMargins(AOrientation: TTBViewOrientation; var Margins: TRect);
- virtual;
- function GetMDIButtonsItem: TTBCustomItem; virtual;
- function GetMDISystemMenuItem: TTBCustomItem; virtual;
- function GetParentToolbarView: TTBView;
- function GetRootView: TTBView;
- function HandleWMGetObject(var Message: TMessage): Boolean;
- procedure InitiateActions;
- procedure KeyDown(var Key: Word; Shift: TShiftState); virtual;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetAccelsVisibility(AShowAccels: Boolean);
- procedure SetState(AState: TTBViewState);
- property DoneActionData: TTBDoneActionData read FDoneActionData write FDoneActionData;
- property ShowDownArrow: Boolean read FShowDownArrow; {vb+}
- property ShowUpArrow: Boolean read FShowUpArrow; {vb+}
- public
- constructor CreateView(AOwner: TComponent; AParentView: TTBView;
- AParentItem: TTBCustomItem; AWindow: TWinControl;
- AIsToolbar, ACustomizing, AUsePriorityList: Boolean); virtual;
- destructor Destroy; override;
- procedure BeginUpdate;
- procedure CancelCapture;
- procedure CancelChildPopups;
- procedure CancelMode;
- procedure CloseChildPopups;
- function ContainsView(AView: TTBView): Boolean;
- procedure DrawSubitems(ACanvas: TCanvas);
- procedure EndModal;
- procedure EndModalWithClick(AViewer: TTBItemViewer);
- { MP }
- procedure EndModalWithHelp(AContextID: Integer); overload;
- procedure EndModalWithHelp(HelpKeyword: string); overload;
- { /MP }
- procedure EndModalWithSystemMenu(AWnd: HWND; AKey: Cardinal);
- procedure EndUpdate;
- procedure EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions); virtual;
- procedure ExecuteSelected(AGivePriority: Boolean);
- function Find(Item: TTBCustomItem): TTBItemViewer;
- function FirstSelectable: TTBItemViewer;
- function GetAccObject: IDispatch;
- function GetCaptureWnd: HWND;
- function GetFont: TFont; virtual;
- procedure GetOffEdgeControlList(const List: TList);
- procedure GivePriority(AViewer: TTBItemViewer);
- function HighestPriorityViewer: TTBItemViewer;
- procedure Invalidate(AViewer: TTBItemViewer);
- procedure InvalidatePositions; virtual;
- function IndexOf(AViewer: TTBItemViewer): Integer;
- function IsModalEnding: Boolean;
- function NextSelectable(CurViewer: TTBItemViewer; GoForward: Boolean): TTBItemViewer;
- function NextSelectableWithAccel(CurViewer: TTBItemViewer; Key: Char;
- RequirePrimaryAccel: Boolean; var IsOnlyItemWithAccel: Boolean): TTBItemViewer;
- procedure NotifyFocusEvent;
- function OpenChildPopup(const SelectFirstItem: Boolean): Boolean;
- procedure RecreateAllViewers;
- procedure ScrollSelectedIntoView;
- procedure Select(Value: TTBItemViewer; ViaMouse: Boolean);
- procedure SetCapture;
- procedure TryValidatePositions;
- procedure UpdateSelection(const P: PPoint; const AllowNewSelection: Boolean);
- function UpdatePositions: TPoint;
- procedure ValidatePositions;
- function ViewerFromPoint(const P: TPoint): TTBItemViewer;
- function GetMonitor: TMonitor; virtual;
- property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor;
- property BaseSize: TPoint read FBaseSize;
- property Capture: Boolean read FCapture;
- property ChevronOffset: Integer read FChevronOffset write FChevronOffset;
- property ChevronSize: Integer read FChevronSize write FChevronSize;
- property Customizing: Boolean read FCustomizing write SetCustomizing;
- property IsPopup: Boolean read FIsPopup;
- property IsToolbar: Boolean read FIsToolbar;
- property MouseOverSelected: Boolean read FMouseOverSelected;
- property NewViewersGetHighestPriority: Boolean read FNewViewersGetHighestPriority
- write FNewViewersGetHighestPriority;
- property ParentView: TTBView read FParentView;
- property ParentItem: TTBCustomItem read FParentItem;
- property OpenViewer: TTBItemViewer read FOpenViewer;
- property OpenViewerView: TTBView read FOpenViewerView;
- property Orientation: TTBViewOrientation read FOrientation write FOrientation;
- property Selected: TTBItemViewer read FSelected write SetSelected;
- property SelectedViaMouse: Boolean read FSelectedViaMouse;
- property State: TTBViewState read FState;
- property Style: TTBViewStyle read FStyle write FStyle;
- property UsePriorityList: Boolean read FUsePriorityList write SetUsePriorityList;
- property Viewers: PTBItemViewerArray read FViewers;
- property ViewerCount: Integer read FViewerCount;
- property Window: TWinControl read FWindow;
- property WrapOffset: Integer read FWrapOffset write FWrapOffset;
- end;
- TTBRootItemClass = class of TTBRootItem;
- TTBRootItem = class(TTBCustomItem);
- { same as TTBCustomItem, except there's a property editor for it }
- TTBItem = class(TTBCustomItem)
- published
- property Action;
- property AutoCheck;
- property Caption;
- property Checked;
- property DisplayMode;
- property Enabled;
- property GroupIndex;
- property HelpContext;
- { MP }
- property HelpKeyword;
- property Hint;
- property ImageIndex;
- property Images;
- property InheritOptions;
- property MaskOptions;
- property Options;
- property RadioItem;
- property ShortCut;
- property Visible;
- property OnClick;
- property OnSelect;
- end;
- TTBGroupItem = class(TTBCustomItem)
- public
- constructor Create(AOwner: TComponent); override;
- published
- property InheritOptions;
- property LinkSubitems;
- property MaskOptions;
- property Options;
- end;
- TTBSubmenuItem = class(TTBCustomItem)
- private
- function GetDropdownCombo: Boolean;
- procedure SetDropdownCombo(Value: Boolean);
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Action;
- property AutoCheck;
- property Caption;
- property Checked;
- //property DisplayAsToolbar;
- property DisplayMode;
- property DropdownCombo: Boolean read GetDropdownCombo write SetDropdownCombo default False;
- property Enabled;
- property GroupIndex;
- property HelpContext;
- { MP }
- property HelpKeyword;
- property Hint;
- property ImageIndex;
- property Images;
- property InheritOptions;
- property LinkSubitems;
- property MaskOptions;
- property Options;
- property RadioItem;
- property ShortCut;
- property SubMenuImages;
- property Visible;
- property OnClick;
- property OnPopup;
- property OnSelect;
- end;
- TTBSeparatorItem = class(TTBCustomItem)
- private
- FBlank: Boolean;
- procedure SetBlank(Value: Boolean);
- protected
- function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Blank: Boolean read FBlank write SetBlank default False;
- property Hint;
- property Visible;
- end;
- TTBSeparatorItemViewer = class(TTBItemViewer)
- protected
- procedure CalcSize(const Canvas: TCanvas;
- var AWidth, AHeight: Integer); override;
- procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
- IsSelected, IsPushed, UseDisabledShadow: Boolean); override;
- function UsesSameWidth: Boolean; override;
- end;
- TTBControlItem = class(TTBCustomItem)
- private
- FControl: TControl;
- FDontFreeControl: Boolean;
- procedure SetControl(Value: TControl);
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- public
- constructor Create(AOwner: TComponent); override;
- constructor CreateControlItem(AOwner: TComponent; AControl: TControl);
- destructor Destroy; override;
- property DontFreeControl: Boolean read FDontFreeControl write FDontFreeControl;
- published
- property Control: TControl read FControl write SetControl;
- end;
- TTBPopupView = class(TTBView)
- protected
- procedure AutoSize(AWidth, AHeight: Integer); override;
- public
- function GetMonitor: TMonitor; override;
- function GetFont: TFont; override;
- end;
- ITBPopupWindow = interface
- ['{E45CBE74-1ECF-44CB-B064-6D45B1924708}']
- end;
- TTBPopupWindow = class(TCustomControl, ITBPopupWindow)
- private
- FAccelsVisibilitySet: Boolean;
- FAnimationDirection: TTBAnimationDirection;
- FView: TTBView;
- procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
- procedure CMHintShowPause(var Message: TMessage); message CM_HINTSHOWPAUSE;
- procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
- procedure WMClose(var Message: TWMClose); message WM_CLOSE;
- procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
- procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT;
- procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
- procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
- procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
- procedure WMPrint(var Message: TMessage); message WM_PRINT;
- procedure WMPrintClient(var Message: TMessage); message WM_PRINTCLIENT;
- procedure WMTB2kStepAnimation(var Message: TMessage); message WM_TB2K_STEPANIMATION;
- procedure WMTB2kAnimationEnded (var Message: TMessage); message WM_TB2K_ANIMATIONENDED;
- protected
- procedure CreateParams(var Params: TCreateParams); override;
- procedure CreateWnd; override;
- procedure DestroyWindowHandle; override;
- function GetNCSize: TPoint; dynamic;
- function GetViewClass: TTBViewClass; dynamic;
- procedure Paint; override;
- procedure PaintScrollArrows; virtual;
- property AnimationDirection: TTBAnimationDirection read FAnimationDirection;
- {MP}
- procedure Cancel; dynamic;
- public
- constructor CreatePopupWindow(AOwner: TComponent; const AParentView: TTBView;
- const AItem: TTBCustomItem; const ACustomizing: Boolean; const PopupPoint: TPoint); virtual;
- destructor Destroy; override;
- procedure BeforeDestruction; override;
- property View: TTBView read FView;
- end;
- ITBItems = interface
- ['{A5C0D7CC-3EC4-4090-A0F8-3D03271877EA}']
- function GetItems: TTBCustomItem;
- end;
- TTBItemContainer = class(TComponent, ITBItems)
- private
- FItem: TTBRootItem;
- function GetImages: TCustomImageList;
- function GetItems: TTBCustomItem;
- procedure SetImages(Value: TCustomImageList);
- protected
- procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- property Items: TTBRootItem read FItem;
- published
- property Images: TCustomImageList read GetImages write SetImages;
- end;
- TTBPopupMenu = class(TPopupMenu, ITBItems)
- private
- FItem: TTBRootItem;
- //procedure SetItems(Value: TTBCustomItem);
- function GetImages: TCustomImageList;
- function GetItems: TTBCustomItem;
- function GetLinkSubitems: TTBCustomItem;
- function GetOptions: TTBItemOptions;
- procedure RootItemClick(Sender: TObject);
- procedure SetImages(Value: TCustomImageList);
- procedure SetLinkSubitems(Value: TTBCustomItem);
- procedure SetOptions(Value: TTBItemOptions);
- protected
- function GetRootItemClass: TTBRootItemClass; dynamic;
- procedure SetChildOrder(Child: TComponent; Order: Integer); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function IsShortCut(var Message: TWMKey): Boolean; override;
- procedure Popup(X, Y: Integer); override;
- function PopupEx(X, Y: Integer; ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
- procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
- published
- property Images: TCustomImageList read GetImages write SetImages;
- property Items: TTBRootItem read FItem;
- property LinkSubitems: TTBCustomItem read GetLinkSubitems write SetLinkSubitems;
- property Options: TTBItemOptions read GetOptions write SetOptions default [];
- end;
- TTBCustomImageList = class(TImageList)
- private
- FCheckedImages: TCustomImageList;
- FCheckedImagesChangeLink: TChangeLink;
- FDisabledImages: TCustomImageList;
- FDisabledImagesChangeLink: TChangeLink;
- FHotImages: TCustomImageList;
- FHotImagesChangeLink: TChangeLink;
- FImagesBitmap: TBitmap;
- FImagesBitmapMaskColor: TColor;
- procedure ChangeImages(var AImageList: TCustomImageList;
- Value: TCustomImageList; AChangeLink: TChangeLink);
- procedure ImageListChanged(Sender: TObject);
- procedure ImagesBitmapChanged(Sender: TObject);
- procedure SetCheckedImages(Value: TCustomImageList);
- procedure SetDisabledImages(Value: TCustomImageList);
- procedure SetHotImages(Value: TCustomImageList);
- procedure SetImagesBitmap(Value: TBitmap);
- procedure SetImagesBitmapMaskColor(Value: TColor);
- protected
- procedure DefineProperties(Filer: TFiler); override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- property CheckedImages: TCustomImageList read FCheckedImages write SetCheckedImages;
- property DisabledImages: TCustomImageList read FDisabledImages write SetDisabledImages;
- property HotImages: TCustomImageList read FHotImages write SetHotImages;
- property ImagesBitmap: TBitmap read FImagesBitmap write SetImagesBitmap;
- property ImagesBitmapMaskColor: TColor read FImagesBitmapMaskColor
- write SetImagesBitmapMaskColor default clFuchsia;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DrawState(Canvas: TCanvas; X, Y, Index: Integer;
- Enabled, Selected, Checked: Boolean); virtual;
- end;
- TTBImageList = class(TTBCustomImageList)
- published
- property CheckedImages;
- property DisabledImages;
- property HotImages;
- property ImagesBitmap;
- property ImagesBitmapMaskColor;
- end;
- const
- {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
- tbMenuBkColor = clMenu;
- tbMenuTextColor = clMenuText;
- {$ELSE}
- tbMenuBkColor = clBtnFace;
- tbMenuTextColor = clBtnText;
- {$ENDIF}
- tbMenuVerticalMargin = 4;
- tbMenuImageTextSpace = 1;
- tbMenuLeftTextMargin = 2;
- tbMenuRightTextMargin = 3;
- tbMenuSeparatorOffset = 12;
- tbMenuScrollArrowHeight = 19;
- tbDropdownArrowWidth = 8;
- tbDropdownArrowMargin = 3;
- tbDropdownComboArrowWidth = 11;
- tbDropdownComboMargin = 2;
- tbLineSpacing = 6;
- tbLineSepOffset = 1;
- tbDockedLineSepOffset = 4;
- WM_TB2K_CLICKITEM = WM_USER + $100;
- procedure TBInitToolbarSystemFont;
- function GetToolbarFont(PixelsPerInch: Integer): TFont; overload;
- function GetToolbarFont(Control: TControl): TFont; overload;
- type
- TTBModalHandler = class
- private
- FCreatedWnd: Boolean;
- FInited: Boolean;
- FWnd: HWND;
- FRootPopup: TTBPopupWindow;
- procedure WndProc(var Msg: TMessage);
- public
- constructor Create(AExistingWnd: HWND);
- destructor Destroy; override;
- procedure Loop(const RootView: TTBView; const AMouseDown, AExecuteSelected,
- AFromMSAA, TrackRightButton: Boolean);
- property RootPopup: TTBPopupWindow read FRootPopup write FRootPopup;
- property Wnd: HWND read FWnd;
- class procedure DoLockForegroundWindow(LockCode: Cardinal);
- class procedure LockForegroundWindow;
- class procedure UnlockForegroundWindow;
- end;
- function ProcessDoneAction(const DoneActionData: TTBDoneActionData;
- const ReturnClickedItemOnly: Boolean): TTBCustomItem;
- implementation
- uses
- MMSYSTEM, TB2Consts, TB2Common, IMM, TB2Acc, Winapi.oleacc, Types, PasTools, Generics.Collections, TB2Toolbar;
- var
- LastPos: TPoint;
- threadvar
- ClickWndRefCount: Integer;
- ClickWnd: HWND;
- ClickList: TList;
- type
- PItemChangedNotificationData = ^TItemChangedNotificationData;
- TItemChangedNotificationData = record
- Proc: TTBItemChangedProc;
- RefCount: Integer;
- end;
- TComponentAccess = class(TComponent);
- TControlAccess = class(TControl);
- const
- ViewTimerBaseID = 9000;
- MaxGroupLevel = 10;
- { Misc. }
- var
- ShortCutToTextFixes: TStrings = nil;
- function ShortCutToTextFix(AShortCut: TShortCut): string;
- begin
- Result := ShortCutToText(AShortCut);
- // WORKAROUND: German keyboard driver is giving wrong name for VK_MULTIPLY
- if (AShortCut = ShortCut(VK_MULTIPLY, [])) and
- (Result = ' (ZEHNERTASTATUR)') then
- begin
- Result := ShortCutToText(ShortCut(VK_ADD, []));
- Result := StringReplace(Result, '+', '*', []);
- end;
- end;
- procedure DestroyClickWnd;
- begin
- if ClickWnd <> 0 then begin
- Classes.DeallocateHWnd(ClickWnd);
- ClickWnd := 0;
- end;
- FreeAndNil(ClickList);
- end;
- procedure ReferenceClickWnd;
- begin
- Inc(ClickWndRefCount);
- end;
- procedure ReleaseClickWnd;
- begin
- Dec(ClickWndRefCount);
- if ClickWndRefCount = 0 then
- DestroyClickWnd;
- end;
- procedure QueueClick(const AItem: TObject; const AArg: Integer);
- { Adds an item to ClickList and posts a message to handle it. AItem must be
- either a TTBCustomItem or TTBItemViewer. }
- var
- I: Integer;
- begin
- if ClickWnd = 0 then
- ClickWnd := Classes.AllocateHWnd(TTBCustomItem.ClickWndProc);
- if ClickList = nil then
- ClickList := TList.Create;
- { Add a new item to ClickList or replace an empty one }
- I := ClickList.IndexOf(nil);
- if I = -1 then
- I := ClickList.Add(AItem)
- else
- ClickList[I] := AItem;
- PostMessage(ClickWnd, WM_TB2K_CLICKITEM, AArg, I);
- end;
- procedure RemoveFromClickList(const AItem: TObject);
- { Any class that potentially calls QueueClick needs to call RemoveFromClickList
- before an instance is destroyed to ensure that any references to the
- instance still in ClickList are removed. }
- var
- I: Integer;
- begin
- if Assigned(ClickList) and Assigned(AItem) then
- for I := 0 to ClickList.Count-1 do
- if ClickList[I] = AItem then
- ClickList[I] := Pointer(1);
- { ^ The special value of Pointer(1) is assigned to the item instead of
- of nil because we want the index to stay reserved until the
- WM_TB2K_CLICKITEM message for the index is processed. We don't want
- the WM_TB2K_CLICKITEM message that's still in the queue to later
- refer to a different item; this would result in queued clicks being
- processed in the wrong order in a case like this:
- A.PostClick; B.PostClick; A.Free; C.PostClick;
- C's click would end up being processed before A's, because C would
- get A's index. }
- end;
- function ProcessDoneAction(const DoneActionData: TTBDoneActionData;
- const ReturnClickedItemOnly: Boolean): TTBCustomItem;
- begin
- Result := nil;
- case DoneActionData.DoneAction of
- tbdaNone: ;
- tbdaClickItem: begin
- if DoneActionData.Sound and NeedToPlaySound('MenuCommand') then
- PlaySoundA('MenuCommand', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
- Result := DoneActionData.ClickItem;
- if not ReturnClickedItemOnly then
- Result.PostClick;
- end;
- tbdaOpenSystemMenu: begin
- SendMessage(DoneActionData.Wnd, WM_SYSCOMMAND, SC_KEYMENU, DoneActionData.Key);
- end;
- tbdaHelpContext: begin
- { Based on code in TPopupList.WndProc: }
- if Assigned(Screen.ActiveForm) and
- (biHelp in Screen.ActiveForm.BorderIcons) then
- Application.HelpCommand(HELP_CONTEXTPOPUP, DoneActionData.ContextID)
- else
- Application.HelpContext(DoneActionData.ContextID);
- end;
- { MP }
- tbdaHelpKeyword: begin
- Application.HelpKeyword(string(DoneActionData.HelpKeyword));
- end;
- { /MP }
- end;
- end;
- { TTBItemDataArray routines }
- procedure InsertIntoItemArray(var AItems: PTBItemDataArray;
- var AItemCount: Integer; NewIndex: Integer; AItem: TTBCustomItem);
- begin
- ReallocMem(AItems, (AItemCount+1) * SizeOf(AItems[0]));
- if NewIndex < AItemCount then
- System.Move(AItems[NewIndex], AItems[NewIndex+1],
- (AItemCount-NewIndex) * SizeOf(AItems[0]));
- AItems[NewIndex].Item := AItem;
- Inc(AItemCount);
- end;
- procedure DeleteFromItemArray(var AItems: PTBItemDataArray;
- var AItemCount: Integer; Index: Integer);
- begin
- Dec(AItemCount);
- if Index < AItemCount then
- System.Move(AItems[Index+1], AItems[Index],
- (AItemCount-Index) * SizeOf(AItems[0]));
- ReallocMem(AItems, AItemCount * SizeOf(AItems[0]));
- end;
- procedure InsertIntoViewerArray(var AItems: PTBItemViewerArray;
- var AItemCount: Integer; NewIndex: Integer; AItem: TTBItemViewer);
- begin
- ReallocMem(AItems, (AItemCount+1) * SizeOf(AItems[0]));
- if NewIndex < AItemCount then
- System.Move(AItems[NewIndex], AItems[NewIndex+1],
- (AItemCount-NewIndex) * SizeOf(AItems[0]));
- AItems[NewIndex] := AItem;
- Inc(AItemCount);
- end;
- procedure DeleteFromViewerArray(var AItems: PTBItemViewerArray;
- var AItemCount: Integer; Index: Integer);
- begin
- Dec(AItemCount);
- if Index < AItemCount then
- System.Move(AItems[Index+1], AItems[Index],
- (AItemCount-Index) * SizeOf(AItems[0]));
- ReallocMem(AItems, AItemCount * SizeOf(AItems[0]));
- end;
- { TTBCustomItemActionLink }
- procedure TTBCustomItemActionLink.AssignClient(AClient: TObject);
- begin
- FClient := AClient as TTBCustomItem;
- end;
- function TTBCustomItemActionLink.IsAutoCheckLinked: Boolean;
- begin
- Result := (FClient.AutoCheck = (Action as TCustomAction).AutoCheck);
- end;
- function TTBCustomItemActionLink.IsCaptionLinked: Boolean;
- begin
- Result := inherited IsCaptionLinked and
- (FClient.Caption = (Action as TCustomAction).Caption);
- end;
- function TTBCustomItemActionLink.IsCheckedLinked: Boolean;
- begin
- Result := inherited IsCheckedLinked and
- (FClient.Checked = (Action as TCustomAction).Checked);
- end;
- function TTBCustomItemActionLink.IsEnabledLinked: Boolean;
- begin
- Result := inherited IsEnabledLinked and
- (FClient.Enabled = (Action as TCustomAction).Enabled);
- end;
- function TTBCustomItemActionLink.IsHelpContextLinked: Boolean;
- begin
- Result := inherited IsHelpContextLinked and
- (FClient.HelpContext = (Action as TCustomAction).HelpContext);
- end;
- { MP }
- function TTBCustomItemActionLink.IsHelpLinked: Boolean;
- begin
- Result := inherited IsHelpLinked and
- (FClient.HelpContext = (Action as TCustomAction).HelpContext) and
- (FClient.HelpKeyword = (Action as TCustomAction).HelpKeyword){ and
- (FClient.HelpType = (Action as TCustomAction).HelpType);} // TODO
- end;
- { /MP }
- function TTBCustomItemActionLink.IsHintLinked: Boolean;
- begin
- Result := inherited IsHintLinked and
- (FClient.Hint = (Action as TCustomAction).Hint);
- end;
- function TTBCustomItemActionLink.IsImageIndexLinked: Boolean;
- begin
- Result := inherited IsImageIndexLinked and
- (FClient.ImageIndex = (Action as TCustomAction).ImageIndex);
- end;
- function TTBCustomItemActionLink.IsShortCutLinked: Boolean;
- begin
- Result := inherited IsShortCutLinked and
- (FClient.ShortCut = (Action as TCustomAction).ShortCut);
- end;
- function TTBCustomItemActionLink.IsVisibleLinked: Boolean;
- begin
- Result := inherited IsVisibleLinked and
- (FClient.Visible = (Action as TCustomAction).Visible);
- end;
- function TTBCustomItemActionLink.IsOnExecuteLinked: Boolean;
- begin
- Result := inherited IsOnExecuteLinked and
- MethodsEqual(TMethod(FClient.OnClick), TMethod(Action.OnExecute));
- end;
- procedure TTBCustomItemActionLink.SetAutoCheck(Value: Boolean);
- begin
- if IsAutoCheckLinked then FClient.AutoCheck := Value;
- end;
- procedure TTBCustomItemActionLink.SetCaption(const Value: string);
- begin
- if IsCaptionLinked then FClient.Caption := Value;
- end;
- procedure TTBCustomItemActionLink.SetChecked(Value: Boolean);
- begin
- if IsCheckedLinked then FClient.Checked := Value;
- end;
- procedure TTBCustomItemActionLink.SetEnabled(Value: Boolean);
- begin
- if IsEnabledLinked then FClient.Enabled := Value;
- end;
- procedure TTBCustomItemActionLink.SetHelpContext(Value: THelpContext);
- begin
- if { MP } IsHelpLinked { /MP } then FClient.HelpContext := Value;
- end;
- { MP }
- procedure TTBCustomItemActionLink.SetHelpKeyword(const Value: String);
- begin
- if IsHelpLinked then FClient.HelpKeyword := Value;
- end;
- { /MP }
- procedure TTBCustomItemActionLink.SetHint(const Value: string);
- begin
- if IsHintLinked then FClient.Hint := Value;
- end;
- procedure TTBCustomItemActionLink.SetImageIndex(Value: Integer);
- begin
- if IsImageIndexLinked then FClient.ImageIndex := Value;
- end;
- procedure TTBCustomItemActionLink.SetShortCut(Value: TShortCut);
- begin
- if IsShortCutLinked then FClient.ShortCut := Value;
- end;
- procedure TTBCustomItemActionLink.SetVisible(Value: Boolean);
- begin
- if IsVisibleLinked then FClient.Visible := Value;
- end;
- procedure TTBCustomItemActionLink.SetOnExecute(Value: TNotifyEvent);
- begin
- if IsOnExecuteLinked then FClient.OnClick := Value;
- end;
- { TTBCustomItem }
- {}function ItemContainingItems(const AItem: TTBCustomItem): TTBCustomItem;
- begin
- if Assigned(AItem) and Assigned(AItem.FLinkSubitems) then
- Result := AItem.FLinkSubitems
- else
- Result := AItem;
- end;
- constructor TTBCustomItem.Create(AOwner: TComponent);
- begin
- inherited;
- FEnabled := True;
- FImageIndex := -1;
- FInheritOptions := True;
- FItemStyle := [tbisSelectable, tbisRedrawOnSelChange, tbisRedrawOnMouseOverChange];
- FVisible := True;
- ReferenceClickWnd;
- end;
- destructor TTBCustomItem.Destroy;
- var
- I: Integer;
- begin
- Destroying;
- RemoveFromClickList(Self);
- { Changed in 0.33. Moved FParent.Remove call *after* the child items are
- deleted. }
- for I := Count-1 downto 0 do
- Items[I].Free;
- if Assigned(FParent) then
- FParent.Remove(Self);
- FreeMem(FItems);
- FActionLink.Free;
- FActionLink := nil;
- FreeAndNil(FSubMenuImagesChangeLink);
- FreeAndNil(FImagesChangeLink);
- inherited;
- if Assigned(FNotifyList) then begin
- for I := FNotifyList.Count-1 downto 0 do
- Dispose(PItemChangedNotificationData(FNotifyList[I]));
- FNotifyList.Free;
- end;
- FLinkParents.Free;
- ReleaseClickWnd;
- end;
- function TTBCustomItem.IsAutoCheckStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsAutoCheckLinked;
- end;
- function TTBCustomItem.IsCaptionStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsCaptionLinked;
- end;
- function TTBCustomItem.IsCheckedStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsCheckedLinked;
- end;
- function TTBCustomItem.IsEnabledStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsEnabledLinked;
- end;
- function TTBCustomItem.IsHintStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsHintLinked;
- end;
- function TTBCustomItem.IsHelpContextStored: Boolean;
- begin
- { MP }
- Result := (ActionLink = nil) or not FActionLink.IsHelpLinked;
- end;
- function TTBCustomItem.IsImageIndexStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsImageIndexLinked;
- end;
- function TTBCustomItem.IsShortCutStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsShortCutLinked;
- end;
- function TTBCustomItem.IsVisibleStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsVisibleLinked;
- end;
- function TTBCustomItem.IsOnClickStored: Boolean;
- begin
- Result := (ActionLink = nil) or not FActionLink.IsOnExecuteLinked;
- end;
- function TTBCustomItem.GetAction: TBasicAction;
- begin
- if FActionLink <> nil then
- Result := FActionLink.Action
- else
- Result := nil;
- end;
- function TTBCustomItem.GetActionLinkClass: TTBCustomItemActionLinkClass;
- begin
- Result := TTBCustomItemActionLink;
- end;
- procedure TTBCustomItem.DoActionChange(Sender: TObject);
- begin
- if Sender = Action then ActionChange(Sender, False);
- end;
- procedure TTBCustomItem.ActionChange(Sender: TObject; CheckDefaults: Boolean);
- begin
- if Action is TCustomAction then
- with TCustomAction(Sender) do
- begin
- if not CheckDefaults or (Self.AutoCheck = False) then
- Self.AutoCheck := AutoCheck;
- if not CheckDefaults or (Self.Caption = '') then
- Self.Caption := Caption;
- if not CheckDefaults or (Self.Checked = False) then
- Self.Checked := Checked;
- if not CheckDefaults or (Self.Enabled = True) then
- Self.Enabled := Enabled;
- if not CheckDefaults or (Self.HelpContext = 0) then
- Self.HelpContext := HelpContext;
- { MP }
- if not CheckDefaults or (Self.HelpKeyword = '') then
- Self.HelpKeyword := HelpKeyword;
- { /MP }
- if not CheckDefaults or (Self.Hint = '') then
- Self.Hint := Hint;
- if not CheckDefaults or (Self.ImageIndex = -1) then
- Self.ImageIndex := ImageIndex;
- if not CheckDefaults or (Self.ShortCut = scNone) then
- Self.ShortCut := ShortCut;
- if not CheckDefaults or (Self.Visible = True) then
- Self.Visible := Visible;
- if not CheckDefaults or not Assigned(Self.OnClick) then
- Self.OnClick := OnExecute;
- end;
- end;
- procedure TTBCustomItem.SetAction(Value: TBasicAction);
- begin
- if Value = nil then begin
- FActionLink.Free;
- FActionLink := nil;
- end
- else begin
- if FActionLink = nil then
- FActionLink := GetActionLinkClass.Create(Self);
- FActionLink.Action := Value;
- FActionLink.OnChange := DoActionChange;
- { Note: Delphi's Controls.pas and Menus.pas merely check for
- "csLoading in Value.ComponentState" here. But that doesn't help when
- the Action property references an action on another form / data module
- that has already finished loading. So we check two things:
- 1. csLoading in Value.ComponentState
- 2. csLoading in ComponentState
- In the typical case where the item and action list reside on the same
- form, #1 and #2 are both true.
- Only #1 is true when Action references an action on another form / data
- module that is created *after* the item (e.g. if Form1.TBItem1.Action =
- Form2.Action1, and Form1 is created before Form2).
- Only #2 is true when Action references an action on another form / data
- module that is created *before* the item (e.g. if Form2.TBItem1.Action =
- Form1.Action1, and Form1 is created before Form2). }
- ActionChange(Value, (csLoading in Value.ComponentState) or
- (csLoading in ComponentState));
- Value.FreeNotification(Self);
- end;
- end;
- procedure TTBCustomItem.InitiateAction;
- begin
- if FActionLink <> nil then FActionLink.Update;
- end;
- procedure TTBCustomItem.Loaded;
- begin
- inherited;
- if Action <> nil then ActionChange(Action, True);
- end;
- procedure TTBCustomItem.GetChildren(Proc: TGetChildProc; Root: TComponent);
- var
- I: Integer;
- begin
- for I := 0 to FItemCount-1 do
- Proc(FItems[I].Item);
- end;
- procedure TTBCustomItem.SetChildOrder(Child: TComponent; Order: Integer);
- var
- I: Integer;
- begin
- I := IndexOf(Child as TTBCustomItem);
- if I <> -1 then
- Move(I, Order);
- end;
- function TTBCustomItem.HasParent: Boolean;
- begin
- Result := True;
- end;
- function TTBCustomItem.GetParentComponent: TComponent;
- begin
- if (FParent <> nil) and (FParent.FParentComponent <> nil) then
- Result := FParent.FParentComponent
- else
- Result := FParent;
- end;
- function TTBCustomItem.GetTopComponent: TComponent;
- begin
- if Parent <> nil then Result := Parent.GetTopComponent
- else Result := FParentComponent;
- end;
- procedure TTBCustomItem.SetName(const NewName: TComponentName);
- begin
- if Name <> NewName then begin
- inherited;
- if Assigned(FParent) then
- FParent.Notify(tbicNameChanged, -1, Self);
- end;
- end;
- procedure TTBCustomItem.SetParentComponent(Value: TComponent);
- var
- Intf: ITBItems;
- begin
- if FParent <> nil then FParent.Remove(Self);
- if Value <> nil then begin
- if Value is TTBCustomItem then
- TTBCustomItem(Value).Add(Self)
- else if Value.GetInterface(ITBItems, Intf) then
- Intf.GetItems.Add(Self);
- end;
- end;
- procedure TTBCustomItem.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited;
- if Operation = opRemove then begin
- RemoveFromList(FLinkParents, AComponent);
- if AComponent = Action then Action := nil;
- if AComponent = Images then Images := nil;
- if AComponent = SubMenuImages then SubMenuImages := nil;
- if AComponent = LinkSubitems then LinkSubitems := nil;
- end;
- end;
- procedure TTBCustomItem.IndexError;
- begin
- raise ETBItemError.Create(STBToolbarIndexOutOfBounds);
- end;
- class procedure TTBCustomItem.ClickWndProc(var Message: TMessage);
- var
- List: TList;
- I: Integer;
- Item: TObject;
- begin
- if Message.Msg = WM_TB2K_CLICKITEM then begin
- List := ClickList; { optimization... }
- if Assigned(List) then begin
- I := Message.LParam;
- if (I >= 0) and (I < List.Count) then begin
- Item := List[I];
- List[I] := nil;
- if Item = Pointer(1) then { is it a destroyed item? }
- Item := nil;
- end
- else
- Item := nil;
- { Remove trailing nil items from ClickList. This is not *necessary*, but
- it will make RemoveFromClickList faster if we clean out items that
- aren't used, and may never be used again. }
- for I := List.Count-1 downto 0 do begin
- if List[I] = nil then
- List.Delete(I)
- else
- Break;
- end;
- if Assigned(Item) then begin
- try
- if Item is TTBCustomItem then
- TTBCustomItem(Item).Click
- else if Item is TTBItemViewer then
- TTBItemViewer(Item).AccSelect(Message.WParam <> 0);
- except
- Application.HandleException(Item);
- end;
- end;
- end;
- end
- else
- with Message do
- Result := DefWindowProc(ClickWnd, Msg, wParam, lParam);
- end;
- procedure TTBCustomItem.PostClick;
- { Posts a message to the message queue that causes the item's Click handler to
- be executed when control is returned to the message loop.
- This should be called instead of Click when a WM_SYSCOMMAND message is
- (possibly) currently being handled, because TApplication.WndProc's
- CM_APPSYSCOMMAND handler disables the VCL's processing of focus messages
- until the Perform(WM_SYSCOMMAND, ...) call returns. (An OnClick handler which
- calls TForm.ShowModal needs focus messages to be enabled or else the form
- will be shown with no initial focus.) }
- begin
- QueueClick(Self, 0);
- end;
- procedure TTBCustomItem.Click;
- begin
- if Enabled then begin
- { Following code based on D6's TMenuItem.Click }
- if (not Assigned(ActionLink) and AutoCheck) or
- (Assigned(ActionLink) and not ActionLink.IsAutoCheckLinked and AutoCheck) then
- Checked := not Checked;
- { Following code based on D4's TControl.Click }
- { Call OnClick if assigned and not equal to associated action's OnExecute.
- If associated action's OnExecute assigned then call it, otherwise, call
- OnClick. }
- if Assigned(FOnClick) and (Action <> nil) and
- not MethodsEqual(TMethod(FOnClick), TMethod(Action.OnExecute)) then
- FOnClick(Self)
- else
- if not(csDesigning in ComponentState) and (ActionLink <> nil) then
- ActionLink.Execute(Self)
- else
- if Assigned(FOnClick) then
- FOnClick(Self);
- end;
- end;
- function TTBCustomItem.GetItem(Index: Integer): TTBCustomItem;
- begin
- if (Index < 0) or (Index >= FItemCount) then IndexError;
- Result := FItems[Index].Item;
- end;
- procedure TTBCustomItem.Add(AItem: TTBCustomItem);
- begin
- Insert(Count, AItem);
- end;
- procedure TTBCustomItem.InternalNotify(Ancestor: TTBCustomItem;
- NestingLevel: Integer; Action: TTBItemChangedAction; Index: Integer;
- Item: TTBCustomItem);
- { Note: Ancestor is Item's parent, or in the case of a group item relayed
- notification, it can also be a group item which *links* to Item's parent
- (i.e. ItemContainingItems(Ancestor) = Item.Parent). }
- procedure RelayToParentOf(const AItem: TTBCustomItem);
- begin
- if NestingLevel > MaxGroupLevel then
- Exit;
- if (tbisEmbeddedGroup in AItem.ItemStyle) and Assigned(AItem.Parent) then begin
- if Ancestor = Self then
- AItem.Parent.InternalNotify(AItem, NestingLevel + 1, Action, Index, Item)
- else
- { Don't alter Ancestor on subsequent relays; only on the first. }
- AItem.Parent.InternalNotify(Ancestor, NestingLevel + 1, Action, Index, Item);
- end;
- end;
- var
- I: Integer;
- P: TTBCustomItem;
- SaveProc: TTBItemChangedProc;
- begin
- { If Self is a group item, relay the notification to the parent }
- RelayToParentOf(Self);
- { If any group items are linked to Self, relay the notification to
- those items' parents }
- if Assigned(FLinkParents) then
- for I := 0 to FLinkParents.Count-1 do begin
- P := FLinkParents[I];
- if P <> Parent then
- RelayToParentOf(P);
- end;
- if Assigned(FNotifyList) then begin
- I := 0;
- while I < FNotifyList.Count do begin
- with PItemChangedNotificationData(FNotifyList[I])^ do begin
- SaveProc := Proc;
- Proc(Ancestor, Ancestor <> Self, Action, Index, Item);
- end;
- { Is I now out of bounds? }
- if I >= FNotifyList.Count then
- Break;
- { Only proceed to the next index if the list didn't change }
- if MethodsEqual(TMethod(PItemChangedNotificationData(FNotifyList[I])^.Proc),
- TMethod(SaveProc)) then
- Inc(I);
- end;
- end;
- end;
- procedure TTBCustomItem.Notify(Action: TTBItemChangedAction; Index: Integer;
- Item: TTBCustomItem);
- begin
- InternalNotify(Self, 0, Action, Index, Item);
- end;
- procedure TTBCustomItem.ViewBeginUpdate;
- begin
- Notify(tbicSubitemsBeginUpdate, -1, nil);
- end;
- procedure TTBCustomItem.ViewEndUpdate;
- begin
- Notify(tbicSubitemsEndUpdate, -1, nil);
- end;
- procedure TTBCustomItem.Insert(NewIndex: Integer; AItem: TTBCustomItem);
- begin
- if Assigned(AItem.FParent) then
- raise ETBItemError.Create(STBToolbarItemReinserted);
- if (NewIndex < 0) or (NewIndex > FItemCount) then IndexError;
- InsertIntoItemArray(FItems, FItemCount, NewIndex, AItem);
- AItem.FParent := Self;
- ViewBeginUpdate;
- try
- Notify(tbicInserted, NewIndex, AItem);
- AItem.RefreshOptions;
- finally
- ViewEndUpdate;
- end;
- end;
- procedure TTBCustomItem.Delete(Index: Integer);
- begin
- if (Index < 0) or (Index >= FItemCount) then IndexError;
- Notify(tbicDeleting, Index, FItems[Index].Item);
- FItems[Index].Item.FParent := nil;
- DeleteFromItemArray(FItems, FItemCount, Index);
- end;
- function TTBCustomItem.IndexOf(AItem: TTBCustomItem): Integer;
- var
- I: Integer;
- begin
- for I := 0 to FItemCount-1 do
- if FItems[I].Item = AItem then begin
- Result := I;
- Exit;
- end;
- Result := -1;
- end;
- procedure TTBCustomItem.Remove(Item: TTBCustomItem);
- var
- I: Integer;
- begin
- I := IndexOf(Item);
- //if I = -1 then raise ETBItemError.Create(STBToolbarItemNotFound);
- if I <> -1 then
- Delete(I);
- end;
- procedure TTBCustomItem.Clear;
- var
- I: Integer;
- begin
- for I := Count-1 downto 0 do
- Items[I].Free;
- end;
- procedure TTBCustomItem.Move(CurIndex, NewIndex: Integer);
- var
- Item: TTBCustomItem;
- begin
- if CurIndex <> NewIndex then begin
- if (NewIndex < 0) or (NewIndex >= FItemCount) then IndexError;
- Item := Items[CurIndex];
- ViewBeginUpdate;
- try
- Delete(CurIndex);
- Insert(NewIndex, Item);
- finally
- ViewEndUpdate;
- end;
- end;
- end;
- function TTBCustomItem.ContainsItem(AItem: TTBCustomItem): Boolean;
- begin
- while Assigned(AItem) and (AItem <> Self) do
- AItem := AItem.Parent;
- Result := Assigned(AItem);
- end;
- procedure TTBCustomItem.RegisterNotification(ANotify: TTBItemChangedProc);
- var
- I: Integer;
- Data: PItemChangedNotificationData;
- begin
- if FNotifyList = nil then FNotifyList := TList.Create;
- for I := 0 to FNotifyList.Count-1 do
- with PItemChangedNotificationData(FNotifyList[I])^ do
- if MethodsEqual(TMethod(ANotify), TMethod(Proc)) then begin
- Inc(RefCount);
- Exit;
- end;
- FNotifyList.Expand;
- New(Data);
- Data.Proc := ANotify;
- Data.RefCount := 1;
- FNotifyList.Add(Data);
- end;
- procedure TTBCustomItem.UnregisterNotification(ANotify: TTBItemChangedProc);
- var
- I: Integer;
- Data: PItemChangedNotificationData;
- begin
- if Assigned(FNotifyList) then
- for I := 0 to FNotifyList.Count-1 do begin
- Data := FNotifyList[I];
- if MethodsEqual(TMethod(Data.Proc), TMethod(ANotify)) then begin
- Dec(Data.RefCount);
- if Data.RefCount = 0 then begin
- FNotifyList.Delete(I);
- Dispose(Data);
- if FNotifyList.Count = 0 then begin
- FNotifyList.Free;
- FNotifyList := nil;
- end;
- end;
- Break;
- end;
- end;
- end;
- function TTBCustomItem.GetPopupWindowClass: TTBPopupWindowClass;
- begin
- Result := TTBPopupWindow;
- end;
- procedure TTBCustomItem.DoPopup(Sender: TTBCustomItem; FromLink: Boolean);
- begin
- if Assigned(FOnPopup) then
- FOnPopup(Sender, FromLink);
- if not(tbisCombo in ItemStyle) then
- Click;
- end;
- var
- PlayedSound: Boolean = False;
- procedure TTBCustomItem.GetPopupPosition(ParentView: TTBView;
- PopupWindow: TTBPopupWindow; var PopupPositionRec: TTBPopupPositionRec);
- var
- X2, Y2: Integer;
- RepeatCalcX: Boolean;
- function CountObscured(X, Y, W, H: Integer): Integer;
- var
- I: Integer;
- P: TPoint;
- V: TTBItemViewer;
- begin
- Result := 0;
- if ParentView = nil then
- Exit;
- P := ParentView.FWindow.ClientToScreen(Point(0, 0));
- Dec(X, P.X);
- Dec(Y, P.Y);
- Inc(W, X);
- Inc(H, Y);
- for I := 0 to ParentView.FViewerCount-1 do begin
- V := ParentView.FViewers[I];
- if V.Show and (V.BoundsRect.Left >= X) and (V.BoundsRect.Right <= W) and
- (V.BoundsRect.Top >= Y) and (V.BoundsRect.Bottom <= H) then
- Inc(Result);
- end;
- end;
- begin
- with PopupPositionRec do
- begin
- { Adjust the Y position of the popup window }
- { If the window is going off the bottom of the monitor, try placing it
- above the parent item }
- if (Y + H > MonitorRect.Bottom) and
- ((ParentView = nil) or (ParentView.FOrientation <> tbvoVertical)) then begin
- if not PositionAsSubmenu then
- Y2 := ParentItemRect.Top
- else
- Y2 := ParentItemRect.Bottom + NCSizeY;
- Dec(Y2, H);
- { Only place it above the parent item if it isn't going to go off the
- top of the monitor }
- if Y2 >= MonitorRect.Top then
- Y := Y2;
- end;
- { If it's still going off the bottom (which can be possible if a menu bar
- was off the screen to begin with), clip it to the bottom of the monitor }
- if Y + H > MonitorRect.Bottom then
- Y := MonitorRect.Bottom - H;
- if Y < MonitorRect.Top then
- Y := MonitorRect.Top;
- { Other adjustments to the position of the popup window }
- if not PositionAsSubmenu then begin
- if (ParentView = nil) and (Alignment = tbpaRight) and (X < MonitorRect.Left) then
- Inc(X, W);
- if X + W > MonitorRect.Right then begin
- if Assigned(ParentView) or (Alignment <> tbpaLeft) then
- X := MonitorRect.Right;
- Dec(X, W);
- end;
- if X < MonitorRect.Left then
- X := MonitorRect.Left;
- if (ParentView = nil) or (ParentView.FOrientation <> tbvoVertical) then begin
- Y2 := ParentItemRect.Top - H;
- if Y2 >= MonitorRect.Top then begin
- { Would the popup window obscure less items if it popped out to the
- top instead? }
- if (CountObscured(X, Y2, W, H) < CountObscured(X, Y, W, H)) or
- ((Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
- (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left)) then
- Y := Y2;
- end;
- { Make sure a tall popup window doesn't overlap the parent item }
- if (Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
- (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left) then begin
- if ParentItemRect.Right + W <= MonitorRect.Right then
- X := ParentItemRect.Right
- else
- X := ParentItemRect.Left - W;
- if X < MonitorRect.Top then
- X := MonitorRect.Top;
- end;
- end
- else begin
- X2 := ParentItemRect.Right;
- if X2 + W <= MonitorRect.Right then begin
- { Would the popup window obscure less items if it popped out to the
- right instead? }
- if (CountObscured(X2, Y, W, H) < CountObscured(X, Y, W, H)) or
- ((Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
- (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left)) then
- X := X2;
- end;
- { Make sure a wide popup window doesn't overlap the parent item }
- if (Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
- (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left) then begin
- if ParentItemRect.Bottom + H <= MonitorRect.Bottom then
- Y := ParentItemRect.Bottom
- else
- Y := ParentItemRect.Top - H;
- if Y < MonitorRect.Top then
- Y := MonitorRect.Top;
- end;
- end;
- end
- else begin
- { Make nested submenus go from left to right on the screen. Each it
- runs out of space on the screen, switch directions }
- repeat
- RepeatCalcX := False;
- X2 := X;
- if Opposite or (X2 + W > MonitorRect.Right) then begin
- if Assigned(ParentView) then
- X2 := ParentItemRect.Left + NCSizeX;
- Dec(X2, W);
- if not Opposite then
- Include(PopupWindow.View.FState, vsOppositePopup)
- else begin
- if X2 < MonitorRect.Left then begin
- Opposite := False;
- RepeatCalcX := True;
- end
- else
- Include(PopupWindow.View.FState, vsOppositePopup);
- end;
- end;
- until not RepeatCalcX;
- X := X2;
- if X < MonitorRect.Left then
- X := MonitorRect.Left;
- end;
- { Determine animation direction }
- AnimDir := [];
- if not PositionAsSubmenu then begin
- if Y >= ParentItemRect.Bottom then
- Include(AnimDir, tbadDown)
- else if Y + H <= ParentItemRect.Top then
- Include(AnimDir, tbadUp);
- if X >= ParentItemRect.Right then
- Include(AnimDir, tbadRight)
- else if X + W <= ParentItemRect.Left then
- Include(AnimDir, tbadLeft);
- end
- else begin
- if X + W div 2 >= ParentItemRect.Left + (ParentItemRect.Right - ParentItemRect.Left) div 2 then
- Include(AnimDir, tbadRight)
- else
- Include(AnimDir, tbadLeft);
- end;
- end;
- end;
- function TTBCustomItem.CreatePopup(const ParentView: TTBView;
- const ParentViewer: TTBItemViewer; const PositionAsSubmenu, SelectFirstItem,
- Customizing: Boolean; const APopupPoint: TPoint;
- const Alignment: TTBPopupAlignment): TTBPopupWindow;
- var
- EventItem, ParentItem: TTBCustomItem;
- Opposite: Boolean;
- ChevronParentView: TTBView;
- ChevronMenu: Boolean;
- X, Y, W, H: Integer;
- P: TPoint;
- ParentItemRect: TRect;
- MonitorRect: TRect;
- PopupRec: TTBPopupPositionRec;
- NCSize: TPoint;
- begin
- EventItem := ItemContainingItems(Self);
- if EventItem <> Self then
- EventItem.DoPopup(Self, True);
- DoPopup(Self, False);
- ChevronParentView := GetChevronParentView;
- ChevronMenu := False; // shut up
- if ChevronParentView = nil then
- ParentItem := Self
- else begin
- ParentItem := ChevronParentView.FParentItem;
- Assert(ParentItem.ParentComponent is TTBCustomToolbar);
- ChevronMenu :=
- (ParentItem.ParentComponent is TTBCustomToolbar) and
- TTBCustomToolbar(ParentItem.ParentComponent).ChevronMenu;
- end;
- Opposite := Assigned(ParentView) and (vsOppositePopup in ParentView.FState);
- Result := GetPopupWindowClass.CreatePopupWindow(nil, ParentView, ParentItem,
- Customizing, APopupPoint);
- try
- if Assigned(ChevronParentView) then begin
- ChevronParentView.FreeNotification(Result.View);
- Result.View.FChevronParentView := ChevronParentView;
- Result.View.FIsToolbar := not ChevronMenu;
- Result.View.Style := Result.View.Style +
- (ChevronParentView.Style * [vsAlwaysShowHints]);
- Result.Color := clBtnFace;
- end;
- { Calculate ParentItemRect, and MonitorRect (the rectangle of the monitor
- that the popup window will be confined to) }
- if Assigned(ParentView) then begin
- ParentView.ValidatePositions;
- ParentItemRect := ParentViewer.BoundsRect;
- P := ParentView.FWindow.ClientToScreen(Point(0, 0));
- OffsetRect(ParentItemRect, P.X, P.Y);
- if not IsRectEmpty(ParentView.FMonitorRect) then
- MonitorRect := ParentView.FMonitorRect
- else
- { MP (display menu on correct monitor) }
- MonitorRect := GetRectOfMonitorContainingRect(ParentItemRect, True);
- {MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, False);} {vb-}
- { MP }
- {MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, True);} {vb+}
- end
- else begin
- ParentItemRect.TopLeft := APopupPoint;
- ParentItemRect.BottomRight := APopupPoint;
- {MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, False);} {vb-}
- MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, True); {vb+}
- end;
- Result.View.FMonitorRect := MonitorRect;
- { Initialize item positions and size of the popup window }
- NCSize := Result.GetNCSize;
- if ChevronParentView = nil then
- Result.View.FMaxHeight := (MonitorRect.Bottom - MonitorRect.Top) -
- (NCSize.Y * 2)
- else
- Result.View.WrapOffset := (MonitorRect.Right - MonitorRect.Left) -
- (NCSize.X * 2);
- if SelectFirstItem then
- Result.View.Selected := Result.View.FirstSelectable;
- Result.View.UpdatePositions;
- W := Result.Width;
- H := Result.Height;
- { Calculate initial X,Y position of the popup window }
- if Assigned(ParentView) then begin
- if not PositionAsSubmenu then begin
- if ChevronParentView = nil then begin
- if (ParentView = nil) or (ParentView.FOrientation <> tbvoVertical) then begin
- if GetSystemMetrics(SM_MENUDROPALIGNMENT) = 0 then
- X := ParentItemRect.Left
- else
- X := ParentItemRect.Right - W;
- Y := ParentItemRect.Bottom;
- end
- else begin
- X := ParentItemRect.Left - W;
- Y := ParentItemRect.Top;
- end;
- end
- else begin
- if ChevronParentView.FOrientation <> tbvoVertical then begin
- X := ParentItemRect.Right - W;
- Y := ParentItemRect.Bottom;
- end
- else begin
- X := ParentItemRect.Left - W;
- Y := ParentItemRect.Top;
- end;
- end;
- end
- else begin
- X := ParentItemRect.Right - NCSize.X;
- Y := ParentItemRect.Top - NCSize.Y;
- end;
- end
- else begin
- X := APopupPoint.X;
- Y := APopupPoint.Y;
- case Alignment of
- tbpaRight: Dec(X, W);
- tbpaCenter: Dec(X, W div 2);
- end;
- end;
- PopupRec.PositionAsSubmenu := PositionAsSubmenu;
- PopupRec.Alignment := Alignment;
- PopupRec.Opposite := Opposite;
- PopupRec.MonitorRect := MonitorRect;
- PopupRec.ParentItemRect := ParentItemRect;
- PopupRec.NCSizeX := NCSize.X;
- PopupRec.NCSizeY := NCSize.Y;
- PopupRec.X := X;
- PopupRec.Y := Y;
- PopupRec.W := W;
- PopupRec.H := H;
- PopupRec.AnimDir := [];
- PopupRec.PlaySound := True;
- GetPopupPosition(ParentView, Result, PopupRec);
- X := PopupRec.X;
- Y := PopupRec.Y;
- W := PopupRec.W;
- H := PopupRec.H;
- Result.FAnimationDirection := PopupRec.AnimDir;
- Result.SetBounds(X, Y, W, H);
- if Assigned(ParentView) then begin
- Result.FreeNotification(ParentView);
- ParentView.FOpenViewerWindow := Result;
- ParentView.FOpenViewerView := Result.View;
- ParentView.FOpenViewer := ParentViewer;
- if ParentView.FIsToolbar then begin
- Include(ParentView.FState, vsDropDownMenus);
- ParentView.Invalidate(ParentViewer);
- ParentView.FWindow.Update;
- end;
- end;
- Include(Result.View.FState, vsDrawInOrder);
- if not PopupRec.PlaySound or not NeedToPlaySound('MenuPopup') then begin
- { Don't call PlaySound if we don't have to }
- Result.Visible := True;
- end
- else begin
- if not PlayedSound then begin
- { Work around Windows 2000 "bug" where there's a 1/3 second delay upon the
- first call to PlaySound (or sndPlaySound) by painting the window
- completely first. This way the delay isn't very noticable. }
- PlayedSound := True;
- Result.Visible := True;
- Result.Update;
- PlaySoundA('MenuPopup', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
- end
- else begin
- PlaySoundA('MenuPopup', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
- Result.Visible := True;
- end;
- end;
- NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, Result.View.FWindow.Handle,
- OBJID_CLIENT, CHILDID_SELF);
- { Call NotifyFocusEvent now that the window is visible }
- if Assigned(Result.View.Selected) then
- Result.View.NotifyFocusEvent;
- except
- Result.Free;
- raise;
- end;
- end;
- function TTBCustomItem.OpenPopup(const SelectFirstItem, TrackRightButton: Boolean;
- const PopupPoint: TPoint; const Alignment: TTBPopupAlignment;
- const ReturnClickedItemOnly: Boolean; PositionAsSubmenu: Boolean): TTBCustomItem;
- var
- ModalHandler: TTBModalHandler;
- Popup: TTBPopupWindow;
- DoneActionData: TTBDoneActionData;
- begin
- ModalHandler := TTBModalHandler.Create(0);
- try
- Popup := CreatePopup(nil, nil, PositionAsSubmenu, SelectFirstItem, False, PopupPoint,
- Alignment);
- try
- Include(Popup.View.FState, vsIgnoreFirstMouseUp);
- ModalHandler.RootPopup := Popup;
- ModalHandler.Loop(Popup.View, False, False, False, TrackRightButton);
- DoneActionData := Popup.View.FDoneActionData;
- finally
- ModalHandler.RootPopup := nil;
- { Remove vsModal state from the root view before any TTBView.Destroy
- methods get called, so that NotifyFocusEvent becomes a no-op }
- Exclude(Popup.View.FState, vsModal);
- Popup.Free;
- end;
- finally
- ModalHandler.Free;
- end;
- Result := ProcessDoneAction(DoneActionData, ReturnClickedItemOnly);
- end;
- function TTBCustomItem.Popup(X, Y: Integer; TrackRightButton: Boolean;
- Alignment: TTBPopupAlignment = tbpaLeft;
- ReturnClickedItemOnly: Boolean = False;
- PositionAsSubmenu: Boolean = False): TTBCustomItem;
- var
- P: TPoint;
- begin
- P.X := X;
- P.Y := Y;
- Result := OpenPopup(False, TrackRightButton, P, Alignment,
- ReturnClickedItemOnly, PositionAsSubmenu);
- end;
- function TTBCustomItem.FindItemWithShortCut(AShortCut: TShortCut;
- var ATopmostParent: TTBCustomItem): TTBCustomItem;
- function DoItem(AParentItem: TTBCustomItem; LinkDepth: Integer): TTBCustomItem;
- var
- I: Integer;
- NewParentItem, Item: TTBCustomItem;
- begin
- Result := nil;
- NewParentItem := AParentItem;
- if Assigned(NewParentItem.LinkSubitems) then begin
- NewParentItem := NewParentItem.LinkSubitems;
- Inc(LinkDepth);
- if LinkDepth > 25 then
- Exit; { prevent infinite link recursion }
- end;
- for I := 0 to NewParentItem.Count-1 do begin
- Item := NewParentItem.Items[I];
- if Item.ShortCut = AShortCut then begin
- Result := Item;
- Exit;
- end;
- Result := DoItem(Item, LinkDepth);
- if Assigned(Result) then begin
- ATopmostParent := Item;
- Exit;
- end;
- end;
- end;
- begin
- ATopmostParent := nil;
- Result := DoItem(Self, 0);
- end;
- function TTBCustomItem.IsShortCut(var Message: TWMKey): Boolean;
- var
- ShortCut: TShortCut;
- ShiftState: TShiftState;
- ShortCutItem, TopmostItem, Item, EventItem: TTBCustomItem;
- I: Integer;
- label 1;
- begin
- Result := False;
- ShiftState := KeyDataToShiftState(Message.KeyData);
- ShortCut := Menus.ShortCut(Message.CharCode, ShiftState);
- 1:ShortCutItem := FindItemWithShortCut(ShortCut, TopmostItem);
- if Assigned(ShortCutItem) then begin
- { Send OnPopup/OnClick events to ShortCutItem's parents so that they can
- update the Enabled state of ShortCutItem if needed }
- Item := Self;
- repeat
- if not Item.Enabled then
- Exit;
- EventItem := ItemContainingItems(Item);
- if not(csDesigning in ComponentState) then begin
- for I := 0 to EventItem.Count-1 do
- EventItem.Items[I].InitiateAction;
- end;
- if not(tbisEmbeddedGroup in Item.ItemStyle) then begin
- if EventItem <> Item then begin
- try
- EventItem.DoPopup(Item, True);
- except
- Application.HandleException(Self);
- end;
- end;
- try
- Item.DoPopup(Item, False);
- except
- Application.HandleException(Self);
- end;
- end;
- ShortCutItem := Item.FindItemWithShortCut(ShortCut, TopmostItem);
- if ShortCutItem = nil then
- { Can no longer find the shortcut inside TopmostItem. Start over
- because the shortcut might have moved. }
- goto 1;
- Item := TopmostItem;
- until Item = nil;
- if ShortCutItem.Enabled then begin
- try
- ShortCutItem.Click;
- except
- Application.HandleException(Self);
- end;
- Result := True;
- end;
- end;
- end;
- function TTBCustomItem.GetChevronParentView: TTBView;
- begin
- Result := nil;
- end;
- function TTBCustomItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
- begin
- Result := TTBItemViewer;
- end;
- function TTBCustomItem.NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean;
- begin
- Result := False;
- end;
- function TTBCustomItem.GetShortCutText: String;
- var
- P: Integer;
- begin
- P := Pos(#9, Caption);
- if P = 0 then begin
- if ShortCut <> 0 then
- Result := ShortCutToTextFix(ShortCut)
- else
- Result := '';
- end
- else
- Result := Copy(Caption, P+1, Maxint);
- end;
- procedure TTBCustomItem.Change(NeedResize: Boolean);
- const
- ItemChangedActions: array[Boolean] of TTBItemChangedAction =
- (tbicInvalidate, tbicInvalidateAndResize);
- begin
- if Assigned(FParent) then
- FParent.Notify(ItemChangedActions[NeedResize], -1, Self);
- end;
- procedure TTBCustomItem.RecreateItemViewers;
- begin
- if Assigned(FParent) then
- FParent.Notify(tbicRecreateItemViewers, -1, Self);
- end;
- procedure TTBCustomItem.ImageListChangeHandler(Sender: TObject);
- var
- Resize: Boolean;
- begin
- if Sender = FSubMenuImages then begin
- FSubMenuImagesChangeLink.FLastWidth := FSubMenuImages.Width;
- FSubMenuImagesChangeLink.FLastHeight := FSubMenuImages.Height;
- SubMenuImagesChanged;
- end
- else begin
- { Sender is FImages }
- Resize := False;
- if (FImagesChangeLink.FLastWidth <> FImages.Width) or
- (FImagesChangeLink.FLastHeight <> FImages.Height) then begin
- FImagesChangeLink.FLastWidth := FImages.Width;
- FImagesChangeLink.FLastHeight := FImages.Height;
- Resize := True;
- end;
- Change(Resize);
- end;
- end;
- procedure TTBCustomItem.SubMenuImagesChanged;
- begin
- Notify(tbicSubMenuImagesChanged, -1, nil);
- end;
- procedure TTBCustomItem.TurnSiblingsOff;
- var
- I: Integer;
- Item: TTBCustomItem;
- begin
- if (GroupIndex <> 0) and Assigned(FParent) then begin
- for I := 0 to FParent.Count-1 do begin
- Item := FParent[I];
- if (Item <> Self) and (Item.GroupIndex = GroupIndex) then
- Item.Checked := False;
- end;
- end;
- end;
- procedure TTBCustomItem.SetCaption(Value: String);
- begin
- if FCaption <> Value then begin
- FCaption := Value;
- Change(True);
- end;
- end;
- procedure TTBCustomItem.SetChecked(Value: Boolean);
- begin
- if FChecked <> Value then begin
- FChecked := Value;
- Change(False);
- if Value then
- TurnSiblingsOff;
- end;
- end;
- procedure TTBCustomItem.SetDisplayMode(Value: TTBItemDisplayMode);
- begin
- if FDisplayMode <> Value then begin
- FDisplayMode := Value;
- Change(True);
- end;
- end;
- procedure TTBCustomItem.EnabledChanged;
- begin
- Change(False);
- end;
- procedure TTBCustomItem.SetEnabled(Value: Boolean);
- begin
- if FEnabled <> Value then begin
- FEnabled := Value;
- EnabledChanged;
- end;
- end;
- procedure TTBCustomItem.SetGroupIndex(Value: Integer);
- begin
- if FGroupIndex <> Value then begin
- FGroupIndex := Value;
- if Checked then
- TurnSiblingsOff;
- end;
- end;
- procedure TTBCustomItem.SetImageIndex(Value: TImageIndex);
- var
- HadNoImage: Boolean;
- begin
- if FImageIndex <> Value then begin
- HadNoImage := FImageIndex = -1;
- FImageIndex := Value;
- Change(HadNoImage xor (Value = -1));
- end;
- end;
- function TTBCustomItem.ChangeImages(var AImages: TCustomImageList;
- const Value: TCustomImageList; var AChangeLink: TTBImageChangeLink): Boolean;
- { Returns True if image list was resized }
- var
- LastWidth, LastHeight: Integer;
- begin
- Result := False;
- LastWidth := -1;
- LastHeight := -1;
- if Assigned(AImages) then begin
- LastWidth := AImages.Width;
- LastHeight := AImages.Height;
- AImages.UnregisterChanges(AChangeLink);
- if Value = nil then begin
- AChangeLink.Free;
- AChangeLink := nil;
- Result := True;
- end;
- end;
- AImages := Value;
- if Assigned(Value) then begin
- Result := (Value.Width <> LastWidth) or (Value.Height <> LastHeight);
- if AChangeLink = nil then begin
- AChangeLink := TTBImageChangeLink.Create;
- AChangeLink.FLastWidth := Value.Width;
- AChangeLink.FLastHeight := Value.Height;
- AChangeLink.OnChange := ImageListChangeHandler;
- end;
- Value.RegisterChanges(AChangeLink);
- Value.FreeNotification(Self);
- end;
- end;
- procedure TTBCustomItem.SetImages(Value: TCustomImageList);
- begin
- if FImages <> Value then
- Change(ChangeImages(FImages, Value, FImagesChangeLink));
- end;
- procedure TTBCustomItem.SetSubMenuImages(Value: TCustomImageList);
- begin
- if FSubMenuImages <> Value then begin
- ChangeImages(FSubMenuImages, Value, FSubMenuImagesChangeLink);
- SubMenuImagesChanged;
- end;
- end;
- procedure TTBCustomItem.SetInheritOptions(Value: Boolean);
- begin
- if FInheritOptions <> Value then begin
- FInheritOptions := Value;
- RefreshOptions;
- end;
- end;
- procedure TTBCustomItem.SetLinkSubitems(Value: TTBCustomItem);
- begin
- if Value = Self then
- Value := nil;
- if FLinkSubitems <> Value then begin
- if Assigned(FLinkSubitems) then
- RemoveFromList(FLinkSubitems.FLinkParents, Self);
- FLinkSubitems := Value;
- if Assigned(Value) then begin
- Value.FreeNotification(Self);
- AddToList(Value.FLinkParents, Self);
- end;
- Notify(tbicSubitemsChanged, -1, nil);
- end;
- end;
- function TTBCustomItem.FixOptions(const AOptions: TTBItemOptions): TTBItemOptions;
- begin
- Result := AOptions;
- if not(tboToolbarStyle in Result) then
- Exclude(Result, tboToolbarSize);
- end;
- procedure TTBCustomItem.RefreshOptions;
- const
- NonInheritedOptions = [tboDefault];
- ChangeOptions = [tboDefault, tboDropdownArrow, tboImageAboveCaption,
- tboNoRotation, tboSameWidth, tboToolbarStyle, tboToolbarSize];
- var
- OldOptions, NewOptions: TTBItemOptions;
- I: Integer;
- Item: TTBCustomItem;
- begin
- OldOptions := FEffectiveOptions;
- if FInheritOptions and Assigned(FParent) then
- NewOptions := FParent.FEffectiveOptions - NonInheritedOptions
- else
- NewOptions := [];
- NewOptions := FixOptions(NewOptions - FMaskOptions + FOptions);
- if FEffectiveOptions <> NewOptions then begin
- FEffectiveOptions := NewOptions;
- if (OldOptions * ChangeOptions) <> (NewOptions * ChangeOptions) then
- Change(True);
- for I := 0 to FItemCount-1 do begin
- Item := FItems[I].Item;
- if Item.FInheritOptions then
- Item.RefreshOptions;
- end;
- end;
- end;
- procedure TTBCustomItem.SetMaskOptions(Value: TTBItemOptions);
- begin
- if FMaskOptions <> Value then begin
- FMaskOptions := Value;
- RefreshOptions;
- end;
- end;
- procedure TTBCustomItem.SetOptions(Value: TTBItemOptions);
- begin
- Value := FixOptions(Value);
- if FOptions <> Value then begin
- FOptions := Value;
- RefreshOptions;
- end;
- end;
- procedure TTBCustomItem.SetRadioItem(Value: Boolean);
- begin
- if FRadioItem <> Value then begin
- FRadioItem := Value;
- Change(False);
- end;
- end;
- procedure TTBCustomItem.SetVisible(Value: Boolean);
- begin
- if FVisible <> Value then begin
- FVisible := Value;
- Change(True);
- end;
- end;
- procedure TTBCustomItem.ChangeScale(M, D: Integer);
- var
- I: Integer;
- begin
- for I := 0 to Count - 1 do
- begin
- Items[I].ChangeScale(M, D);
- end;
- end;
- { TTBGroupItem }
- constructor TTBGroupItem.Create(AOwner: TComponent);
- begin
- inherited;
- ItemStyle := ItemStyle + [tbisEmbeddedGroup, tbisSubitemsEditable];
- end;
- { TTBSubmenuItem }
- constructor TTBSubmenuItem.Create(AOwner: TComponent);
- begin
- inherited;
- ItemStyle := ItemStyle + [tbisSubMenu, tbisSubitemsEditable];
- end;
- function TTBSubmenuItem.GetDropdownCombo: Boolean;
- begin
- Result := tbisCombo in ItemStyle;
- end;
- procedure TTBSubmenuItem.SetDropdownCombo(Value: Boolean);
- begin
- if (tbisCombo in ItemStyle) <> Value then begin
- if Value then
- ItemStyle := ItemStyle + [tbisCombo]
- else
- ItemStyle := ItemStyle - [tbisCombo];
- Change(True);
- end;
- end;
- { TTBSeparatorItem }
- constructor TTBSeparatorItem.Create(AOwner: TComponent);
- begin
- inherited;
- ItemStyle := ItemStyle - [tbisSelectable, tbisRedrawOnSelChange,
- tbisRedrawOnMouseOverChange] + [tbisSeparator, tbisClicksTransparent];
- end;
- function TTBSeparatorItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
- begin
- Result := TTBSeparatorItemViewer;
- end;
- procedure TTBSeparatorItem.SetBlank(Value: Boolean);
- begin
- if FBlank <> Value then begin
- FBlank := Value;
- Change(False);
- end;
- end;
- { TTBSeparatorItemViewer }
- procedure TTBSeparatorItemViewer.CalcSize(const Canvas: TCanvas;
- var AWidth, AHeight: Integer);
- begin
- if not IsToolbarStyle then
- Inc(AHeight, DivRoundUp(GetTextHeight(Canvas.Handle) * 2, 3))
- else begin
- AWidth := 6;
- AHeight := 6;
- end;
- end;
- procedure TTBSeparatorItemViewer.Paint(const Canvas: TCanvas;
- const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
- var
- DC: HDC;
- R: TRect;
- ToolbarStyle, Horiz, LineSep: Boolean;
- begin
- DC := Canvas.Handle;
- if TTBSeparatorItem(Item).FBlank then
- Exit;
- R := ClientAreaRect;
- ToolbarStyle := IsToolbarStyle;
- Horiz := not ToolbarStyle or (View.FOrientation = tbvoVertical);
- LineSep := tbisLineSep in State;
- if LineSep then
- Horiz := not Horiz;
- if Horiz then begin
- R.Top := R.Bottom div 2 - 1;
- if not ToolbarStyle then
- InflateRect(R, -tbMenuSeparatorOffset, 0)
- else if LineSep then begin
- if View.FOrientation = tbvoFloating then
- InflateRect(R, -tbLineSepOffset, 0)
- else
- InflateRect(R, -tbDockedLineSepOffset, 0);
- end;
- DrawEdge(DC, R, EDGE_ETCHED, BF_TOP);
- end
- else begin
- R.Left := R.Right div 2 - 1;
- if LineSep then
- InflateRect(R, 0, -tbDockedLineSepOffset);
- DrawEdge(DC, R, EDGE_ETCHED, BF_LEFT);
- end;
- end;
- function TTBSeparatorItemViewer.UsesSameWidth: Boolean;
- begin
- Result := False;
- end;
- { TTBControlItem }
- constructor TTBControlItem.Create(AOwner: TComponent);
- begin
- inherited;
- ItemStyle := ItemStyle - [tbisSelectable] + [tbisClicksTransparent];
- end;
- constructor TTBControlItem.CreateControlItem(AOwner: TComponent;
- AControl: TControl);
- begin
- FControl := AControl;
- AControl.FreeNotification(Self);
- Create(AOwner);
- end;
- destructor TTBControlItem.Destroy;
- begin
- inherited;
- { Free the associated control *after* the item is completely destroyed }
- if not FDontFreeControl and Assigned(FControl) and
- not(csAncestor in FControl.ComponentState) then
- FControl.Free;
- end;
- procedure TTBControlItem.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited;
- if (Operation = opRemove) and (AComponent = FControl) then
- Control := nil;
- end;
- procedure TTBControlItem.SetControl(Value: TControl);
- begin
- if FControl <> Value then begin
- FControl := Value;
- if Assigned(Value) then
- Value.FreeNotification(Self);
- Change(True);
- end;
- end;
- { TTBItemViewer }
- constructor TTBItemViewer.Create(AView: TTBView; AItem: TTBCustomItem;
- AGroupLevel: Integer);
- begin
- FItem := AItem;
- FView := AView;
- FGroupLevel := AGroupLevel;
- ReferenceClickWnd;
- end;
- destructor TTBItemViewer.Destroy;
- begin
- RemoveFromClickList(Self);
- if Assigned(FAccObjectInstance) then begin
- FAccObjectInstance.ClientIsDestroying;
- FAccObjectInstance := nil;
- end;
- inherited;
- ReleaseClickWnd;
- end;
- function TTBItemViewer.GetAccObject: IDispatch;
- begin
- if FAccObjectInstance = nil then begin
- FAccObjectInstance := TTBItemViewerAccObject.Create(Self);
- end;
- Result := FAccObjectInstance;
- end;
- procedure TTBItemViewer.AccSelect(const AExecute: Boolean);
- { Called by ClickWndProc when an item of type TTBItemViewer is in ClickList }
- var
- Obj: IDispatch;
- begin
- { Ensure FAccObjectInstance is created by calling GetAccObject }
- Obj := GetAccObject;
- if Assigned(Obj) then
- (FAccObjectInstance as TTBItemViewerAccObject).HandleAccSelect(AExecute);
- end;
- procedure TTBItemViewer.PostAccSelect(const AExecute: Boolean);
- { Internally called by TTBItemViewerAccObject. Don't call directly. }
- begin
- QueueClick(Self, Ord(AExecute));
- end;
- function TTBItemViewer.IsAccessible: Boolean;
- { Returns True if MSAA clients should know about the viewer, specifically
- if it's either shown, off-edge, or clipped (in other words, not completely
- invisible/inaccessible). }
- begin
- { Note: Can't simply check Item.Visible because the chevron item's Visible
- property is always True }
- Result := Show or OffEdge or Clipped;
- end;
- function TTBItemViewer.GetCaptionText: String;
- var
- P: Integer;
- begin
- Result := Item.Caption;
- P := Pos(#9, Result);
- if P <> 0 then
- SetLength(Result, P-1);
- { MP }
- if IsToolbarStyle and not (vsMenuBar in View.Style) then
- Result := StripAccelChars(StripTrailingPunctuation(Result), True);
- end;
- function TTBItemViewer.GetHintText: String;
- var
- P: Integer;
- LongHint: string;
- HintStyleCaption: string;
- begin
- if Pos('|', Item.Hint) > 0 then
- begin
- Result := GetShortHint(Item.Hint);
- LongHint := GetLongHint(Item.Hint);
- end
- else
- begin
- LongHint := Item.Hint;
- end;
- HintStyleCaption := StripAccelChars(StripTrailingPunctuation(GetCaptionText));
- { If there is no short hint, use the caption for the hint. Like Office,
- strip any trailing colon or ellipsis. }
- if (Result = '') and (not(tboNoAutoHint in Item.EffectiveOptions) or (LongHint <> '')) and
- (not(tbisSubmenu in Item.ItemStyle) or (tbisCombo in Item.ItemStyle) or
- not CaptionShown) then
- Result := HintStyleCaption;
- { Call associated action's OnHint event handler to post-process the hint }
- if Assigned(Item.ActionLink) and
- (Item.ActionLink.Action is TCustomAction) then begin
- if not TCustomAction(Item.ActionLink.Action).DoHint(Result) then
- Result := '';
- { Note: TControlActionLink.DoShowHint actually misinterprets the result
- of DoHint, but we get it right... }
- end;
- if Result = '' then
- Result := LongHint;
- // "Select all" and "Select All" are still the same
- if SameText(LongHint, Result) then
- LongHint := '';
- if CaptionShown and (LongHint = '') and SameText(Result, HintStyleCaption) then
- Result := '';
- { Add shortcut text }
- if (Result <> '') and Application.HintShortCuts then
- begin
- { Custom shortcut }
- P := Pos(#9, Item.Caption);
- if (P <> 0) and (P < Length(Item.Caption)) then
- Result := Format('%s (%s)', [Result, Copy(Item.Caption, P+ 1, MaxInt)])
- else
- if (Item.ShortCut <> scNone) then
- Result := Format('%s (%s)', [Result, ShortCutToTextFix(Item.ShortCut)]);
- end;
- if LongHint <> '' then
- Result := Result + '|' + GetLongHint(LongHint);
- end;
- function TTBItemViewer.CaptionShown: Boolean;
- begin
- Result := (GetCaptionText <> '') and (not IsToolbarSize or
- (Item.ImageIndex < 0) or (Item.DisplayMode in [nbdmTextOnly, nbdmImageAndText])) or
- (tboImageAboveCaption in Item.EffectiveOptions);
- end;
- function TTBItemViewer.ImageShown: Boolean;
- begin
- {}{should also return false if Images=nil (use UsedImageList?)}
- ImageShown := (Item.ImageIndex >= 0) and
- ((Item.DisplayMode in [nbdmDefault, nbdmImageAndText]) or
- (IsToolbarStyle and (Item.DisplayMode = nbdmTextOnlyInMenus)));
- end;
- function TTBItemViewer.GetImageList: TCustomImageList;
- var
- V: TTBView;
- begin
- Result := Item.Images;
- if Assigned(Result) then
- Exit;
- V := View;
- repeat
- if Assigned(V.FCurParentItem) then begin
- Result := V.FCurParentItem.SubMenuImages;
- if Assigned(Result) then
- Break;
- end;
- if Assigned(V.FParentItem) then begin
- Result := V.FParentItem.SubMenuImages;
- if Assigned(Result) then
- Break;
- end;
- V := V.FParentView;
- until V = nil;
- end;
- function TTBItemViewer.IsRotated: Boolean;
- { Returns True if the caption should be drawn with rotated (vertical) text,
- underneath the image }
- begin
- Result := (View.Orientation = tbvoVertical) and
- not (tboNoRotation in Item.EffectiveOptions) and
- not (tboImageAboveCaption in Item.EffectiveOptions);
- end;
- procedure TTBItemViewer.CalcSize(const Canvas: TCanvas;
- var AWidth, AHeight: Integer);
- var
- ToolbarStyle: Boolean;
- DC: HDC;
- TextMetrics: TTextMetric;
- H, LeftMargin: Integer;
- ImgList: TCustomImageList;
- S: String;
- RotatedFont, SaveFont: HFONT;
- begin
- ToolbarStyle := IsToolbarStyle;
- DC := Canvas.Handle;
- ImgList := GetImageList;
- if ToolbarStyle then begin
- AWidth := 6;
- AHeight := 6;
- end
- else begin
- AWidth := 0;
- AHeight := 0;
- end;
- if not ToolbarStyle or CaptionShown then begin
- if not IsRotated then begin
- GetTextMetrics(DC, TextMetrics);
- Inc(AHeight, TextMetrics.tmHeight);
- Inc(AWidth, GetTextWidth(DC, GetCaptionText, True));
- if ToolbarStyle then
- Inc(AWidth, 6);
- end
- else begin
- { Vertical text isn't always the same size as horizontal text, so we have
- to select the rotated font into the DC to get an accurate size }
- RotatedFont := CreateRotatedFont(DC);
- SaveFont := SelectObject(DC, RotatedFont);
- GetTextMetrics(DC, TextMetrics);
- Inc(AWidth, TextMetrics.tmHeight);
- Inc(AHeight, GetTextWidth(DC, GetCaptionText, True));
- if ToolbarStyle then
- Inc(AHeight, 6);
- SelectObject(DC, SaveFont);
- DeleteObject(RotatedFont);
- end;
- end;
- if ToolbarStyle and ImageShown and Assigned(ImgList) then begin
- if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then begin
- Inc(AWidth, ImgList.Width + 1);
- if AHeight < ImgList.Height + 6 then
- AHeight := ImgList.Height + 6;
- end
- else begin
- Inc(AHeight, ImgList.Height);
- if AWidth < ImgList.Width + 7 then
- AWidth := ImgList.Width + 7;
- end;
- end;
- if ToolbarStyle and (tbisSubmenu in Item.ItemStyle) then begin
- if tbisCombo in Item.ItemStyle then
- Inc(AWidth, tbDropdownComboArrowWidth)
- else
- if tboDropdownArrow in Item.EffectiveOptions then begin
- if View.Orientation <> tbvoVertical then
- Inc(AWidth, tbDropdownArrowWidth)
- else
- Inc(AHeight, tbDropdownArrowWidth);
- end;
- end;
- if not ToolbarStyle then begin
- Inc(AHeight, TextMetrics.tmExternalLeading + tbMenuVerticalMargin);
- if Assigned(ImgList) then begin
- H := ImgList.Height + 3;
- if H > AHeight then
- AHeight := H;
- LeftMargin := MulDiv(ImgList.Width + 3, AHeight, H);
- end
- else
- LeftMargin := AHeight;
- Inc(AWidth, LeftMargin + tbMenuImageTextSpace + tbMenuLeftTextMargin +
- tbMenuRightTextMargin);
- S := Item.GetShortCutText;
- if S <> '' then
- Inc(AWidth, (AHeight - 6) + GetTextWidth(DC, S, True));
- Inc(AWidth, AHeight);
- end;
- end;
- procedure TTBItemViewer.DrawItemCaption(const Canvas: TCanvas; ARect: TRect;
- const ACaption: String; ADrawDisabledShadow: Boolean; AFormat: UINT);
- var
- DC: HDC;
- procedure Draw;
- begin
- if not IsRotated then
- DrawText(DC, PChar(ACaption), Length(ACaption), ARect, AFormat)
- else
- DrawRotatedText(DC, ACaption, ARect, AFormat);
- end;
- var
- ShadowColor, HighlightColor, SaveTextColor: DWORD;
- begin
- DC := Canvas.Handle;
- if not ADrawDisabledShadow then
- Draw
- else begin
- ShadowColor := GetSysColor(COLOR_BTNSHADOW);
- HighlightColor := GetSysColor(COLOR_BTNHIGHLIGHT);
- OffsetRect(ARect, 1, 1);
- SaveTextColor := SetTextColor(DC, HighlightColor);
- Draw;
- OffsetRect(ARect, -1, -1);
- SetTextColor(DC, ShadowColor);
- Draw;
- SetTextColor(DC, SaveTextColor);
- end;
- end;
- procedure TTBItemViewer.Paint(const Canvas: TCanvas;
- const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
- var
- ShowEnabled, HasArrow: Boolean;
- MenuCheckWidth, MenuCheckHeight: Integer;
- function GetDrawTextFlags: UINT;
- begin
- Result := 0;
- if not AreKeyboardCuesEnabled and (vsUseHiddenAccels in View.FStyle) and
- not(vsShowAccels in View.FState) then
- Result := DT_HIDEPREFIX;
- end;
- procedure DrawSubmenuArrow;
- var
- BR: TRect;
- Bmp: TBitmap;
- procedure DrawWithColor(AColor: TColor);
- const
- ROP_DSPDxax = $00E20746;
- var
- DC: HDC;
- SaveTextColor, SaveBkColor: TColorRef;
- begin
- Canvas.Brush.Color := AColor;
- DC := Canvas.Handle;
- SaveTextColor := SetTextColor(DC, clWhite);
- SaveBkColor := SetBkColor(DC, clBlack);
- BitBlt(DC, BR.Left, BR.Top, MenuCheckWidth, MenuCheckHeight,
- Bmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
- SetBkColor(DC, SaveBkColor);
- SetTextColor(DC, SaveTextColor);
- Canvas.Brush.Style := bsClear;
- end;
- begin
- Bmp := TBitmap.Create;
- try
- Bmp.Monochrome := True;
- Bmp.Width := MenuCheckWidth;
- Bmp.Height := MenuCheckHeight;
- BR := Rect(0, 0, MenuCheckWidth, MenuCheckHeight);
- DrawFrameControl(Bmp.Canvas.Handle, BR, DFC_MENU, DFCS_MENUARROW);
- OffsetRect(BR, ClientAreaRect.Right - MenuCheckWidth,
- ClientAreaRect.Top + ((ClientAreaRect.Bottom - ClientAreaRect.Top) - MenuCheckHeight) div 2);
- if not UseDisabledShadow then begin
- if ShowEnabled and (tbisCombo in Item.ItemStyle) and IsSelected then begin
- OffsetRect(BR, 1, 1);
- DrawWithColor(clBtnText);
- end
- else
- DrawWithColor(Canvas.Font.Color);
- end
- else begin
- OffsetRect(BR, 1, 1);
- DrawWithColor(clBtnHighlight);
- OffsetRect(BR, -1, -1);
- DrawWithColor(clBtnShadow);
- end;
- finally
- Bmp.Free;
- end;
- end;
- procedure DrawDropdownArrow(R: TRect; Rotated: Boolean);
- procedure DrawWithColor(AColor: TColor);
- var
- X, Y: Integer;
- P: array[0..2] of TPoint;
- begin
- X := (R.Left + R.Right) div 2;
- Y := (R.Top + R.Bottom) div 2;
- if not Rotated then begin
- Dec(Y);
- P[0].X := X-2;
- P[0].Y := Y;
- P[1].X := X+2;
- P[1].Y := Y;
- P[2].X := X;
- P[2].Y := Y+2;
- end
- else begin
- Dec(X);
- P[0].X := X;
- P[0].Y := Y+2;
- P[1].X := X;
- P[1].Y := Y-2;
- P[2].X := X-2;
- P[2].Y := Y;
- end;
- Canvas.Pen.Color := AColor;
- Canvas.Brush.Color := AColor;
- Canvas.Polygon(P);
- end;
- begin
- if not UseDisabledShadow then
- DrawWithColor(Canvas.Font.Color)
- else begin
- OffsetRect(R, 1, 1);
- DrawWithColor(clBtnHighlight);
- OffsetRect(R, -1, -1);
- DrawWithColor(clBtnShadow);
- end;
- end;
- function GetDitherBitmap: TBitmap;
- begin
- Result := AllocPatternBitmap(clBtnFace, clBtnHighlight);
- Result.HandleType := bmDDB; { needed for Win95, or else brush is solid white }
- end;
- const
- EdgeStyles: array[Boolean] of UINT = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
- CheckMarkPoints: array[0..11] of TPoint = (
- { Black }
- (X: -2; Y: -2), (X: 0; Y: 0), (X: 4; Y: -4),
- (X: 4; Y: -3), (X: 0; Y: 1), (X: -2; Y: -1),
- (X: -2; Y: -2),
- { White }
- (X: -3; Y: -2), (X: -3; Y: -1), (X: 0; Y: 2),
- (X: 5; Y: -3), (X: 5; Y: -5));
- var
- ToolbarStyle, ImageIsShown: Boolean;
- R, RC, RD: TRect;
- S: String;
- ImgList: TCustomImageList;
- I, X, Y: Integer;
- Points: array[0..11] of TPoint;
- DrawTextFlags: UINT;
- LeftMargin: Integer;
- TextMetrics: TTextMetric;
- begin
- ToolbarStyle := IsToolbarStyle;
- ShowEnabled := Item.Enabled or View.Customizing;
- HasArrow := (tbisSubmenu in Item.ItemStyle) and
- ((tbisCombo in Item.ItemStyle) or (tboDropdownArrow in Item.EffectiveOptions));
- MenuCheckWidth := GetSystemMetricsForControl(View.FWindow, SM_CXMENUCHECK);
- MenuCheckHeight := GetSystemMetricsForControl(View.FWindow, SM_CYMENUCHECK);
- ImgList := GetImageList;
- ImageIsShown := ImageShown and Assigned(ImgList);
- LeftMargin := 0;
- if not ToolbarStyle then begin
- if Assigned(ImgList) then
- LeftMargin := MulDiv(ImgList.Width + 3, ClientAreaRect.Bottom, ImgList.Height + 3)
- else
- LeftMargin := ClientAreaRect.Bottom;
- end;
- { Border }
- RC := ClientAreaRect;
- if ToolbarStyle then begin
- if HasArrow then begin
- if tbisCombo in Item.ItemStyle then begin
- Dec(RC.Right, tbDropdownComboMargin);
- RD := RC;
- Dec(RC.Right, tbDropdownComboArrowWidth - tbDropdownComboMargin);
- RD.Left := RC.Right;
- end
- else begin
- if View.Orientation <> tbvoVertical then
- RD := Rect(RC.Right - tbDropdownArrowWidth - tbDropdownArrowMargin, 0,
- RC.Right - tbDropdownArrowMargin, RC.Bottom)
- else
- RD := Rect(0, RC.Bottom - tbDropdownArrowWidth - tbDropdownArrowMargin,
- RC.Right, RC.Bottom - tbDropdownArrowMargin);
- end;
- end
- else
- SetRectEmpty(RD);
- if (IsSelected and ShowEnabled) or Item.Checked or
- (csDesigning in Item.ComponentState) then begin
- if not(tbisCombo in Item.ItemStyle) then
- DrawEdge(Canvas.Handle, RC, EdgeStyles[IsPushed or Item.Checked], BF_RECT)
- else begin
- DrawEdge(Canvas.Handle, RC, EdgeStyles[(IsPushed and View.FCapture) or Item.Checked], BF_RECT);
- if (IsSelected and ShowEnabled) or
- (csDesigning in Item.ComponentState) then
- DrawEdge(Canvas.Handle, RD, EdgeStyles[IsPushed and not View.FCapture], BF_RECT);
- end;
- end;
- if HasArrow then begin
- if not(tbisCombo in Item.ItemStyle) and IsPushed then
- OffsetRect(RD, 1, 1);
- DrawDropdownArrow(RD, not(tbisCombo in Item.ItemStyle) and
- (View.Orientation = tbvoVertical));
- end;
- InflateRect(RC, -1, -1);
- if Item.Checked and not (IsSelected and ShowEnabled) then begin
- Canvas.Brush.Bitmap := GetDitherBitmap;
- Canvas.FillRect(RC);
- Canvas.Brush.Style := bsClear;
- end;
- InflateRect(RC, -1, -1);
- if Item.Checked or
- ((IsSelected and IsPushed) and
- (not(tbisCombo in Item.ItemStyle) or View.FCapture)) then
- OffsetRect(RC, 1, 1);
- if HasArrow and not(tbisCombo in Item.ItemStyle) then begin
- if View.Orientation <> tbvoVertical then
- Dec(RC.Right, tbDropdownArrowWidth)
- else
- Dec(RC.Bottom, tbDropdownArrowWidth);
- end;
- end
- else begin
- { On selected menu items, fill the background with the selected color.
- Note: This assumes the brush color was not changed from the initial
- value. }
- if IsSelected then begin
- R := RC;
- if ImageIsShown or Item.Checked then
- Inc(R.Left, LeftMargin + tbMenuImageTextSpace);
- if (tbisCombo in Item.ItemStyle) and IsSelected and ShowEnabled then
- Dec(R.Right, MenuCheckWidth);
- Canvas.FillRect(R);
- end;
- end;
- { Adjust brush & font }
- Canvas.Brush.Style := bsClear;
- if tboDefault in Item.EffectiveOptions then
- with Canvas.Font do Style := Style + [fsBold];
- GetTextMetrics(Canvas.Handle, TextMetrics);
- { Caption }
- if CaptionShown then begin
- S := GetCaptionText;
- R := RC;
- DrawTextFlags := GetDrawTextFlags;
- if ToolbarStyle then begin
- if ImageIsShown then begin
- if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then
- Inc(R.Left, ImgList.Width + 1)
- else
- Inc(R.Top, ImgList.Height + 1);
- end;
- DrawItemCaption(Canvas, R, S, UseDisabledShadow,
- DT_SINGLELINE or DT_CENTER or DT_VCENTER or DrawTextFlags)
- end
- else begin
- Inc(R.Left, LeftMargin + tbMenuImageTextSpace + tbMenuLeftTextMargin);
- { Like standard menus, shift the text up one pixel if the text height
- is 4 pixels less than the total item height. This is done so underlined
- characters aren't displayed too low. }
- if (R.Bottom - R.Top) - (TextMetrics.tmHeight + TextMetrics.tmExternalLeading) = tbMenuVerticalMargin then
- Dec(R.Bottom);
- Inc(R.Top, TextMetrics.tmExternalLeading);
- DrawItemCaption(Canvas, R, S, UseDisabledShadow,
- DT_SINGLELINE or DT_LEFT or DT_VCENTER or DrawTextFlags);
- end;
- end;
- { Shortcut and/or submenu arrow (menus only) }
- if not ToolbarStyle then begin
- S := Item.GetShortCutText;
- if S <> '' then begin
- R := RC;
- R.Left := R.Right - (R.Bottom - R.Top) - GetTextWidth(Canvas.Handle, S, True);
- { Like standard menus, shift the text up one pixel if the text height
- is 4 pixels less than the total item height. This is done so underlined
- characters aren't displayed too low. }
- if (R.Bottom - R.Top) - (TextMetrics.tmHeight + TextMetrics.tmExternalLeading) = tbMenuVerticalMargin then
- Dec(R.Bottom);
- Inc(R.Top, TextMetrics.tmExternalLeading);
- DrawItemCaption(Canvas, R, S, UseDisabledShadow,
- DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_NOPREFIX);
- end;
- if tbisSubmenu in Item.ItemStyle then begin
- if tbisCombo in Item.ItemStyle then begin
- R := RC;
- R.Left := R.Right - MenuCheckWidth;
- if IsSelected and ShowEnabled then
- DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_RECT or BF_MIDDLE)
- else begin
- Dec(R.Left);
- if not IsSelected then
- DrawEdge(Canvas.Handle, R, EDGE_ETCHED, BF_LEFT)
- else
- DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_LEFT);
- end;
- end;
- DrawSubmenuArrow;
- end;
- end;
- { Image, or check box }
- if ImageIsShown or (not ToolbarStyle and Item.Checked) then begin
- R := RC;
- if ToolbarStyle then begin
- if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then
- R.Right := R.Left + ImgList.Width + 2
- else
- R.Bottom := R.Top + ImgList.Height + 2;
- end
- else begin
- R.Right := R.Left + LeftMargin;
- if (IsSelected and ShowEnabled) or Item.Checked then
- DrawEdge(Canvas.Handle, R, EdgeStyles[Item.Checked], BF_RECT or BF_MIDDLE);
- if Item.Checked and not IsSelected then begin
- InflateRect(R, -1, -1);
- Canvas.Brush.Bitmap := GetDitherBitmap;
- Canvas.FillRect(R);
- Canvas.Brush.Style := bsClear;
- InflateRect(R, 1, 1);
- end;
- if Item.Checked then
- OffsetRect(R, 1, 1);
- end;
- if ImageIsShown then begin
- X := R.Left + ((R.Right - R.Left) - ImgList.Width) div 2;
- Y := R.Top + ((R.Bottom - R.Top) - ImgList.Height) div 2;
- if ImgList is TTBCustomImageList then
- TTBCustomImageList(ImgList).DrawState(Canvas, X, Y, Item.ImageIndex,
- ShowEnabled, IsSelected, Item.Checked)
- else
- ImgList.Draw(Canvas, X, Y, Item.ImageIndex, ShowEnabled);
- end
- else
- if not ToolbarStyle and Item.Checked then begin
- { Draw default check mark or radio button image when user hasn't
- specified their own }
- X := (R.Left + R.Right) div 2;
- Y := (R.Top + R.Bottom) div 2;
- if Item.RadioItem then begin
- Canvas.Pen.Color := clBtnText;
- Canvas.Brush.Color := clBtnText;
- Canvas.RoundRect(X-3, Y-3, X+2, Y+2, 2, 2);
- Canvas.Pen.Color := clBtnHighlight;
- Canvas.Brush.Style := bsClear;
- Canvas.RoundRect(X-4, Y-4, X+3, Y+3, 6, 6);
- end
- else begin
- Dec(X, 2);
- Inc(Y);
- System.Move(CheckMarkPoints, Points, 12 * SizeOf(TPoint));
- for I := Low(Points) to High(Points) do begin
- Inc(Points[I].X, X);
- Inc(Points[I].Y, Y);
- end;
- Canvas.Pen.Color := clBtnText;
- Polyline(Canvas.Handle, Points[0], 7);
- Canvas.Pen.Color := clBtnHighlight;
- Polyline(Canvas.Handle, Points[7], 5);
- end;
- end;
- end;
- end;
- procedure TTBItemViewer.GetCursor(const Pt: TPoint; var ACursor: HCURSOR);
- begin
- end;
- function TTBItemViewer.GetIndex: Integer;
- begin
- Result := View.IndexOf(Self);
- end;
- function TTBItemViewer.IsToolbarSize: Boolean;
- begin
- Result := View.FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
- end;
- function TTBItemViewer.IsToolbarStyle: Boolean;
- begin
- Result := View.FIsToolbar or (tboToolbarStyle in Item.FEffectiveOptions);
- end;
- function TTBItemViewer.IsPtInButtonPart(X, Y: Integer): Boolean;
- var
- W: Integer;
- begin
- Result := not(tbisSubmenu in Item.ItemStyle);
- if tbisCombo in Item.ItemStyle then begin
- if IsToolbarStyle then
- W := tbDropdownComboArrowWidth
- else
- W := GetSystemMetricsForControl(View.FWindow, SM_CXMENUCHECK);
- Result := X < (BoundsRect.Right - BoundsRect.Left) - W;
- end;
- end;
- procedure TTBItemViewer.MouseDown(Shift: TShiftState; X, Y: Integer;
- var MouseDownOnMenu: Boolean);
- procedure HandleDefaultDoubleClick(const View: TTBView);
- { Looks for a tboDefault item in View and ends the modal loop if it finds
- one. }
- var
- I: Integer;
- Viewer: TTBItemViewer;
- Item: TTBCustomItem;
- begin
- for I := 0 to View.FViewerCount-1 do begin
- Viewer := View.FViewers[I];
- Item := Viewer.Item;
- if (Viewer.Show or Viewer.Clipped) and (tboDefault in Item.EffectiveOptions) and
- (tbisSelectable in Item.ItemStyle) and Item.Enabled and Item.Visible then begin
- Viewer.Execute(True);
- Break;
- end;
- end;
- end;
- var
- WasAlreadyOpen: Boolean;
- begin
- if not Item.Enabled then begin
- if (View.FParentView = nil) and not View.FIsPopup then
- View.EndModal;
- Exit;
- end;
- if IsPtInButtonPart(X, Y) then begin
- if IsToolbarStyle then begin
- View.CancelChildPopups;
- View.SetCapture;
- View.Invalidate(Self);
- end;
- end
- else begin
- WasAlreadyOpen := (View.FOpenViewer = Self);
- if View.OpenChildPopup(False) then begin
- if WasAlreadyOpen and ((View.FParentView = nil) and not View.FIsPopup) then
- MouseDownOnMenu := True;
- if (ssDouble in Shift) and not(tbisCombo in Item.ItemStyle) then
- HandleDefaultDoubleClick(View.FOpenViewerView);
- end;
- end;
- end;
- procedure TTBItemViewer.MouseMove(X, Y: Integer);
- begin
- end;
- procedure TTBItemViewer.MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean);
- var
- HadCapture, IsToolbarItem: Boolean;
- begin
- HadCapture := View.FCapture;
- View.CancelCapture;
- IsToolbarItem := (View.FParentView = nil) and not View.FIsPopup;
- if not View.FMouseOverSelected or not Item.Enabled or
- (tbisClicksTransparent in Item.ItemStyle) then begin
- if IsToolbarItem then
- View.EndModal;
- Exit;
- end;
- if (tbisSubmenu in Item.ItemStyle) and not IsPtInButtonPart(X, Y) then begin
- if IsToolbarItem and MouseWasDownOnMenu then
- View.EndModal;
- end
- else begin
- { it's a 'normal' item }
- if not IsToolbarStyle or HadCapture then
- Execute(True);
- end;
- end;
- procedure TTBItemViewer.MouseWheel(WheelDelta, X, Y: Integer);
- begin
- end;
- procedure TTBItemViewer.LosingCapture;
- begin
- View.Invalidate(Self);
- end;
- procedure TTBItemViewer.Entering(OldSelected: TTBItemViewer);
- begin
- if Assigned(Item.FOnSelect) then
- Item.FOnSelect(Item, Self, True);
- end;
- procedure TTBItemViewer.Leaving;
- begin
- if Assigned(Item.FOnSelect) then
- Item.FOnSelect(Item, Self, False);
- end;
- procedure TTBItemViewer.KeyDown(var Key: Word; Shift: TShiftState);
- begin
- end;
- function TTBItemViewer.ScreenToClient(const P: TPoint): TPoint;
- begin
- Result := View.FWindow.ScreenToClient(P);
- Dec(Result.X, BoundsRect.Left);
- Dec(Result.Y, BoundsRect.Top);
- end;
- function TTBItemViewer.UsesSameWidth: Boolean;
- { If UsesSameWidth returns True, the item viewer's width will be expanded to
- match the widest item viewer on the same view whose UsesSameWidth method
- also returns True. }
- begin
- Result := (tboImageAboveCaption in Item.FEffectiveOptions) and
- (tboSameWidth in Item.FEffectiveOptions) and IsToolbarSize;
- end;
- function TTBItemViewer.DoExecute: Boolean;
- { Low-level 'execute' handler. Returns True if the caller should call
- GivePriority on the viewer (normally, if the 'execute' operation was a
- success and the modal loop is ending). }
- begin
- View.EndModalWithClick(Self);
- Result := True;
- end;
- procedure TTBItemViewer.Execute(AGivePriority: Boolean);
- { Calls DoExecute and, if applicable, View.GivePriority. Note that it is up to
- the caller to check the viewer's visibility and enabled state. }
- begin
- if DoExecute and AGivePriority then
- View.GivePriority(Self);
- end;
- function TTBItemViewer.GetAccRole: Integer;
- { Returns the MSAA "role" of the viewer. }
- const
- { Constants from OleAcc.h }
- ROLE_SYSTEM_CLIENT = $a;
- ROLE_SYSTEM_MENUITEM = $c;
- ROLE_SYSTEM_SEPARATOR = $15;
- ROLE_SYSTEM_PUSHBUTTON = $2b;
- ROLE_SYSTEM_BUTTONMENU = $39;
- begin
- if Item is TTBControlItem then
- Result := ROLE_SYSTEM_CLIENT
- else if tbisSeparator in Item.ItemStyle then
- Result := ROLE_SYSTEM_SEPARATOR
- else if View.IsPopup or (vsMenuBar in View.Style) then
- Result := ROLE_SYSTEM_MENUITEM
- else if tbisSubmenu in Item.ItemStyle then
- Result := ROLE_SYSTEM_BUTTONMENU
- else
- Result := ROLE_SYSTEM_PUSHBUTTON;
- end;
- function TTBItemViewer.GetAccValue(var Value: WideString): Boolean;
- { Gets the MSAA "value" text of the viewer. Returns True if something was
- assigned to Value, or False if the viewer does not possess a "value". }
- begin
- Result := False;
- end;
- { TTBView }
- constructor TTBView.CreateView(AOwner: TComponent; AParentView: TTBView;
- AParentItem: TTBCustomItem; AWindow: TWinControl;
- AIsToolbar, ACustomizing, AUsePriorityList: Boolean);
- begin
- Create(AOwner);
- FBackgroundColor := clDefault;
- FCustomizing := ACustomizing;
- FIsPopup := not AIsToolbar;
- FIsToolbar := AIsToolbar;
- FNewViewersGetHighestPriority := True;
- FParentView := AParentView;
- FParentItem := AParentItem;
- if Assigned(FParentItem) then begin
- //FIsToolbar := FIsToolbar or FParentItem.FDisplayAsToolbar;
- FParentItem.RegisterNotification(LinkNotification);
- FParentItem.FreeNotification(Self);
- end;
- FUsePriorityList := AUsePriorityList;
- FWindow := AWindow;
- UpdateCurParentItem;
- end;
- destructor TTBView.Destroy;
- begin
- CloseChildPopups;
- if Assigned(FAccObjectInstance) then begin
- FAccObjectInstance.ClientIsDestroying;
- { Get rid of our own reference to FAccObjectInstance. Normally the
- reference count will be now be zero and FAccObjectInstance will be
- freed, unless MSAA still holds a reference. }
- FAccObjectInstance._Release;
- FAccObjectInstance := nil;
- end;
- { If parent view is a toolbar, invalidate the open item so that it's
- redrawn back in the "up" position }
- if Assigned(ParentView) and ParentView.FIsToolbar then begin
- Include(ParentView.FState, vsNoAnimation);
- if Assigned(ParentView.FOpenViewer) then
- ParentView.Invalidate(ParentView.FOpenViewer);
- end;
- if Assigned(FCurParentItem) then
- FCurParentItem.UnregisterNotification(ItemNotification);
- if Assigned(FParentItem) then
- FParentItem.UnregisterNotification(LinkNotification);
- inherited;
- FPriorityList.Free;
- FreeViewers;
- { Now that we're destroyed, "focus" the parent view }
- if Assigned(FParentView) then
- FParentView.NotifyFocusEvent;
- end;
- function TTBView.GetAccObject: IDispatch;
- begin
- if FAccObjectInstance = nil then begin
- FAccObjectInstance := TTBViewAccObject.Create(Self);
- { Strictly as an optimization, take a reference for ourself and keep it
- for the lifetime of the view. (Destroy calls _Release.) }
- FAccObjectInstance._AddRef;
- end;
- Result := FAccObjectInstance;
- end;
- function TTBView.HandleWMGetObject(var Message: TMessage): Boolean;
- begin
- if (Message.LParam = Integer(OBJID_CLIENT)) then begin
- Message.Result := LresultFromObject(ITBAccessible, Message.WParam, GetAccObject);
- Result := True;
- end
- else
- Result := False;
- end;
- procedure TTBView.UpdateCurParentItem;
- var
- Value: TTBCustomItem;
- begin
- Value := ItemContainingItems(FParentItem);
- if FCurParentItem <> Value then begin
- CloseChildPopups;
- if Assigned(FCurParentItem) then
- FCurParentItem.UnregisterNotification(ItemNotification);
- FCurParentItem := Value;
- if Assigned(Value) then
- Value.RegisterNotification(ItemNotification);
- RecreateAllViewers;
- if Assigned(Value) and not(csDesigning in Value.ComponentState) then
- InitiateActions;
- end;
- end;
- procedure TTBView.InitiateActions;
- var
- I: Integer;
- begin
- { Use a 'while' instead of a 'for' since an InitiateAction implementation
- may add/delete items }
- I := 0;
- while I < FViewerCount do begin
- FViewers[I].Item.InitiateAction;
- Inc(I);
- end;
- end;
- procedure TTBView.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- inherited;
- if Operation = opRemove then begin
- if AComponent = FParentItem then begin
- FParentItem := nil;
- UpdateCurParentItem;
- if Assigned(FParentView) then
- FParentView.CloseChildPopups;
- end
- else if AComponent = FOpenViewerWindow then begin
- FOpenViewerWindow := nil;
- FOpenViewerView := nil;
- FOpenViewer := nil;
- end
- else if AComponent = FChevronParentView then
- FChevronParentView := nil;
- end
- end;
- function TTBView.ContainsView(AView: TTBView): Boolean;
- begin
- while Assigned(AView) and (AView <> Self) do
- AView := AView.FParentView;
- Result := Assigned(AView);
- end;
- function TTBView.GetRootView: TTBView;
- begin
- Result := Self;
- while Assigned(Result.FParentView) do
- Result := Result.FParentView;
- end;
- function TTBView.GetParentToolbarView: TTBView;
- begin
- Result := Self;
- while Assigned(Result) and not Result.FIsToolbar do
- Result := Result.FParentView;
- end;
- procedure TTBView.FreeViewers;
- var
- VI: PTBItemViewerArray;
- I, C: Integer;
- begin
- if Assigned(FViewers) then begin
- VI := FViewers;
- C := FViewerCount;
- FViewers := nil;
- FViewerCount := 0;
- for I := C-1 downto 0 do
- FreeAndNil(VI[I]);
- FreeMem(VI);
- end;
- end;
- procedure TTBView.InvalidatePositions;
- begin
- if FValidated then begin
- FValidated := False;
- if Assigned(FWindow) and FWindow.HandleAllocated then
- InvalidateRect(FWindow.Handle, nil, True);
- end;
- end;
- procedure TTBView.ValidatePositions;
- begin
- if not FValidated then
- UpdatePositions;
- end;
- procedure TTBView.TryValidatePositions;
- begin
- if (FUpdating = 0) and
- (not Assigned(FParentItem) or not(csLoading in FParentItem.ComponentState)) and
- (not Assigned(FParentItem.Owner) or not(csLoading in FParentItem.Owner.ComponentState)) then
- ValidatePositions;
- end;
- (*procedure TTBView.TryRevalidatePositions;
- begin
- if FValidated then begin
- if FUpdating = 0 then begin
- FreePositions;
- UpdatePositions;
- end
- else
- InvalidatePositions;
- end;
- end;*)
- function TTBView.Find(Item: TTBCustomItem): TTBItemViewer;
- var
- I: Integer;
- begin
- for I := 0 to FViewerCount-1 do
- if FViewers[I].Item = Item then begin
- Result := FViewers[I];
- Exit;
- end;
- raise ETBItemError.Create(STBViewerNotFound);
- end;
- function TTBView.IndexOf(AViewer: TTBItemViewer): Integer;
- var
- I: Integer;
- begin
- if Assigned(AViewer) then
- for I := 0 to FViewerCount-1 do
- if FViewers[I] = AViewer then begin
- Result := I;
- Exit;
- end;
- Result := -1;
- end;
- procedure TTBView.DeletingViewer(Viewer: TTBItemViewer);
- begin
- if FSelected = Viewer then
- FSelected := nil;
- if FOpenViewer = Viewer then
- CloseChildPopups;
- end;
- procedure TTBView.RecreateItemViewer(const I: Integer);
- var
- OldViewer, NewViewer: TTBItemViewer;
- J: Integer;
- begin
- OldViewer := FViewers[I];
- DeletingViewer(OldViewer);
- NewViewer := OldViewer.Item.GetItemViewerClass(Self).Create(Self,
- OldViewer.Item, OldViewer.FGroupLevel);
- FViewers[I] := NewViewer;
- if Assigned(FPriorityList) then begin
- J := FPriorityList.IndexOf(OldViewer);
- if J <> -1 then
- FPriorityList[J] := NewViewer;
- end;
- OldViewer.Free;
- end;
- function TTBView.InsertItemViewers(const NewIndex: Integer;
- const AItem: TTBCustomItem; const AGroupLevel: Integer;
- const AddToPriorityList, TopOfPriorityList: Boolean): Integer;
- var
- NewViewer: TTBItemViewer;
- LinkItem: TTBCustomItem;
- I: Integer;
- begin
- if AGroupLevel > MaxGroupLevel then begin
- Result := 0;
- Exit;
- end;
- NewViewer := AItem.GetItemViewerClass(Self).Create(Self, AItem,
- AGroupLevel);
- InsertIntoViewerArray(FViewers, FViewerCount, NewIndex,
- NewViewer);
- if AddToPriorityList and FUsePriorityList then begin
- if not TopOfPriorityList then
- AddToList(FPriorityList, NewViewer)
- else
- { When new items are inserted programmatically at run-time, place
- them at the top of FPriorityList }
- AddToFrontOfList(FPriorityList, NewViewer);
- end;
- Result := 1;
- { If a new group item is being inserted, insert all its child items too }
- if not FCustomizing and (tbisEmbeddedGroup in AItem.ItemStyle) then begin
- LinkItem := ItemContainingItems(AItem);
- for I := 0 to LinkItem.Count-1 do begin
- Inc(Result, InsertItemViewers(NewIndex + Result, LinkItem.FItems[I].Item,
- AGroupLevel + 1, AddToPriorityList, TopOfPriorityList));
- end;
- end;
- end;
- procedure TTBView.ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- procedure ItemInserted;
- var
- NewLevel, Start, InsertPoint, Last: Integer;
- GroupItem, NextItem: TTBCustomItem;
- Found, SearchAgain: Boolean;
- begin
- InvalidatePositions;
- NewLevel := 0;
- Start := 0;
- if Ancestor = FCurParentItem then
- InsertPoint := FViewerCount
- else begin
- { Ancestor <> FCurParentItem, so apparently an item has been inserted
- inside a group item }
- repeat
- Found := False;
- while Start < FViewerCount do begin
- GroupItem := FViewers[Start].Item;
- if (tbisEmbeddedGroup in GroupItem.ItemStyle) and (GroupItem = Ancestor) then begin
- NewLevel := FViewers[Start].FGroupLevel + 1;
- Inc(Start);
- Found := True;
- Break;
- end;
- Inc(Start);
- end;
- if not Found then
- { Couldn't find Ancestor; it shouldn't get here }
- Exit;
- InsertPoint := Start;
- SearchAgain := False;
- while (InsertPoint < FViewerCount) and
- (FViewers[InsertPoint].FGroupLevel >= NewLevel) do begin
- if (FViewers[InsertPoint].Item = Item) and
- (FViewers[InsertPoint].FGroupLevel = NewLevel) then begin
- { If the item we were going to insert already exists, then there
- must be multiple instances of the same group item. This can
- happen when are two group items on the same toolbar each
- linking to the same submenu item, with the submenu item
- containing a group item of its own, and an item is inserted
- inside that. }
- SearchAgain := True;
- Break;
- end;
- Inc(InsertPoint);
- end;
- until not SearchAgain;
- end;
- if InsertPoint = FViewerCount then begin
- { Don't add items after the chevron or MDI buttons item }
- Dec(InsertPoint, FInternalViewersAtEnd);
- if InsertPoint < 0 then
- InsertPoint := 0; { just in case? }
- end;
- { If the new item wasn't placed at the end, adjust InsertPoint accordingly }
- if Index < Item.Parent.Count-1 then begin
- Last := InsertPoint;
- InsertPoint := Start;
- NextItem := Item.Parent.FItems[Index+1].Item;
- while (InsertPoint < Last) and
- ((FViewers[InsertPoint].Item <> NextItem) or
- (FViewers[InsertPoint].FGroupLevel <> NewLevel)) do
- Inc(InsertPoint);
- end;
- InsertItemViewers(InsertPoint, Item, NewLevel, True,
- not(csLoading in Item.ComponentState) and FNewViewersGetHighestPriority);
- end;
- procedure ItemDeleting;
- procedure DeleteItem(DeleteIndex: Integer);
- var
- Viewer: TTBItemViewer;
- begin
- Viewer := FViewers[DeleteIndex];
- DeletingViewer(Viewer);
- RemoveFromList(FPriorityList, Viewer);
- FreeAndNil(Viewer);
- DeleteFromViewerArray(FViewers, FViewerCount, DeleteIndex);
- end;
- var
- I: Integer;
- DeleteLevel: Integer;
- begin
- InvalidatePositions;
- I := 0;
- DeleteLevel := 0;
- while I < FViewerCount do begin
- if DeleteLevel > 0 then begin
- if FViewers[I].FGroupLevel >= DeleteLevel then begin
- DeleteItem(I);
- Continue;
- end
- else
- DeleteLevel := 0;
- end;
- if FViewers[I].Item = Item then begin
- { Delete the item, and any group item children afterward }
- DeleteLevel := FViewers[I].FGroupLevel + 1;
- DeleteItem(I);
- Continue;
- end;
- Inc(I);
- end;
- end;
- var
- I: Integer;
- begin
- case Action of
- tbicInserted: ItemInserted;
- tbicDeleting: ItemDeleting;
- tbicSubitemsChanged: begin
- { If Relayed=True, LinkSubitems must have changed on a child group
- item. Currently there isn't any optimized way of handling this
- situation; just recreate all viewers. }
- if Relayed then
- RecreateAllViewers;
- end;
- tbicSubitemsBeginUpdate: BeginUpdate;
- tbicSubitemsEndUpdate: EndUpdate;
- tbicInvalidate: begin
- for I := 0 to FViewerCount-1 do
- if FViewers[I].Item = Item then
- Invalidate(FViewers[I]);
- end;
- tbicInvalidateAndResize: InvalidatePositions;
- tbicRecreateItemViewers: begin
- InvalidatePositions;
- for I := 0 to FViewerCount-1 do
- if FViewers[I].Item = Item then
- RecreateItemViewer(I);
- end;
- tbicSubMenuImagesChanged: ImagesChanged;
- else
- { Prevent TryValidatePositions from being called below on Actions other than
- those listed above. Currently there are no other Actions, but for forward
- compatibility, we should ignore unknown Actions completely. }
- Exit;
- end;
- TryValidatePositions;
- end;
- procedure TTBView.LinkNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
- Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
- { This notification procedure watches for tbicSubitemsChanged notifications
- from FParentItem }
- begin
- case Action of
- tbicSubitemsChanged: begin
- { LinkSubitems may have changed on FParentItem, e.g. on the root item
- of a toolbar, so see if FCurParentItem needs updating }
- UpdateCurParentItem;
- end;
- tbicSubMenuImagesChanged: begin
- { In case the images were inherited from the actual parent instead of
- the linked parent... }
- if FParentItem <> FCurParentItem then
- ImagesChanged;
- end;
- end;
- end;
- procedure TTBView.ImagesChanged;
- begin
- InvalidatePositions;
- TryValidatePositions;
- if Assigned(FOpenViewerView) then
- FOpenViewerView.ImagesChanged;
- end;
- procedure TTBView.GivePriority(AViewer: TTBItemViewer);
- { Move item to top of priority list. Rearranges items if necessary. }
- var
- I: Integer;
- begin
- if Assigned(FChevronParentView) then begin
- I := AViewer.Index + FChevronParentView.FInternalViewersAtFront;
- if I < FChevronParentView.FViewerCount then { range check just in case }
- FChevronParentView.GivePriority(FChevronParentView.FViewers[I]);
- Exit;
- end;
- if Assigned(FPriorityList) then begin
- I := FPriorityList.IndexOf(AViewer);
- if I <> -1 then begin
- FPriorityList.Move(I, 0);
- if not FValidated or AViewer.OffEdge then
- UpdatePositions;
- end;
- end;
- { Call GivePriority on parent view, so that if an item on a submenu is
- clicked, the parent item of the submenu gets priority. }
- if Assigned(FParentView) and Assigned(FParentView.FOpenViewer) then
- FParentView.GivePriority(FParentView.FOpenViewer);
- end;
- function TTBView.HighestPriorityViewer: TTBItemViewer;
- { Returns index of first visible, non-separator item at top of priority list,
- or -1 if there are no items found }
- var
- I: Integer;
- J: TTBItemViewer;
- begin
- ValidatePositions;
- Result := nil;
- if Assigned(FPriorityList) then begin
- for I := 0 to FPriorityList.Count-1 do begin
- J := FPriorityList[I];
- if J.Show and not(tbisSeparator in J.Item.ItemStyle) then begin
- Result := J;
- Break;
- end;
- end;
- end
- else begin
- for I := 0 to FViewerCount-1 do begin
- J := FViewers[I];
- if J.Show and not(tbisSeparator in J.Item.ItemStyle) then begin
- Result := J;
- Break;
- end;
- end;
- end;
- end;
- procedure TTBView.StartTimer(const ATimer: TTBViewTimerID;
- const Interval: Integer);
- { Starts a timer. Stops any previously set timer of the same ID first.
- Note: WM_TIMER messages generated by timers set by the method are handled
- in PopupMessageLoop. }
- begin
- StopTimer(ATimer);
- if (FWindow is TTBPopupWindow) and FWindow.HandleAllocated then begin
- SetTimer(FWindow.Handle, ViewTimerBaseID + Ord(ATimer), Interval, nil);
- Include(FActiveTimers, ATimer);
- end;
- end;
- procedure TTBView.StopAllTimers;
- var
- I: TTBViewTimerID;
- begin
- for I := Low(I) to High(I) do
- StopTimer(I);
- end;
- procedure TTBView.StopTimer(const ATimer: TTBViewTimerID);
- begin
- if ATimer in FActiveTimers then begin
- if (FWindow is TTBPopupWindow) and FWindow.HandleAllocated then
- KillTimer(FWindow.Handle, ViewTimerBaseID + Ord(ATimer));
- Exclude(FActiveTimers, ATimer);
- end;
- end;
- function TTBView.OpenChildPopup(const SelectFirstItem: Boolean): Boolean;
- var
- Item: TTBCustomItem;
- begin
- StopTimer(tiClose);
- StopTimer(tiOpen);
- if FSelected <> FOpenViewer then begin
- CloseChildPopups;
- if Assigned(FSelected) then begin
- Item := FSelected.Item;
- if Item.Enabled and (tbisSubmenu in Item.ItemStyle) then
- Item.CreatePopup(Self, FSelected, not FIsToolbar, SelectFirstItem,
- False, Point(0, 0), tbpaLeft);
- end;
- end;
- Result := Assigned(FOpenViewer);
- end;
- procedure TTBView.CloseChildPopups;
- begin
- if Assigned(FOpenViewerView) then
- FOpenViewerView.CloseChildPopups;
- StopTimer(tiClose);
- FOpenViewerWindow.Free;
- FOpenViewerWindow := nil;
- FOpenViewerView := nil;
- FOpenViewer := nil;
- end;
- procedure TTBView.CancelChildPopups;
- begin
- if FIsToolbar then
- Exclude(FState, vsDropDownMenus);
- {MP}
- if Assigned(FOpenViewerWindow) then
- FOpenViewerWindow.Cancel;
- CloseChildPopups;
- end;
- function TTBView.ViewerFromPoint(const P: TPoint): TTBItemViewer;
- var
- I: Integer;
- begin
- ValidatePositions;
- for I := 0 to FViewerCount-1 do begin
- if FViewers[I].Show and
- PtInRect(FViewers[I].BoundsRect, P) then begin
- Result := FViewers[I];
- Exit;
- end;
- end;
- Result := nil;
- end;
- procedure TTBView.NotifyFocusEvent;
- { Notifies Active Accessibility of a change in "focus". Has no effect if the
- view or the root view lacks the vsModal state, or if the modal loop is
- ending (EndModal* was called). }
- var
- I, ChildID, J: Integer;
- begin
- { Note: We don't notify about windows not yet shown (e.g. a popup menu that
- is still initializing) because that would probably confuse screen readers.
- Also allocating a window handle at this point *might* not be a good idea. }
- if (vsModal in FState) and (vsModal in GetRootView.FState) and
- not IsModalEnding and
- FWindow.HandleAllocated and IsWindowVisible(FWindow.Handle) then begin
- if Assigned(FSelected) and FSelected.IsAccessible then
- I := IndexOf(FSelected)
- else
- I := -1;
- if (I < 0) and Assigned(FParentView) then begin
- { If we have no selected item, report the the selected item on the parent
- view as having the "focus".
- Note: With standard menus, when you go from having a selection to no
- selection on a submenu, it sends two focus events - first with the
- client window as having the focus, then with the parent item. I
- figure that's probably a bug, so I don't try to emulate that behavior
- here. }
- FParentView.NotifyFocusEvent;
- end
- else begin
- if I >= 0 then begin
- { Convert viewer index into a one-based child index.
- (TTBViewAccObject.get_accChild does the inverse.) }
- ChildID := 1;
- for J := 0 to I-1 do
- if FViewers[J].IsAccessible then
- Inc(ChildID);
- end
- else begin
- { If there is no (accessible) selection and no parent view, report
- the client window itself as being "focused". This is what happens
- when a standard context menu has no selection. }
- ChildID := CHILDID_SELF;
- end;
- NotifyWinEvent(EVENT_OBJECT_FOCUS, FWindow.Handle, OBJID_CLIENT, ChildID);
- end;
- end;
- end;
- procedure TTBView.SetSelected(Value: TTBItemViewer);
- begin
- Select(Value, False);
- end;
- procedure TTBView.Select(Value: TTBItemViewer; ViaMouse: Boolean);
- { Sets the current selection.
- When the selection is changing it will also, if necessary, open/close child
- popups. How exactly this works depends on the setting of ViaMouse. If
- ViaMouse is True it will delay the opening/closing of popups using timers. }
- var
- OldSelected: TTBItemViewer;
- NewMouseOverSelected: Boolean;
- P: TPoint;
- begin
- OldSelected := FSelected;
- if Value <> OldSelected then begin
- { If there's a new selection and the parent item on the parent view
- isn't currently selected, select it. Also stop any timer running on
- the parent view. }
- if Assigned(Value) and Assigned(FParentView) and
- Assigned(FParentView.FOpenViewer) and
- (FParentView.FSelected <> FParentView.FOpenViewer) then begin
- FParentView.Selected := FParentView.FOpenViewer;
- FParentView.StopTimer(tiClose);
- FParentView.StopTimer(tiOpen);
- end;
- { Handle automatic closing of child popups }
- if vsModal in FState then begin
- { If the view is a toolbar, or if the new selection didn't come from
- the mouse, close child popups immediately }
- if FIsToolbar or not ViaMouse then begin
- { Always stop any close timer because CloseChildPopups may not be
- called below }
- StopTimer(tiClose);
- if Value <> FOpenViewer then
- { ^ But don't close if selection is returning to the open item.
- Needed for the "FParentView.Selected := FParentView.FOpenViewer"
- line above to work. }
- CloseChildPopups;
- end
- else begin
- { Otherwise, delay-close any child popup }
- if Assigned(FOpenViewerView) and not(tiClose in FActiveTimers) then
- StartTimer(tiClose, GetMenuShowDelay);
- end;
- end;
- CancelCapture;
- if Assigned(OldSelected) then
- OldSelected.Leaving;
- FSelected := Value;
- FSelectedViaMouse := ViaMouse;
- end;
- NewMouseOverSelected := False;
- if Assigned(Value) and Assigned(FWindow) then begin
- P := SmallPointToPoint(TSmallPoint(GetMessagePos()));
- if FindDragTarget(P, True) = FWindow then begin
- P := FWindow.ScreenToClient(P);
- NewMouseOverSelected := (ViewerFromPoint(P) = Value);
- if NewMouseOverSelected and FCapture and
- not Value.IsPtInButtonPart(P.X - Value.BoundsRect.Left,
- P.Y - Value.BoundsRect.Top) then
- NewMouseOverSelected := False;
- end;
- end;
- if Value <> OldSelected then begin
- FMouseOverSelected := NewMouseOverSelected;
- if Assigned(OldSelected) and (tbisRedrawOnSelChange in OldSelected.Item.ItemStyle) then
- Invalidate(OldSelected);
- if Assigned(Value) then begin
- if tbisRedrawOnSelChange in Value.Item.ItemStyle then
- Invalidate(Value);
- Value.Entering(OldSelected);
- end;
- NotifyFocusEvent;
- { Handle automatic opening of a child popup }
- if vsModal in FState then begin
- { If the view is a toolbar, immediately open any child popup }
- if FIsToolbar then begin
- if Assigned(Value) then begin
- if ViaMouse and Assigned(FParentView) then begin
- { On chevron popups, always drop down menus when mouse passes
- over them, like Office 2000 }
- Include(FState, vsDropDownMenus);
- end;
- if (vsDropDownMenus in FState) and
- (ViaMouse or not(tbisNoAutoOpen in Value.Item.ItemStyle)) then
- OpenChildPopup(not ViaMouse);
- end;
- end
- else begin
- { Otherwise, delay-open any child popup if the selection came from
- the mouse }
- StopTimer(tiOpen);
- if ViaMouse and Assigned(Value) and (tbisSubmenu in Value.Item.ItemStyle) then
- StartTimer(tiOpen, GetMenuShowDelay);
- end;
- end;
- end
- else if FMouseOverSelected <> NewMouseOverSelected then begin
- FMouseOverSelected := NewMouseOverSelected;
- if Assigned(Value) and FCapture and (tbisRedrawOnMouseOverChange in Value.Item.ItemStyle) then
- Invalidate(Value);
- end;
- end;
- procedure TTBView.UpdateSelection(const P: PPoint; const AllowNewSelection: Boolean);
- { Called in response to a mouse movement, this method updates the current
- selection, updates the vsMouseInWindow view state, and enables/disables
- scroll timers. }
- function IsPtInScrollArrow(ADownArrow: Boolean): Boolean;
- var
- P2: TPoint;
- R: TRect;
- begin
- Result := False;
- if (vsModal in FState) and (vsMouseInWindow in FState) and
- Assigned(P) then begin
- P2 := FWindow.ScreenToClient(P^);
- R := FWindow.ClientRect;
- if PtInRect(R, P2) then begin
- if ADownArrow then
- Result := FShowDownArrow and (P2.Y >= R.Bottom - tbMenuScrollArrowHeight)
- else
- Result := FShowUpArrow and (P2.Y < tbMenuScrollArrowHeight);
- end;
- end;
- end;
- var
- NewSelected, ViewerAtPoint: TTBItemViewer;
- P2: TPoint;
- MouseWasInWindow: Boolean;
- begin
- ValidatePositions;
- { If modal, default to keeping the existing selection }
- if vsModal in FState then
- NewSelected := FSelected
- else
- NewSelected := nil;
- { Is the mouse inside the window? }
- MouseWasInWindow := vsMouseInWindow in FState;
- if Assigned(P) and Assigned(FWindow) and (FindDragTarget(P^, True) = FWindow) then begin
- { If we're a popup window and the mouse is inside, default to no selection }
- if FIsPopup then
- NewSelected := nil;
- Include(FState, vsMouseInWindow);
- if AllowNewSelection or Assigned(FSelected) then begin
- P2 := FWindow.ScreenToClient(P^);
- ViewerAtPoint := ViewerFromPoint(P2);
- if Assigned(ViewerAtPoint) then
- NewSelected := ViewerAtPoint;
- end;
- end
- else
- Exclude(FState, vsMouseInWindow);
- { If FCapture is True, don't allow the selection to change }
- if FCapture and (NewSelected <> FSelected) then
- NewSelected := FSelected;
- { If we're a popup window and there is a selection... }
- if FIsPopup and Assigned(NewSelected) then begin
- { If the mouse just moved out of the window and no submenu was open,
- remove the highlight }
- if not FCapture and MouseWasInWindow and not(vsMouseInWindow in FState) and
- (not Assigned(FOpenViewerView) or not(tbisSubmenu in NewSelected.Item.ItemStyle)) then
- NewSelected := nil;
- end;
- { Now we set the new Selected value }
- Select(NewSelected, True);
- { Update scroll arrow timers }
- if IsPtInScrollArrow(False) then begin
- StopTimer(tiScrollDown);
- if not(tiScrollUp in FActiveTimers) then
- StartTimer(tiScrollUp, 100);
- end
- else if IsPtInScrollArrow(True) then begin
- StopTimer(tiScrollUp);
- if not(tiScrollDown in FActiveTimers) then
- StartTimer(tiScrollDown, 100);
- end
- else begin
- StopTimer(tiScrollUp);
- StopTimer(tiScrollDown);
- end;
- end;
- procedure TTBView.RecreateAllViewers;
- var
- Item: TTBCustomItem;
- I: Integer;
- begin
- { Since the FViewers list is being rebuilt, FOpenViewer and FSelected
- will no longer be valid, so ensure they're set to nil. }
- CloseChildPopups;
- Selected := nil;
- InvalidatePositions;
- FreeAndNil(FPriorityList);
- FreeViewers;
- FInternalViewersAtFront := 0;
- FInternalViewersAtEnd := 0;
- { MDI system menu item }
- Item := GetMDISystemMenuItem;
- if Assigned(Item) then
- Inc(FInternalViewersAtFront, InsertItemViewers(FViewerCount, Item, 0,
- False, False));
- { Items }
- if Assigned(FCurParentItem) then begin
- for I := 0 to FCurParentItem.Count-1 do
- InsertItemViewers(FViewerCount, FCurParentItem.FItems[I].Item, 0,
- True, False);
- end;
- { MDI buttons item }
- Item := GetMDIButtonsItem;
- if Assigned(Item) then begin
- for I := 0 to Item.Count-1 do
- Inc(FInternalViewersAtEnd, InsertItemViewers(FViewerCount,
- Item.FItems[I].Item, 0, False, False));
- end;
- { Chevron item }
- Item := GetChevronItem;
- if Assigned(Item) then
- Inc(FInternalViewersAtEnd, InsertItemViewers(FViewerCount, Item, 0,
- False, False));
- end;
- function TTBView.CalculatePositions(const CanMoveControls: Boolean;
- const AOrientation: TTBViewOrientation;
- AWrapOffset, AChevronOffset, AChevronSize: Integer;
- var ABaseSize, TotalSize: TPoint;
- var AWrappedLines: Integer): Boolean;
- { Returns True if the positions have changed }
- type
- PTempPosition = ^TTempPosition;
- TTempPosition = record
- BoundsRect: TRect;
- Show, OffEdge, LineSep, Clipped, SameWidth: Boolean;
- end;
- PTempPositionArray = ^TTempPositionArray;
- TTempPositionArray = array[0..$7FFFFFFF div SizeOf(TTempPosition)-1] of TTempPosition;
- var
- DC: HDC;
- LeftX, TopY, CurX, CurY, I: Integer;
- NewPositions: PTempPositionArray;
- GroupSplit, DidWrap: Boolean;
- LineStart, HighestHeightOnLine, HighestWidthOnLine: Integer;
- function GetSizeOfGroup(const StartingIndex: Integer): Integer;
- var
- I: Integer;
- begin
- Result := 0;
- for I := StartingIndex to FViewerCount-1 do begin
- if not NewPositions[I].Show then
- Continue;
- if tbisSeparator in FViewers[I].Item.ItemStyle then
- Break;
- with NewPositions[I] do begin
- if AOrientation <> tbvoVertical then
- Inc(Result, BoundsRect.Right)
- else
- Inc(Result, BoundsRect.Bottom);
- end;
- end;
- end;
- procedure Mirror;
- { Reverses the horizontal ordering (i.e. first item becomes last) }
- var
- I, NewRight: Integer;
- begin
- for I := 0 to FViewerCount-1 do
- with NewPositions[I] do
- if Show then begin
- NewRight := TotalSize.X - BoundsRect.Left;
- BoundsRect.Left := TotalSize.X - BoundsRect.Right;
- BoundsRect.Right := NewRight;
- end;
- end;
- procedure HandleMaxHeight;
- { Decreases, if necessary, the height of the view to FMaxHeight, and adjusts
- the visibility of the scroll arrows }
- var
- MaxOffset, I, MaxTop, MaxBottom: Integer;
- begin
- FShowUpArrow := False;
- FShowDownArrow := False;
- if (FMaxHeight > 0) and (TotalSize.Y > FMaxHeight) then begin
- MaxOffset := TotalSize.Y - FMaxHeight;
- if FScrollOffset > MaxOffset then
- FScrollOffset := MaxOffset;
- if FScrollOffset < 0 then
- FScrollOffset := 0;
- FShowUpArrow := (FScrollOffset > 0);
- FShowDownArrow := (FScrollOffset < MaxOffset);
- MaxTop := 0;
- if FShowUpArrow then
- MaxTop := tbMenuScrollArrowHeight;
- MaxBottom := FMaxHeight;
- if FShowDownArrow then
- Dec(MaxBottom, tbMenuScrollArrowHeight);
- for I := 0 to FViewerCount-1 do begin
- if not IsRectEmpty(NewPositions[I].BoundsRect) then begin
- OffsetRect(NewPositions[I].BoundsRect, 0, -FScrollOffset);
- if NewPositions[I].Show and
- ((NewPositions[I].BoundsRect.Top < MaxTop) or
- (NewPositions[I].BoundsRect.Bottom > MaxBottom)) then begin
- NewPositions[I].Show := False;
- NewPositions[I].Clipped := True;
- end;
- end;
- end;
- TotalSize.Y := FMaxHeight;
- end
- else
- FScrollOffset := 0;
- end;
- procedure FinalizeLine(const LineEnd: Integer; const LastLine: Boolean);
- var
- I, RightAlignStart: Integer;
- Item: TTBCustomItem;
- IsButton: Boolean;
- Pos: PTempPosition;
- Z: Integer;
- begin
- if LineStart <> -1 then begin
- if DidWrap and (FChevronParentView = nil) then begin
- { When wrapping on a docked toolbar, extend TotalSize.X/Y to
- AWrapOffset so that the toolbar always fills the whole row }
- if (AOrientation = tbvoHorizontal) and (TotalSize.X < AWrapOffset) then
- TotalSize.X := AWrapOffset
- else if (AOrientation = tbvoVertical) and (TotalSize.Y < AWrapOffset) then
- TotalSize.Y := AWrapOffset;
- end;
- RightAlignStart := -1;
- for I := LineStart to LineEnd do begin
- Pos := @NewPositions[I];
- if not Pos.Show then
- Continue;
- Item := FViewers[I].Item;
- if (RightAlignStart < 0) and (tbisRightAlign in Item.ItemStyle) then
- RightAlignStart := I;
- IsButton := FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
- if FIsToolbar then begin
- if LastLine and not DidWrap and (AOrientation <> tbvoFloating) then begin
- { In case the toolbar is docked next to a taller/wider toolbar... }
- HighestWidthOnLine := TotalSize.X;
- HighestHeightOnLine := TotalSize.Y;
- end;
- { Make separators on toolbars as tall/wide as the tallest/widest item }
- if [tbisSeparator, tbisStretch] * Item.ItemStyle <> [] then begin
- if AOrientation <> tbvoVertical then
- Pos.BoundsRect.Bottom := Pos.BoundsRect.Top + HighestHeightOnLine
- else
- Pos.BoundsRect.Right := Pos.BoundsRect.Left + HighestWidthOnLine;
- end
- else begin
- { Center the item }
- if AOrientation <> tbvoVertical then begin
- Z := (HighestHeightOnLine - (Pos.BoundsRect.Bottom - Pos.BoundsRect.Top)) div 2;
- Inc(Pos.BoundsRect.Top, Z);
- Inc(Pos.BoundsRect.Bottom, Z);
- end
- else begin
- Z := (HighestWidthOnLine - (Pos.BoundsRect.Right - Pos.BoundsRect.Left)) div 2;
- Inc(Pos.BoundsRect.Left, Z);
- Inc(Pos.BoundsRect.Right, Z);
- end;
- end;
- end
- else begin
- { Make items in a menu as wide as the widest item }
- if not IsButton then begin
- with Pos.BoundsRect do Right := Left + HighestWidthOnLine;
- end;
- end;
- end;
- if RightAlignStart >= 0 then begin
- Z := 0;
- for I := LineEnd downto RightAlignStart do begin
- Pos := @NewPositions[I];
- if not Pos.Show then
- Continue;
- if AOrientation <> tbvoVertical then
- Z := Min(AWrapOffset, TotalSize.X) - Pos.BoundsRect.Right
- else
- Z := Min(AWrapOffset, TotalSize.Y) - Pos.BoundsRect.Bottom;
- Break;
- end;
- if Z > 0 then begin
- for I := RightAlignStart to LineEnd do begin
- Pos := @NewPositions[I];
- if not Pos.Show then
- Continue;
- if AOrientation <> tbvoVertical then begin
- Inc(Pos.BoundsRect.Left, Z);
- Inc(Pos.BoundsRect.Right, Z);
- end
- else begin
- Inc(Pos.BoundsRect.Top, Z);
- Inc(Pos.BoundsRect.Bottom, Z);
- end;
- end;
- end;
- end;
- end;
- LineStart := -1;
- HighestHeightOnLine := 0;
- HighestWidthOnLine := 0;
- end;
- procedure PositionItem(const CurIndex: Integer; var Pos: TTempPosition);
- var
- O, X, Y: Integer;
- IsLineSep, Vert: Boolean;
- begin
- if LineStart = -1 then begin
- LineStart := CurIndex;
- HighestHeightOnLine := 0;
- HighestWidthOnLine := 0;
- end;
- IsLineSep := False;
- Vert := (AOrientation = tbvoVertical);
- if not Vert then
- O := CurX
- else
- O := CurY;
- if (AWrapOffset > 0) and (O > 0) then begin
- if not Vert then
- Inc(O, Pos.BoundsRect.Right)
- else
- Inc(O, Pos.BoundsRect.Bottom);
- if (tbisSeparator in FViewers[CurIndex].Item.ItemStyle) and
- ((GroupSplit and not(tbisNoLineBreak in FViewers[CurIndex].Item.ItemStyle))
- or (O + GetSizeOfGroup(CurIndex+1) > AWrapOffset)) then begin
- DidWrap := True;
- Inc(AWrappedLines);
- if not Vert then begin
- CurX := 0;
- Inc(CurY, HighestHeightOnLine);
- end
- else begin
- CurY := 0;
- Inc(CurX, HighestWidthOnLine);
- end;
- FinalizeLine(CurIndex-1, False);
- LineStart := CurIndex+1;
- if not Vert then begin
- Pos.BoundsRect.Right := 0;
- Pos.BoundsRect.Bottom := tbLineSpacing;
- end
- else begin
- Pos.BoundsRect.Right := tbLineSpacing;
- Pos.BoundsRect.Bottom := 0;
- end;
- Pos.LineSep := True;
- IsLineSep := True;
- end
- else if O > AWrapOffset then begin
- { proceed to next row }
- DidWrap := True;
- Inc(AWrappedLines);
- if not Vert then begin
- CurX := LeftX;
- Inc(CurY, HighestHeightOnLine);
- end
- else begin
- CurY := TopY;
- Inc(CurX, HighestWidthOnLine);
- end;
- GroupSplit := True;
- FinalizeLine(CurIndex-1, False);
- LineStart := CurIndex;
- end;
- end;
- if Pos.BoundsRect.Bottom > HighestHeightOnLine then
- HighestHeightOnLine := Pos.BoundsRect.Bottom;
- if Pos.BoundsRect.Right > HighestWidthOnLine then
- HighestWidthOnLine := Pos.BoundsRect.Right;
- X := CurX;
- Y := CurY;
- if X < 0 then X := 0;
- if Y < 0 then Y := 0;
- OffsetRect(Pos.BoundsRect, X, Y);
- if IsLineSep then begin
- if not Vert then begin
- CurX := LeftX;
- Inc(CurY, tbLineSpacing);
- end
- else begin
- CurY := TopY;
- Inc(CurX, tbLineSpacing);
- end;
- GroupSplit := False;
- end;
- end;
- var
- SaveOrientation: TTBViewOrientation;
- ChevronItem: TTBCustomItem;
- CalcCanvas: TCanvas;
- LastWasSep, LastWasButton, IsButton, IsControl: Boolean;
- Item: TTBCustomItem;
- Ctl: TControl;
- ChangedBold: Boolean;
- HighestSameWidthViewerWidth, Total, J, TotalVisibleItems: Integer;
- IsFirst: Boolean;
- Viewer: TTBItemViewer;
- UseChevron, NonControlsOffEdge, TempViewerCreated: Boolean;
- Margins: TRect;
- label 1;
- begin
- SaveOrientation := FOrientation;
- AWrappedLines := 1;
- ChevronItem := GetChevronItem;
- NewPositions := nil;
- DC := 0;
- CalcCanvas := nil;
- try
- FOrientation := AOrientation;
- CalcCanvas := TCanvas.Create;
- DC := GetDC(0);
- CalcCanvas.Handle := DC;
- CalcCanvas.Font.Assign(GetFont);
- NewPositions := AllocMem(FViewerCount * SizeOf(TTempPosition));
- { Figure out which items should be shown }
- LastWasSep := True; { set to True initially so it won't show leading seps }
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- IsControl := Item is TTBControlItem;
- with NewPositions[I] do begin
- { Show is initially False since AllocMem initializes to zero }
- if Item = ChevronItem then
- Continue;
- if Assigned(FChevronParentView) then begin
- if IsControl then
- Continue;
- FChevronParentView.ValidatePositions;
- J := I + FChevronParentView.FInternalViewersAtFront;
- if J < FChevronParentView.FViewerCount then
- { range check just in case }
- Viewer := FChevronParentView.FViewers[J]
- else
- Viewer := nil;
- if (Viewer = nil) or (not Viewer.OffEdge and not(tbisSeparator in Item.ItemStyle)) then
- Continue;
- end;
- if not IsControl then begin
- if not(tbisEmbeddedGroup in Item.ItemStyle) or FCustomizing then begin
- Show := Item.Visible;
- { Don't display two consecutive separators }
- if Show then begin
- if (tbisSeparator in Item.ItemStyle) and LastWasSep then
- Show := False;
- LastWasSep := tbisSeparator in Item.ItemStyle;
- end;
- end;
- end
- else begin
- { Controls can only be rendered on a single Parent, so only
- include the control if its parent is currently equal to
- FWindow }
- Ctl := TTBControlItem(Item).FControl;
- if Assigned(Ctl) and Assigned(FWindow) and (Ctl.Parent = FWindow) and
- (Ctl.Visible or (csDesigning in Ctl.ComponentState)) then begin
- Show := True;
- LastWasSep := False;
- end;
- end;
- end;
- end;
- { Hide any trailing separators, so that they aren't included in the
- base size }
- for I := FViewerCount-1 downto 0 do begin
- with NewPositions[I] do
- if Show then begin
- if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
- Break;
- Show := False;
- end;
- end;
- { Calculate sizes of all the items }
- HighestSameWidthViewerWidth := 0;
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- IsControl := Item is TTBControlItem;
- with NewPositions[I] do begin
- { BoundsRect is currently empty since AllocMem initializes to zero }
- if not Show then
- Continue;
- if not IsControl then begin
- ChangedBold := False;
- if tboDefault in Item.EffectiveOptions then
- with CalcCanvas.Font do
- if not(fsBold in Style) then begin
- ChangedBold := True;
- Style := Style + [fsBold];
- end;
- Viewer := FViewers[I];
- TempViewerCreated := False;
- if Item.NeedToRecreateViewer(Viewer) then begin
- if CanMoveControls then begin
- RecreateItemViewer(I);
- Viewer := FViewers[I];
- end
- else begin
- Viewer := Item.GetItemViewerClass(Self).Create(Self, Item, 0);
- TempViewerCreated := True;
- end;
- end;
- try
- Viewer.CalcSize(CalcCanvas, BoundsRect.Right, BoundsRect.Bottom);
- if Viewer.UsesSameWidth then begin
- SameWidth := True;
- if (BoundsRect.Right > HighestSameWidthViewerWidth) then
- HighestSameWidthViewerWidth := BoundsRect.Right;
- end;
- finally
- if TempViewerCreated then
- Viewer.Free;
- end;
- if ChangedBold then
- with CalcCanvas.Font do
- Style := Style - [fsBold];
- end
- else begin
- Ctl := TTBControlItem(Item).FControl;
- BoundsRect.Right := Ctl.Width;
- BoundsRect.Bottom := Ctl.Height;
- end;
- end;
- end;
- { Increase widths of SameWidth items if necessary. Also calculate
- ABaseSize.X (or Y). }
- ABaseSize.X := 0;
- ABaseSize.Y := 0;
- for I := 0 to FViewerCount-1 do begin
- with NewPositions[I] do begin
- if SameWidth and (BoundsRect.Right < HighestSameWidthViewerWidth) then
- BoundsRect.Right := HighestSameWidthViewerWidth;
- if AOrientation <> tbvoVertical then
- Inc(ABaseSize.X, BoundsRect.Right)
- else
- Inc(ABaseSize.Y, BoundsRect.Bottom);
- end;
- end;
- { Hide partially visible items, mark them as 'OffEdge' }
- if AOrientation <> tbvoVertical then
- Total := ABaseSize.X
- else
- Total := ABaseSize.Y;
- NonControlsOffEdge := False;
- UseChevron := Assigned(ChevronItem) and (AChevronOffset > 0) and
- (Total > AChevronOffset);
- if UseChevron then begin
- Dec(AChevronOffset, AChevronSize);
- while Total > AChevronOffset do begin
- { Count number of items. Stop loop if <= 1 }
- TotalVisibleItems := 0;
- for I := FViewerCount-1 downto 0 do begin
- if NewPositions[I].Show and not(tbisSeparator in FViewers[I].Item.ItemStyle) then
- Inc(TotalVisibleItems);
- end;
- if TotalVisibleItems <= 1 then
- Break;
- { Hide any trailing separators }
- for I := FViewerCount-1 downto 0 do begin
- with NewPositions[I] do
- if Show then begin
- if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
- Break;
- Show := False;
- if AOrientation <> tbvoVertical then
- Dec(Total, BoundsRect.Right)
- else
- Dec(Total, BoundsRect.Bottom);
- goto 1;
- end;
- end;
- { Find an item to hide }
- if Assigned(FPriorityList) then
- I := FPriorityList.Count-1
- else
- I := FViewerCount-1;
- while I >= 0 do begin
- if Assigned(FPriorityList) then begin
- Viewer := FPriorityList[I];
- J := Viewer.Index;
- end
- else begin
- Viewer := FViewers[I];
- J := I;
- end;
- if NewPositions[J].Show and not(tbisSeparator in Viewer.Item.ItemStyle) then begin
- NewPositions[J].Show := False;
- NewPositions[J].OffEdge := True;
- if AOrientation <> tbvoVertical then
- Dec(Total, NewPositions[J].BoundsRect.Right)
- else
- Dec(Total, NewPositions[J].BoundsRect.Bottom);
- if not NonControlsOffEdge and not(Viewer.Item is TTBControlItem) then
- NonControlsOffEdge := True;
- goto 1;
- end;
- Dec(I);
- end;
- Break; { prevent endless loop }
- 1:
- { Don't show two consecutive separators }
- LastWasSep := True; { set to True initially so it won't show leading seps }
- for J := 0 to FViewerCount-1 do begin
- Item := FViewers[J].Item;
- with NewPositions[J] do begin
- if Show then begin
- if (tbisSeparator in Item.ItemStyle) and LastWasSep then begin
- Show := False;
- if AOrientation <> tbvoVertical then
- Dec(Total, BoundsRect.Right)
- else
- Dec(Total, BoundsRect.Bottom);
- end;
- LastWasSep := tbisSeparator in Item.ItemStyle;
- end;
- end;
- end;
- end;
- end;
- { Hide any trailing separators after items were hidden }
- for I := FViewerCount-1 downto 0 do begin
- with NewPositions[I] do
- if Show then begin
- if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
- Break;
- Show := False;
- end;
- end;
- { Set the ABaseSize.Y (or X) *after* items were hidden }
- for I := 0 to FViewerCount-1 do begin
- with NewPositions[I] do
- if Show then begin
- if AOrientation <> tbvoVertical then begin
- if BoundsRect.Bottom > ABaseSize.Y then
- ABaseSize.Y := BoundsRect.Bottom;
- end
- else begin
- if BoundsRect.Right > ABaseSize.X then
- ABaseSize.X := BoundsRect.Right;
- end;
- end;
- end;
- { On menus, set all non-separator items to be as tall as the tallest item }
- {if not FIsToolbar then begin
- J := 0;
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- with NewPositions[I] do
- if Show and not(tbisSeparator in Item.ItemStyle) and
- not(tboToolbarSize in Item.FEffectiveOptions) and
- (BoundsRect.Bottom - BoundsRect.Top > J) then
- J := BoundsRect.Bottom - BoundsRect.Top;
- end;
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- with NewPositions[I] do
- if Show and not(tbisSeparator in Item.ItemStyle) and
- not(tboToolbarSize in Item.FEffectiveOptions) then
- BoundsRect.Bottom := BoundsRect.Top + J;
- end;
- end;}
- { Calculate the position of the items }
- GetMargins(AOrientation, Margins);
- LeftX := Margins.Left;
- TopY := Margins.Top;
- if AWrapOffset > 0 then begin
- Dec(AWrapOffset, Margins.Right);
- if AWrapOffset < 1 then AWrapOffset := 1;
- end;
- CurX := LeftX;
- CurY := TopY;
- GroupSplit := False;
- DidWrap := False;
- LastWasButton := FIsToolbar;
- LineStart := -1;
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- with NewPositions[I] do begin
- if not Show then
- Continue;
- IsButton := FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
- if LastWasButton and not IsButton then begin
- { On a menu, if last item was a button and the current item isn't,
- proceed to next row }
- CurX := LeftX;
- CurY := TotalSize.Y;
- end;
- LastWasButton := IsButton;
- PositionItem(I, NewPositions[I]);
- if IsButton and (AOrientation <> tbvoVertical) then
- Inc(CurX, BoundsRect.Right - BoundsRect.Left)
- else
- Inc(CurY, BoundsRect.Bottom - BoundsRect.Top);
- if BoundsRect.Right > TotalSize.X then
- TotalSize.X := BoundsRect.Right;
- if BoundsRect.Bottom > TotalSize.Y then
- TotalSize.Y := BoundsRect.Bottom;
- end;
- end;
- if FViewerCount <> 0 then
- FinalizeLine(FViewerCount-1, True);
- Inc(TotalSize.X, Margins.Right);
- Inc(TotalSize.Y, Margins.Bottom);
- if AOrientation = tbvoVertical then
- Mirror;
- HandleMaxHeight;
- if CanMoveControls then begin
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- if Item is TTBControlItem then begin
- if NewPositions[I].Show then begin
- Ctl := TTBControlItem(Item).FControl;
- if not EqualRect(NewPositions[I].BoundsRect, Ctl.BoundsRect) then
- Ctl.BoundsRect := NewPositions[I].BoundsRect;
- end
- else if NewPositions[I].OffEdge or NewPositions[I].Clipped then begin
- { Simulate hiding of OddEdge controls by literally moving them
- off the edge. Do the same for Clipped controls. }
- Ctl := TTBControlItem(Item).FControl;
- Ctl.SetBounds(FWindow.ClientWidth, FWindow.ClientHeight,
- Ctl.Width, Ctl.Height);
- end;
- end;
- end;
- end;
- { Set size of line separators }
- if FIsToolbar then
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- with NewPositions[I] do
- if Show and (tbisSeparator in Item.ItemStyle) and
- LineSep then begin
- if AOrientation <> tbvoVertical then
- BoundsRect.Right := TotalSize.X
- else
- BoundsRect.Bottom := TotalSize.Y;
- end;
- end;
- { Position the chevron item }
- if UseChevron then begin
- if CanMoveControls then
- ChevronItem.Enabled := NonControlsOffEdge;
- NewPositions[FViewerCount-1].Show := True;
- I := AChevronOffset;
- if AOrientation <> tbvoVertical then begin
- if I < TotalSize.X then
- I := TotalSize.X;
- NewPositions[FViewerCount-1].BoundsRect := Bounds(I, 0,
- AChevronSize, TotalSize.Y);
- end
- else begin
- if I < TotalSize.Y then
- I := TotalSize.Y;
- NewPositions[FViewerCount-1].BoundsRect := Bounds(0, I,
- TotalSize.X, AChevronSize);
- end;
- end;
- { Commit changes }
- Result := False;
- if CanMoveControls then begin
- for I := 0 to FViewerCount-1 do begin
- if not Result and
- (not EqualRect(FViewers[I].BoundsRect, NewPositions[I].BoundsRect) or
- (FViewers[I].Show <> NewPositions[I].Show) or
- (tbisLineSep in FViewers[I].State <> NewPositions[I].LineSep)) then
- Result := True;
- FViewers[I].FBoundsRect := NewPositions[I].BoundsRect;
- FViewers[I].FShow := NewPositions[I].Show;
- FViewers[I].FOffEdge := NewPositions[I].OffEdge;
- FViewers[I].FClipped := NewPositions[I].Clipped;
- if NewPositions[I].LineSep then
- Include(FViewers[I].State, tbisLineSep)
- else
- Exclude(FViewers[I].State, tbisLineSep);
- end;
- end;
- finally
- FOrientation := SaveOrientation;
- if Assigned(CalcCanvas) then
- CalcCanvas.Handle := 0;
- if DC <> 0 then ReleaseDC(0, DC);
- CalcCanvas.Free;
- FreeMem(NewPositions);
- end;
- if (ABaseSize.X = 0) or (ABaseSize.Y = 0) then begin
- { If there are no visible items... }
- {}{scale this?}
- ABaseSize.X := 23;
- ABaseSize.Y := 22;
- if TotalSize.X < 23 then TotalSize.X := 23;
- if TotalSize.Y < 22 then TotalSize.Y := 22;
- end;
- end;
- procedure TTBView.DoUpdatePositions(var ASize: TPoint);
- { This is called by UpdatePositions }
- var
- Bmp: TBitmap;
- CtlCanvas: TControlCanvas;
- WrappedLines: Integer;
- begin
- { Don't call InvalidatePositions before CalculatePositions so that
- endless recursion doesn't happen if an item's CalcSize uses a method that
- calls ValidatePositions }
- if not CalculatePositions(True, FOrientation, FWrapOffset, FChevronOffset,
- FChevronSize, FBaseSize, ASize, WrappedLines) then begin
- { If the new positions are identical to the previous ones, continue using
- the previous ones, and don't redraw }
- FValidated := True;
- { Just because the positions are the same doesn't mean the size hasn't
- changed. (If a shrunken toolbar moves between docks, the positions of
- the non-OffEdge items may be the same on the new dock as on the old
- dock.) }
- AutoSize(ASize.X, ASize.Y);
- end
- else begin
- if not(csDesigning in ComponentState) then begin
- FValidated := True;
- { Need to call ValidateRect before AutoSize, otherwise Windows will
- erase the client area during a resize }
- if FWindow.HandleAllocated then
- ValidateRect(FWindow.Handle, nil);
- AutoSize(ASize.X, ASize.Y);
- if Assigned(FWindow) and FWindow.HandleAllocated and
- IsWindowVisible(FWindow.Handle) and
- (FWindow.ClientWidth > 0) and (FWindow.ClientHeight > 0) then begin
- CtlCanvas := nil;
- Bmp := TBitmap.Create;
- try
- CtlCanvas := TControlCanvas.Create;
- CtlCanvas.Control := FWindow;
- Bmp.Width := FWindow.ClientWidth;
- Bmp.Height := FWindow.ClientHeight;
- SendMessage(FWindow.Handle, WM_ERASEBKGND, WPARAM(Bmp.Canvas.Handle), 0);
- SendMessage(FWindow.Handle, WM_PAINT, WPARAM(Bmp.Canvas.Handle), 0);
- BitBlt(CtlCanvas.Handle, 0, 0, Bmp.Width, Bmp.Height,
- Bmp.Canvas.Handle, 0, 0, SRCCOPY);
- ValidateRect(FWindow.Handle, nil);
- finally
- CtlCanvas.Free;
- Bmp.Free;
- end;
- end;
- end
- else begin
- { Delphi's handling of canvases is different at design time -- child
- controls aren't clipped from a parent control's canvas, so the above
- offscreen rendering code doesn't work right at design-time }
- InvalidatePositions;
- FValidated := True;
- AutoSize(ASize.X, ASize.Y);
- end;
- end;
- end;
- function TTBView.UpdatePositions: TPoint;
- { Called whenever the size or orientation of a view changes. When items are
- added or removed from the view, InvalidatePositions must be called instead,
- otherwise the view may not be redrawn properly. }
- begin
- Result.X := 0;
- Result.Y := 0;
- DoUpdatePositions(Result);
- end;
- procedure TTBView.AutoSize(AWidth, AHeight: Integer);
- begin
- end;
- function TTBView.GetChevronItem: TTBCustomItem;
- begin
- Result := nil;
- end;
- procedure TTBView.GetMargins(AOrientation: TTBViewOrientation;
- var Margins: TRect);
- begin
- if AOrientation = tbvoFloating then begin
- Margins.Left := 4;
- Margins.Top := 2;
- Margins.Right := 4;
- Margins.Bottom := 1;
- end
- else begin
- Margins.Left := 0;
- Margins.Top := 0;
- Margins.Right := 0;
- Margins.Bottom := 0;
- end;
- end;
- function TTBView.GetMDIButtonsItem: TTBCustomItem;
- begin
- Result := nil;
- end;
- function TTBView.GetMDISystemMenuItem: TTBCustomItem;
- begin
- Result := nil;
- end;
- function TTBView.GetFont: TFont;
- begin
- Result := GetToolbarFont(GetMonitorPixelsPerInch(GetMonitor));
- if not Assigned(Result) then
- begin
- { ToolbarFont is destroyed during unit finalization, but in rare cases
- this method may end up being called from ValidatePositions *after*
- unit finalization if Application.Run is never called; see the
- "EConvertError" newsgroup thread. We can't return nil because that would
- cause an exception in the calling function, so just return the window
- font. It's not the *right* font, but it shouldn't matter since the app
- is exiting anyway. }
- Result := TControlAccess(FWindow).Font;
- end;
- end;
- procedure TTBView.DrawItem(Viewer: TTBItemViewer; DrawTo: TCanvas;
- Offscreen: Boolean);
- const
- COLOR_MENUHILIGHT = 29;
- clMenuHighlight = TColor(COLOR_MENUHILIGHT or $80000000);
- var
- Bmp: TBitmap;
- DrawToDC, BmpDC: HDC;
- DrawCanvas: TCanvas;
- R1, R2, R3: TRect;
- IsOpen, IsSelected, IsPushed: Boolean;
- ToolbarStyle: Boolean;
- UseDisabledShadow: Boolean;
- SaveIndex, SaveIndex2: Integer;
- BkColor: TColor;
- begin
- ValidatePositions;
- if tbisInvalidated in Viewer.State then begin
- Offscreen := True;
- Exclude(Viewer.State, tbisInvalidated);
- end;
- R1 := Viewer.BoundsRect;
- if not Viewer.Show or IsRectEmpty(R1) or (Viewer.Item is TTBControlItem) then
- Exit;
- R2 := R1;
- OffsetRect(R2, -R2.Left, -R2.Top);
- IsOpen := FOpenViewer = Viewer;
- IsSelected := (FSelected = Viewer);
- IsPushed := IsSelected and (IsOpen or (FMouseOverSelected and FCapture));
- ToolbarStyle := Viewer.IsToolbarStyle;
- DrawToDC := DrawTo.Handle;
- Bmp := nil;
- { Must deselect any currently selected handles before calling SaveDC, because
- if they are left selected and DeleteObject gets called on them after the
- SaveDC call, it will fail on Win9x/Me, and thus leak GDI resources. }
- DrawTo.Refresh;
- SaveIndex := SaveDC(DrawToDC);
- try
- IntersectClipRect(DrawToDC, R1.Left, R1.Top, R1.Right, R1.Bottom);
- GetClipBox(DrawToDC, R3);
- if IsRectEmpty(R3) then
- Exit;
- if not Offscreen then begin
- MoveWindowOrg(DrawToDC, R1.Left, R1.Top);
- { Tweak the brush origin so that the checked background drawn behind
- checked items always looks the same regardless of whether the item
- is positioned on an even or odd Left or Top coordinate. }
- SetBrushOrgEx(DrawToDC, R1.Left and 1, R1.Top and 1, nil);
- DrawCanvas := DrawTo;
- end
- else begin
- Bmp := TBitmap.Create;
- Bmp.Width := R2.Right;
- Bmp.Height := R2.Bottom;
- DrawCanvas := Bmp.Canvas;
- BmpDC := DrawCanvas.Handle;
- SaveIndex2 := SaveDC(BmpDC);
- SetWindowOrgEx(BmpDC, R1.Left, R1.Top, nil);
- FWindow.Perform(WM_ERASEBKGND, WPARAM(BmpDC), 0);
- RestoreDC(BmpDC, SaveIndex2);
- end;
- { Initialize brush }
- if not ToolbarStyle and IsSelected then begin
- {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
- if AreFlatMenusEnabled then
- { Windows XP uses a different fill color for selected menu items when
- flat menus are enabled }
- DrawCanvas.Brush.Color := clMenuHighlight
- else
- {$ENDIF}
- DrawCanvas.Brush.Color := clHighlight;
- end
- else
- DrawCanvas.Brush.Style := bsClear;
- { Initialize font }
- DrawCanvas.Font.Assign(GetFont);
- if Viewer.Item.Enabled then begin
- if not ToolbarStyle and IsSelected then
- DrawCanvas.Font.Color := clHighlightText
- else begin
- if ToolbarStyle then
- DrawCanvas.Font.Color := clBtnText
- else
- DrawCanvas.Font.Color := tbMenuTextColor;
- end;
- UseDisabledShadow := False;
- end
- else begin
- DrawCanvas.Font.Color := clGrayText;
- { Use the disabled shadow if either:
- 1. The item is a toolbar-style item.
- 2. The item is not selected, and the background color equals the
- button-face color.
- 3. The gray-text color is the same as the background color.
- Note: Windows actually uses dithered text in this case. }
- BkColor := ColorToRGB(TControlAccess(FWindow).Color);
- UseDisabledShadow := ToolbarStyle or
- (not IsSelected and (BkColor = ColorToRGB(clBtnFace))) or
- (ColorToRGB(clGrayText) = BkColor);
- end;
- Viewer.Paint(DrawCanvas, R2, IsSelected, IsPushed, UseDisabledShadow);
- if Offscreen then
- BitBlt(DrawToDC, R1.Left, R1.Top, Bmp.Width, Bmp.Height, DrawCanvas.Handle,
- 0, 0, SRCCOPY);
- finally
- DrawTo.Refresh; { must do this before a RestoreDC }
- RestoreDC(DrawToDC, SaveIndex);
- Bmp.Free;
- end;
- end;
- procedure TTBView.DrawSubitems(ACanvas: TCanvas);
- var
- I: Integer;
- begin
- for I := 0 to FViewerCount-1 do begin
- if (vsDrawInOrder in FState) or (FViewers[I] <> FSelected) then
- DrawItem(FViewers[I], ACanvas, False);
- end;
- if not(vsDrawInOrder in FState) and Assigned(FSelected) then
- DrawItem(FSelected, ACanvas, False);
- Exclude(FState, vsDrawInOrder);
- end;
- procedure TTBView.Invalidate(AViewer: TTBItemViewer);
- begin
- if not FValidated or not Assigned(FWindow) or not FWindow.HandleAllocated then
- Exit;
- if AViewer.Show and not IsRectEmpty(AViewer.BoundsRect) and
- not(AViewer.Item is TTBControlItem) then begin
- Include(AViewer.State, tbisInvalidated);
- InvalidateRect(FWindow.Handle, @AViewer.BoundsRect, False);
- end;
- end;
- procedure TTBView.SetAccelsVisibility(AShowAccels: Boolean);
- var
- I: Integer;
- Viewer: TTBItemViewer;
- begin
- { Always show accels when keyboard cues are enabled }
- AShowAccels := AShowAccels or not(vsUseHiddenAccels in FStyle) or
- AreKeyboardCuesEnabled;
- if AShowAccels <> (vsShowAccels in FState) then begin
- if AShowAccels then
- Include(FState, vsShowAccels)
- else
- Exclude(FState, vsShowAccels);
- if Assigned(FWindow) and FWindow.HandleAllocated and
- IsWindowVisible(FWindow.Handle) then
- { ^ the visibility check is just an optimization }
- for I := 0 to FViewerCount-1 do begin
- Viewer := FViewers[I];
- if Viewer.CaptionShown and
- (FindAccelChar(Viewer.GetCaptionText) <> #0) then
- Invalidate(Viewer);
- end;
- end;
- end;
- function TTBView.FirstSelectable: TTBItemViewer;
- var
- FirstViewer: TTBItemViewer;
- begin
- Result := NextSelectable(nil, True);
- if Assigned(Result) then begin
- FirstViewer := Result;
- while tbisDontSelectFirst in Result.Item.ItemStyle do begin
- Result := NextSelectable(Result, True);
- if Result = FirstViewer then
- { don't loop endlessly if all items have the tbisDontSelectFirst style }
- Break;
- end;
- end;
- end;
- function TTBView.NextSelectable(CurViewer: TTBItemViewer;
- GoForward: Boolean): TTBItemViewer;
- var
- I, J: Integer;
- begin
- ValidatePositions;
- Result := nil;
- if FViewerCount = 0 then Exit;
- J := -1;
- I := IndexOf(CurViewer);
- while True do begin
- if GoForward then begin
- Inc(I);
- if I >= FViewerCount then I := 0;
- end
- else begin
- Dec(I);
- if I < 0 then I := FViewerCount-1;
- end;
- if J = -1 then
- J := I
- else
- if I = J then
- Exit;
- if (FViewers[I].Show or FViewers[I].Clipped) and FViewers[I].Item.Visible and
- (tbisSelectable in FViewers[I].Item.ItemStyle) then
- Break;
- end;
- Result := FViewers[I];
- end;
- function TTBView.NextSelectableWithAccel(CurViewer: TTBItemViewer;
- Key: Char; RequirePrimaryAccel: Boolean; var IsOnlyItemWithAccel: Boolean): TTBItemViewer;
- function IsAccelItem(const Index: Integer;
- const Primary, EnabledItems: Boolean): Boolean;
- var
- S: String;
- LastAccel: Char;
- Viewer: TTBItemViewer;
- Item: TTBCustomItem;
- begin
- Result := False;
- Viewer := FViewers[Index];
- Item := Viewer.Item;
- if (Viewer.Show or Viewer.Clipped) and (tbisSelectable in Item.ItemStyle) and
- (Item.Enabled = EnabledItems) and
- Item.Visible and Viewer.CaptionShown then begin
- S := Viewer.GetCaptionText;
- if S <> '' then begin
- LastAccel := FindAccelChar(S);
- if Primary then begin
- if LastAccel <> #0 then
- Result := AnsiCompareText(LastAccel, Key) = 0;
- end
- else
- if (LastAccel = #0) and (Key <> ' ') then
- Result := AnsiCompareText(S[1], Key) = 0;
- end;
- end;
- end;
- function FindAccel(I: Integer;
- const Primary, EnabledItems: Boolean): Integer;
- var
- J: Integer;
- begin
- Result := -1;
- J := -1;
- while True do begin
- Inc(I);
- if I >= FViewerCount then I := 0;
- if J = -1 then
- J := I
- else
- if I = J then
- Break;
- if IsAccelItem(I, Primary, EnabledItems) then begin
- Result := I;
- Break;
- end;
- end;
- end;
- var
- Start, I: Integer;
- Primary, EnabledItems: Boolean;
- begin
- ValidatePositions;
- Result := nil;
- IsOnlyItemWithAccel := False;
- if FViewerCount = 0 then Exit;
- Start := IndexOf(CurViewer);
- for Primary := True downto False do
- if not RequirePrimaryAccel or Primary then
- for EnabledItems := True downto False do begin
- I := FindAccel(Start, Primary, EnabledItems);
- if I <> -1 then begin
- Result := FViewers[I];
- IsOnlyItemWithAccel := not EnabledItems or
- (FindAccel(I, Primary, EnabledItems) = I);
- Exit;
- end;
- end;
- end;
- procedure TTBView.EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions);
- var
- ModalHandler: TTBModalHandler;
- P: TPoint;
- begin
- if vsModal in FState then Exit;
- ModalHandler := TTBModalHandler.Create(FWindow.Handle);
- try
- { remove all states except... }
- FState := FState * [vsShowAccels];
- try
- Include(FState, vsModal);
- { Must ensure that DoneAction is reset to tbdaNone *before* calling
- NotifyFocusEvent so that the IsModalEnding call it makes won't return
- True }
- FDoneActionData.DoneAction := tbdaNone;
- { Now that the vsModal state has been added, send an MSAA focus event }
- if Assigned(Selected) then
- NotifyFocusEvent;
- ModalHandler.Loop(Self, tbetMouseDown in Options,
- tbetExecuteSelected in Options, tbetFromMSAA in Options, False);
- finally
- { Remove vsModal state from the root view before any TTBView.Destroy
- methods get called (as a result of the CloseChildPopups call below),
- so that NotifyFocusEvent becomes a no-op }
- Exclude(FState, vsModal);
- StopAllTimers;
- CloseChildPopups;
- GetCursorPos(P);
- UpdateSelection(@P, True);
- end;
- finally
- ModalHandler.Free;
- end;
- SetAccelsVisibility(False);
- Selected := nil;
- // caused flicker: FWindow.Update;
- ProcessDoneAction(FDoneActionData, False);
- end;
- procedure TTBView.SetCustomizing(Value: Boolean);
- begin
- if FCustomizing <> Value then begin
- FCustomizing := Value;
- RecreateAllViewers;
- end;
- end;
- procedure TTBView.BeginUpdate;
- begin
- Inc(FUpdating);
- end;
- procedure TTBView.EndUpdate;
- begin
- Dec(FUpdating);
- if FUpdating = 0 then
- TryValidatePositions;
- end;
- procedure TTBView.GetOffEdgeControlList(const List: TList);
- var
- I: Integer;
- Item: TTBCustomItem;
- begin
- for I := 0 to FViewerCount-1 do begin
- Item := FViewers[I].Item;
- if (Item is TTBControlItem) and FViewers[I].OffEdge and
- (TTBControlItem(Item).FControl is TWinControl) then
- List.Add(TTBControlItem(Item).FControl);
- end;
- end;
- procedure TTBView.SetCapture;
- begin
- FCapture := True;
- end;
- procedure TTBView.CancelCapture;
- begin
- if FCapture then begin
- FCapture := False;
- LastPos.X := Low(LastPos.X);
- if Assigned(FSelected) then
- FSelected.LosingCapture;
- end;
- end;
- procedure TTBView.KeyDown(var Key: Word; Shift: TShiftState);
- procedure SelNextItem(const ParentView: TTBView; const GoForward: Boolean);
- begin
- ParentView.Selected := ParentView.NextSelectable(ParentView.FSelected,
- GoForward);
- ParentView.ScrollSelectedIntoView;
- end;
- procedure HelpKey;
- var
- V: TTBView;
- ContextID: Integer;
- { MP }
- HelpKeyword: string;
- begin
- ContextID := 0;
- V := Self;
- while Assigned(V) do begin
- if Assigned(V.FSelected) then begin
- ContextID := V.FSelected.Item.HelpContext;
- if ContextID <> 0 then Break;
- end;
- V := V.FParentView;
- end;
- { MP }
- if ContextID <> 0 then
- begin
- EndModalWithHelp(ContextID);
- Exit;
- end;
- HelpKeyword := '';
- V := Self;
- while Assigned(V) do begin
- if Assigned(V.FSelected) then begin
- HelpKeyword := V.FSelected.Item.HelpKeyword;
- if HelpKeyword <> '' then Break;
- end;
- V := V.FParentView;
- end;
- if HelpKeyword <> '' then
- EndModalWithHelp(HelpKeyword);
- { /MP }
- end;
- var
- ParentTBView: TTBView;
- begin
- ParentTBView := GetParentToolbarView;
- case Key of
- VK_TAB: begin
- SelNextItem(Self, GetKeyState(VK_SHIFT) >= 0);
- end;
- VK_RETURN: begin
- ExecuteSelected(True);
- end;
- VK_MENU, VK_F10: begin
- EndModal;
- end;
- VK_ESCAPE: begin
- Key := 0;
- if FParentView = nil then
- EndModal
- else
- FParentView.CancelChildPopups;
- end;
- VK_LEFT, VK_RIGHT: begin
- if (Self = ParentTBView) and (Orientation = tbvoVertical) then
- OpenChildPopup(True)
- else if Key = VK_LEFT then begin
- if Assigned(ParentTBView) and (ParentTBView.Orientation <> tbvoVertical) then begin
- if (Self = ParentTBView) or
- (FParentView = ParentTBView) then
- SelNextItem(ParentTBView, False)
- else
- FParentView.CloseChildPopups;
- end
- else begin
- if Assigned(FParentView) then
- FParentView.CancelChildPopups;
- end;
- end
- else begin
- if ((Self = ParentTBView) or not OpenChildPopup(True)) and
- (Assigned(ParentTBView) and (ParentTBView.Orientation <> tbvoVertical)) then begin
- { If we're on ParentTBView, or if the selected item can't display
- a submenu, proceed to next item on ParentTBView }
- SelNextItem(ParentTBView, True);
- end;
- end;
- end;
- VK_UP, VK_DOWN: begin
- if (Self = ParentTBView) and (Orientation <> tbvoVertical) then
- OpenChildPopup(True)
- else
- SelNextItem(Self, Key = VK_DOWN);
- end;
- VK_HOME, VK_END: begin
- Selected := NextSelectable(nil, Key = VK_HOME);
- ScrollSelectedIntoView;
- end;
- VK_F1: HelpKey;
- else
- Exit; { don't set Key to 0 for unprocessed keys }
- end;
- Key := 0;
- end;
- function TTBView.IsModalEnding: Boolean;
- begin
- Result := (GetRootView.FDoneActionData.DoneAction <> tbdaNone);
- end;
- procedure TTBView.EndModal;
- var
- RootView: TTBView;
- begin
- RootView := GetRootView;
- RootView.FDoneActionData.DoneAction := tbdaCancel;
- end;
- procedure TTBView.EndModalWithClick(AViewer: TTBItemViewer);
- var
- RootView: TTBView;
- begin
- RootView := GetRootView;
- RootView.FDoneActionData.ClickItem := AViewer.Item;
- RootView.FDoneActionData.Sound := AViewer.FView.FIsPopup;
- RootView.FDoneActionData.DoneAction := tbdaClickItem;
- end;
- procedure TTBView.EndModalWithHelp(AContextID: Integer);
- var
- RootView: TTBView;
- begin
- RootView := GetRootView;
- RootView.FDoneActionData.ContextID := AContextID;
- RootView.FDoneActionData.DoneAction := tbdaHelpContext;
- end;
- { MP }
- procedure TTBView.EndModalWithHelp(HelpKeyword: string);
- var
- RootView: TTBView;
- begin
- RootView := GetRootView;
- RootView.FDoneActionData.HelpKeyword := ShortString(HelpKeyword);
- RootView.FDoneActionData.DoneAction := tbdaHelpKeyword;
- end;
- { /MP }
- procedure TTBView.EndModalWithSystemMenu(AWnd: HWND; AKey: Cardinal);
- var
- RootView: TTBView;
- begin
- RootView := GetRootView;
- RootView.FDoneActionData.Wnd := AWnd;
- RootView.FDoneActionData.Key := AKey;
- RootView.FDoneActionData.DoneAction := tbdaOpenSystemMenu;
- end;
- procedure TTBView.ExecuteSelected(AGivePriority: Boolean);
- { Normally called after an Enter or accelerator key press on the view, this
- method 'executes' or opens the selected item. It ends the modal loop, except
- when a submenu is opened. }
- var
- Item: TTBCustomItem;
- begin
- if Assigned(FSelected) and FSelected.Item.Enabled then begin
- Item := FSelected.Item;
- if (tbisCombo in Item.ItemStyle) or not OpenChildPopup(True) then begin
- if tbisSelectable in Item.ItemStyle then
- FSelected.Execute(AGivePriority)
- else
- EndModal;
- end
- end
- else
- EndModal;
- Exit; asm db 0,'Toolbar2000 (C) 1998-2005 Jordan Russell',0 end;
- end;
- procedure TTBView.Scroll(ADown: Boolean);
- var
- CurPos, NewPos, I: Integer;
- begin
- ValidatePositions;
- if ADown then begin
- NewPos := High(NewPos);
- CurPos := FMaxHeight - tbMenuScrollArrowHeight;
- for I := 0 to FViewerCount-1 do begin
- with FViewers[I] do
- if Clipped and not(tbisSeparator in Item.ItemStyle) and
- (BoundsRect.Bottom < NewPos) and (BoundsRect.Bottom > CurPos) then
- NewPos := BoundsRect.Bottom;
- end;
- if NewPos = High(NewPos) then
- Exit;
- Dec(NewPos, FMaxHeight - tbMenuScrollArrowHeight);
- end
- else begin
- NewPos := Low(NewPos);
- CurPos := tbMenuScrollArrowHeight;
- for I := 0 to FViewerCount-1 do begin
- with FViewers[I] do
- if Clipped and not(tbisSeparator in Item.ItemStyle) and
- (BoundsRect.Top > NewPos) and (BoundsRect.Top < CurPos) then
- NewPos := BoundsRect.Top;
- end;
- if NewPos = Low(NewPos) then
- Exit;
- Dec(NewPos, tbMenuScrollArrowHeight);
- end;
- Inc(FScrollOffset, NewPos);
- UpdatePositions;
- end;
- procedure TTBView.ScrollSelectedIntoView;
- begin
- ValidatePositions;
- if (FSelected = nil) or not FSelected.Clipped then
- Exit;
- if FSelected.BoundsRect.Top < tbMenuScrollArrowHeight then begin
- Dec(FScrollOffset, tbMenuScrollArrowHeight - FSelected.BoundsRect.Top);
- UpdatePositions;
- end
- else if FSelected.BoundsRect.Bottom > FMaxHeight - tbMenuScrollArrowHeight then begin
- Dec(FScrollOffset, (FMaxHeight - tbMenuScrollArrowHeight) -
- FSelected.BoundsRect.Bottom);
- UpdatePositions;
- end;
- end;
- procedure TTBView.SetUsePriorityList(Value: Boolean);
- begin
- if FUsePriorityList <> Value then begin
- FUsePriorityList := Value;
- RecreateAllViewers;
- end;
- end;
- function TTBView.GetCaptureWnd: HWND;
- begin
- Result := GetRootView.FCaptureWnd;
- end;
- procedure TTBView.CancelMode;
- var
- View: TTBView;
- begin
- EndModal;
- { Hide all parent/child popup windows. Can't actually destroy them using
- CloseChildPopups because this method may be called while inside
- TTBEditItemViewer's message loop, and it could result in the active
- TTBEditItemViewer instance being destroyed (leading to an AV). }
- View := Self;
- while Assigned(View.FOpenViewerView) do
- View := View.FOpenViewerView;
- repeat
- View.StopAllTimers;
- if View.FWindow is TTBPopupWindow then
- View.FWindow.Visible := False;
- View := View.FParentView;
- until View = nil;
- { Note: This doesn't remove the selection from a top-level toolbar item.
- Unfortunately, we can't do 'Selected := nil' because it would destroy
- child popups and that must'nt happen for the reason stated above. }
- end;
- procedure TTBView.SetState(AState: TTBViewState);
- begin
- FState := AState;
- end;
- function TTBView.GetMonitor: TMonitor;
- begin
- if ParentView <> nil then
- begin
- Result := ParentView.GetMonitor;
- end
- else
- if not IsRectEmpty(FMonitorRect) then
- begin
- Result := Screen.MonitorFromRect(FMonitorRect);
- end
- else
- begin
- Result := GetMonitorFromControl(Window);
- end;
- end;
- { TTBModalHandler }
- const
- LSFW_LOCK = 1;
- LSFW_UNLOCK = 2;
- var
- LockSetForegroundWindowInited: BOOL;
- LockSetForegroundWindow: function(uLockCode: UINT): BOOL; stdcall;
- constructor TTBModalHandler.Create(AExistingWnd: HWND);
- begin
- inherited Create;
- LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
- if AExistingWnd <> 0 then
- FWnd := AExistingWnd
- else begin
- FWnd := Classes.AllocateHWnd(WndProc);
- FCreatedWnd := True;
- end;
- { Like standard menus, don't allow other apps to steal the focus during
- our modal loop. This also prevents us from losing activation when
- "active window tracking" is enabled and the user moves the mouse over
- another application's window. }
- LockForegroundWindow;
- SetCapture(FWnd);
- SetCursor(LoadCursor(0, IDC_ARROW));
- NotifyWinEvent(EVENT_SYSTEM_MENUSTART, FWnd, OBJID_CLIENT, CHILDID_SELF);
- FInited := True;
- end;
- class procedure TTBModalHandler.DoLockForegroundWindow(LockCode: Cardinal);
- begin
- if not LockSetForegroundWindowInited then begin
- LockSetForegroundWindow := GetProcAddress(GetModuleHandle(user32),
- 'LockSetForegroundWindow');
- InterlockedExchange(Integer(LockSetForegroundWindowInited), Ord(True));
- end;
- { Should always, as supported since Windows 2000 }
- if Assigned(LockSetForegroundWindow) then
- LockSetForegroundWindow(LockCode);
- end;
- class procedure TTBModalHandler.LockForegroundWindow;
- begin
- DoLockForegroundWindow(LSFW_LOCK);
- end;
- class procedure TTBModalHandler.UnlockForegroundWindow;
- begin
- DoLockForegroundWindow(LSFW_UNLOCK);
- end;
- destructor TTBModalHandler.Destroy;
- begin
- UnlockForegroundWindow;
- if FWnd <> 0 then begin
- if GetCapture = FWnd then
- ReleaseCapture;
- if FInited then
- NotifyWinEvent(EVENT_SYSTEM_MENUEND, FWnd, OBJID_CLIENT, CHILDID_SELF);
- if FCreatedWnd then
- Classes.DeallocateHWnd(FWnd);
- end;
- inherited;
- end;
- procedure TTBModalHandler.WndProc(var Msg: TMessage);
- begin
- Msg.Result := DefWindowProc(FWnd, Msg.Msg, Msg.WParam, Msg.LParam);
- if (Msg.Msg = WM_CANCELMODE) and Assigned(FRootPopup) then begin
- try
- { We can receive a WM_CANCELMODE message during a modal loop if a dialog
- pops up. Respond by hiding menus to make it look like the modal loop
- has returned, even though it really hasn't yet.
- Note: Similar code in TTBCustomToolbar.WMCancelMode. }
- FRootPopup.View.CancelMode;
- except
- Application.HandleException(Self);
- end;
- end;
- end;
- procedure TTBModalHandler.Loop(const RootView: TTBView;
- const AMouseDown, AExecuteSelected, AFromMSAA, TrackRightButton: Boolean);
- var
- OriginalActiveWindow: HWND;
- function GetActiveView: TTBView;
- begin
- Result := RootView;
- while Assigned(Result.FOpenViewerView) do
- Result := Result.FOpenViewerView;
- end;
- procedure UpdateAllSelections(const P: TPoint; const AllowNewSelection: Boolean);
- var
- View, CapView: TTBView;
- begin
- View := GetActiveView;
- CapView := View;
- while Assigned(CapView) and not CapView.FCapture do
- CapView := CapView.FParentView;
- while Assigned(View) do begin
- if (CapView = nil) or (View = CapView) then
- View.UpdateSelection(@P, AllowNewSelection);
- View := View.FParentView;
- end;
- end;
- function GetSelectedViewer(var AView: TTBView; var AViewer: TTBItemViewer): Boolean;
- { Returns True if AViewer <> nil. }
- var
- View: TTBView;
- begin
- AView := nil;
- AViewer := nil;
- { Look for a capture item first }
- View := RootView;
- repeat
- if View.FCapture then begin
- AView := View;
- AViewer := View.FSelected;
- Break;
- end;
- View := View.FOpenViewerView;
- until View = nil;
- if View = nil then begin
- View := RootView;
- repeat
- if Assigned(View.FSelected) and View.FMouseOverSelected then begin
- AView := View;
- AViewer := View.FSelected;
- Break;
- end;
- if vsMouseInWindow in View.FState then begin
- { ...there is no current selection, but the mouse is still in the
- window. This can happen if the mouse is over the non-client area
- of the toolbar or popup window, or in an area not containing an
- item. }
- AView := View;
- Break;
- end;
- View := View.FOpenViewerView;
- until View = nil;
- end;
- Result := Assigned(AViewer);
- end;
- function ContinueLoop: Boolean;
- begin
- { Don't continue if the mouse capture is lost, if a (modeless) top-level
- window is shown causing the active window to change, or if EndModal* was
- called. }
- Result := (GetCapture = FWnd) and (GetActiveWindow = OriginalActiveWindow)
- and not RootView.IsModalEnding;
- end;
- function SendKeyEvent(const View: TTBView; var Key: Word;
- const Shift: TShiftState): Boolean;
- begin
- Result := True;
- if Assigned(View.FSelected) then begin
- View.FSelected.KeyDown(Key, Shift);
- if RootView.IsModalEnding then
- Exit;
- end;
- if Key <> 0 then begin
- View.KeyDown(Key, Shift);
- if RootView.IsModalEnding then
- Exit;
- end;
- Result := False;
- end;
- procedure DoHintMouseMessage(const Ctl: TControl; const P: TPoint);
- var
- M: TWMMouseMove;
- begin
- M.Msg := WM_MOUSEMOVE;
- M.Keys := 0;
- M.Pos := PointToSmallPoint(P);
- Application.HintMouseMessage(Ctl, TMessage(M));
- end;
- procedure MouseMoved;
- var
- View: TTBView;
- Cursor: HCURSOR;
- Item: TTBCustomItem;
- P: TPoint;
- R: TRect;
- begin
- UpdateAllSelections(LastPos, True);
- View := GetActiveView;
- Cursor := 0;
- if Assigned(View.FSelected) and Assigned(View.FWindow) then begin
- Item := View.FSelected.Item;
- P := View.FWindow.ScreenToClient(LastPos);
- if ((vsAlwaysShowHints in View.FStyle) or
- (tboShowHint in Item.FEffectiveOptions)) and not View.FCapture then begin
- { Display popup hint for the item. Update is called
- first to minimize flicker caused by the hiding &
- showing of the hint window. }
- View.FWindow.Update;
- DoHintMouseMessage(View.FWindow, P);
- end
- else
- Application.CancelHint;
- R := View.FSelected.BoundsRect;
- Dec(P.X, R.Left);
- Dec(P.Y, R.Top);
- View.FSelected.GetCursor(P, Cursor);
- end
- else
- Application.CancelHint;
- if Cursor = 0 then
- Cursor := LoadCursor(0, IDC_ARROW);
- SetCursor(Cursor);
- end;
- procedure UpdateAppHint;
- var
- View: TTBView;
- begin
- View := RootView;
- while Assigned(View.FOpenViewerView) and Assigned(View.FOpenViewerView.FSelected) do
- View := View.FOpenViewerView;
- if Assigned(View.FSelected) then
- Application.Hint := GetLongHint(View.FSelected.Item.Hint)
- else
- Application.Hint := '';
- end;
- procedure HandleTimer(const View: TTBView; const ID: TTBViewTimerID);
- begin
- case ID of
- tiOpen: begin
- { Similar to standard menus, always close child popups, even if
- Selected = OpenViewer.
- Note: CloseChildPopups and OpenChildPopup will stop the tiClose
- and tiOpen timers respectively. }
- View.CloseChildPopups;
- View.OpenChildPopup(False);
- end;
- tiClose: begin
- { Note: CloseChildPopups stops the tiClose timer. }
- View.CloseChildPopups;
- end;
- tiScrollUp: begin
- if View.FShowUpArrow then
- View.Scroll(False)
- else
- View.StopTimer(tiScrollUp);
- end;
- tiScrollDown: begin
- if View.FShowDownArrow then
- View.Scroll(True)
- else
- View.StopTimer(tiScrollDown);
- end;
- end;
- end;
- var
- MouseDownOnMenu: Boolean;
- Msg: TMsg;
- P: TPoint;
- Ctl: TControl;
- View: TTBView;
- IsOnlyItemWithAccel: Boolean;
- MouseIsDown: Boolean;
- Key: Word;
- Shift: TShiftState;
- Viewer: TTBItemViewer;
- begin
- FillChar(RootView.FDoneActionData, SizeOf(RootView.FDoneActionData), 0);
- RootView.ValidatePositions;
- try
- try
- RootView.FCaptureWnd := FWnd;
- MouseDownOnMenu := False;
- if AMouseDown then begin
- P := RootView.FSelected.ScreenToClient(SmallPointToPoint(TSmallPoint(GetMessagePos())));
- RootView.FSelected.MouseDown([], P.X, P.Y, MouseDownOnMenu);
- if RootView.IsModalEnding then
- Exit;
- MouseDownOnMenu := False; { never set MouseDownOnMenu to True on first click }
- end
- else if AExecuteSelected then begin
- RootView.ExecuteSelected(not AFromMSAA);
- if RootView.IsModalEnding then
- Exit;
- end;
- OriginalActiveWindow := GetActiveWindow;
- while ContinueLoop do begin
- { Examine the next message before popping it out of the queue }
- if not PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then begin
- WaitMessage;
- Continue;
- end;
- case Msg.message of
- WM_LBUTTONDOWN, WM_RBUTTONDOWN: begin
- P := SmallPointToPoint(TSmallPoint(Msg.lParam));
- Windows.ClientToScreen(Msg.hwnd, P);
- Ctl := FindDragTarget(P, True);
- { Was the mouse not clicked on a popup, or was it clicked on a
- popup that is not a child of RootView?
- (The latter can happen when in customization mode, for example,
- if the user right-clicks a popup menu being customized and
- the context menu is displayed.) }
- if not(Ctl is TTBPopupWindow) or
- not RootView.ContainsView(TTBPopupWindow(Ctl).View) then begin
- { If the root view is a popup, or if the root view is a toolbar
- and the user clicked outside the toolbar or in its non-client
- area (e.g. on its drag handle), exit }
- if RootView.FIsPopup or (Ctl <> RootView.FWindow) or
- not PtInRect(RootView.FWindow.ClientRect, RootView.FWindow.ScreenToClient(P)) then
- Exit
- else
- if Msg.message = WM_LBUTTONDOWN then begin
- { If the user clicked inside a toolbar on anything but an
- item, exit }
- UpdateAllSelections(P, True);
- if (RootView.FSelected = nil) or not RootView.FMouseOverSelected or
- (tbisClicksTransparent in RootView.FSelected.Item.ItemStyle) then
- Exit;
- end;
- end;
- end;
- end;
- { Now pop the message out of the queue }
- if not PeekMessage(Msg, 0, Msg.message, Msg.message, PM_REMOVE or PM_NOYIELD) then
- Continue;
- case Msg.message of
- $4D:
- { This undocumented message is sent to the focused window when
- F1 is pressed. Windows handles it by sending a WM_HELP message
- to the same window. We don't want this to happen while a menu
- is up, so swallow the message. }
- ;
- WM_CONTEXTMENU:
- { Windows still sends WM_CONTEXTMENU messages for "context menu"
- keystrokes even if WM_KEYUP messages are never dispatched,
- so it must specifically ignore this message }
- ;
- WM_KEYFIRST..WM_KEYLAST: begin
- Application.CancelHint;
- MouseIsDown := (GetKeyState(VK_LBUTTON) < 0) or
- (TrackRightButton and (GetKeyState(VK_RBUTTON) < 0));
- case Msg.message of
- WM_KEYDOWN, WM_SYSKEYDOWN:
- begin
- if Msg.wParam = VK_PROCESSKEY then
- { Don't let IME process the key }
- Msg.wParam := ImmGetVirtualKey(Msg.hwnd);
- if not MouseIsDown or (Msg.wParam = VK_F1) then begin
- Key := Word(Msg.wParam);
- if SendKeyEvent(GetActiveView, Key,
- KeyDataToShiftState(Msg.lParam)) then
- Exit;
- { If it's not handled by a KeyDown method, translate
- it into a WM_*CHAR message }
- if Key <> 0 then
- TranslateMessage(Msg);
- end;
- end;
- WM_CHAR, WM_SYSCHAR:
- if not MouseIsDown then begin
- View := GetActiveView;
- Viewer := View.NextSelectableWithAccel(View.FSelected,
- Chr(Msg.WParam), False, IsOnlyItemWithAccel);
- if Viewer = nil then begin
- if (Msg.WParam in [VK_SPACE, Ord('-')]) and
- not RootView.FIsPopup and (View = RootView) and
- (GetActiveWindow <> 0) then begin
- RootView.EndModalWithSystemMenu(GetActiveWindow,
- Msg.WParam);
- Exit;
- end
- else
- MessageBeep(0);
- end
- else begin
- View.Selected := Viewer;
- View.ScrollSelectedIntoView;
- if IsOnlyItemWithAccel then
- View.ExecuteSelected(True);
- end;
- end;
- end;
- end;
- WM_TIMER:
- begin
- Ctl := FindControl(Msg.hwnd);
- if Assigned(Ctl) and (Ctl is TTBPopupWindow) and
- (Msg.wParam >= ViewTimerBaseID + Ord(Low(TTBViewTimerID))) and
- (Msg.wParam <= ViewTimerBaseID + Ord(High(TTBViewTimerID))) then begin
- if Assigned(TTBPopupWindow(Ctl).FView) then
- HandleTimer(TTBPopupWindow(Ctl).FView,
- TTBViewTimerID(WPARAM(Msg.wParam - ViewTimerBaseID)));
- end
- else
- DispatchMessage(Msg);
- end;
- $118: ;
- { ^ Like standard menus, don't dispatch WM_SYSTIMER messages
- (the internal Windows message used for things like caret
- blink and list box scrolling). }
- WM_MOUSEFIRST..WM_MOUSELAST:
- case Msg.message of
- WM_MOUSEMOVE: begin
- if (Msg.pt.X <> LastPos.X) or (Msg.pt.Y <> LastPos.Y) then begin
- LastPos := Msg.pt;
- MouseMoved;
- end;
- if GetSelectedViewer(View, Viewer) then begin
- P := Viewer.ScreenToClient(Msg.pt);
- Viewer.MouseMove(P.X, P.Y);
- end;
- end;
- WM_MOUSEWHEEL:
- if GetSelectedViewer(View, Viewer) then begin
- P := Viewer.ScreenToClient(Msg.pt);
- Viewer.MouseWheel(Smallint(LongRec(Msg.wParam).Hi), P.X, P.Y);
- end;
- WM_LBUTTONDOWN, WM_LBUTTONDBLCLK, WM_RBUTTONDOWN:
- if (Msg.message <> WM_RBUTTONDOWN) or TrackRightButton then begin
- Application.CancelHint;
- MouseDownOnMenu := False;
- Exclude(RootView.FState, vsIgnoreFirstMouseUp);
- UpdateAllSelections(Msg.pt, True);
- if GetSelectedViewer(View, Viewer) then begin
- if Msg.message <> WM_LBUTTONDBLCLK then
- Shift := []
- else
- Shift := [ssDouble];
- P := Viewer.ScreenToClient(Msg.pt);
- Viewer.MouseDown(Shift, P.X, P.Y, MouseDownOnMenu);
- LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
- end;
- end;
- WM_LBUTTONUP, WM_RBUTTONUP:
- if (Msg.message = WM_LBUTTONUP) or TrackRightButton then begin
- UpdateAllSelections(Msg.pt, False);
- { ^ False is used so that when a popup menu is
- displayed with the cursor currently inside it, the item
- under the cursor won't be accidentally selected when the
- user releases the button. The user must move the mouse at
- at least one pixel (generating a WM_MOUSEMOVE message),
- and then release the button. }
- if not GetSelectedViewer(View, Viewer) then begin
- { Mouse was not released over any item. Cancel out of the
- loop if it's outside all views, or is inside unused
- space on a topmost toolbar }
- if not Assigned(View) or
- ((View = RootView) and RootView.FIsToolbar) then begin
- if not(vsIgnoreFirstMouseUp in RootView.FState) then
- Exit
- else
- Exclude(RootView.FState, vsIgnoreFirstMouseUp);
- end;
- end
- else begin
- P := Viewer.ScreenToClient(Msg.pt);
- Viewer.MouseUp(P.X, P.Y, MouseDownOnMenu);
- end;
- end;
- end;
- else
- DispatchMessage(Msg);
- end;
- if not ContinueLoop then
- begin
- Exit;
- end;
- if LastPos.X = Low(LastPos.X) then begin
- LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
- MouseMoved;
- end;
- UpdateAppHint;
- end;
- finally
- RootView.CancelCapture;
- end;
- finally
- RootView.FCaptureWnd := 0;
- Application.Hint := '';
- { Make sure there are no outstanding WM_*CHAR messages }
- RemoveMessages(WM_CHAR, WM_DEADCHAR);
- RemoveMessages(WM_SYSCHAR, WM_SYSDEADCHAR);
- { Nor any outstanding 'send WM_HELP' messages caused by an earlier press
- of the F1 key }
- RemoveMessages($4D, $4D);
- end;
- end;
- { TTBPopupView }
- procedure TTBPopupView.AutoSize(AWidth, AHeight: Integer);
- begin
- with TTBPopupWindow(FWindow) do
- with GetNCSize do
- SetBounds(Left, Top, AWidth + (X * 2),
- AHeight + (Y * 2));
- end;
- function TTBPopupView.GetMonitor: TMonitor;
- begin
- Result := Screen.MonitorFromRect(FWindow.BoundsRect);
- end;
- function TTBPopupView.GetFont: TFont;
- begin
- Result := (Owner as TTBPopupWindow).Font;
- end;
- { TTBPopupWindow }
- constructor TTBPopupWindow.CreatePopupWindow(AOwner: TComponent;
- const AParentView: TTBView; const AItem: TTBCustomItem;
- const ACustomizing: Boolean; const PopupPoint: TPoint);
- begin
- inherited Create(AOwner);
- Visible := False;
- SetBounds(PopupPoint.X, PopupPoint.Y, 320, 240);
- ControlStyle := ControlStyle - [csCaptureMouse];
- ShowHint := True;
- Color := tbMenuBkColor;
- FView := GetViewClass.CreateView(Self, AParentView, AItem, Self, False,
- ACustomizing, False);
- Include(FView.FState, vsModal);
- { Inherit the font from the parent view, or use the system menu font if
- there is no parent view }
- if Assigned(AParentView) then
- Font.Assign(AParentView.GetFont)
- else
- Font.Assign(GetToolbarFont(GetMonitorPixelsPerInch(Screen.MonitorFromPoint(PopupPoint))));
- { Inherit the accelerator visibility state from the parent view. If there
- is no parent view (i.e. it's a standalone popup menu), then default to
- hiding accelerator keys, but change this in CreateWnd if the last input
- came from the keyboard. }
- if Assigned(AParentView) then begin
- if vsUseHiddenAccels in AParentView.FStyle then
- Include(FView.FStyle, vsUseHiddenAccels);
- if vsShowAccels in AParentView.FState then
- Include(FView.FState, vsShowAccels);
- end
- else
- Include(FView.FStyle, vsUseHiddenAccels);
- if Application.Handle <> 0 then
- { Use Application.Handle if possible so that the taskbar button for the app
- doesn't pop up when a TTBEditItem on a popup menu is focused }
- ParentWindow := Application.Handle
- else
- { When Application.Handle is zero, use GetDesktopWindow() as the parent
- window, not zero, otherwise UpdateControlState won't show the window }
- ParentWindow := GetDesktopWindow;
- end;
- destructor TTBPopupWindow.Destroy;
- begin
- Destroying;
- { Ensure window handle is destroyed *before* FView is freed, since
- DestroyWindowHandle calls NotifyWinEvent which may result in
- FView.HandleWMObject being called }
- if HandleAllocated then
- DestroyWindowHandle;
- FreeAndNil(FView);
- inherited;
- end;
- {MP}
- procedure TTBPopupWindow.Cancel;
- begin
- { noop }
- end;
- procedure TTBPopupWindow.BeforeDestruction;
- begin
- { The inherited BeforeDestruction method hides the form. We need to close
- any child popups first, so that pixels behind the popups are properly
- restored without generating a WM_PAINT message. }
- if Assigned(FView) then
- FView.CloseChildPopups;
- inherited;
- end;
- function TTBPopupWindow.GetNCSize: TPoint;
- begin
- Result.X := PopupMenuWindowNCSize;
- Result.Y := PopupMenuWindowNCSize;
- end;
- function TTBPopupWindow.GetViewClass: TTBViewClass;
- begin
- Result := TTBPopupView;
- end;
- procedure TTBPopupWindow.CreateParams(var Params: TCreateParams);
- const
- CS_DROPSHADOW = $00020000;
- begin
- inherited;
- with Params do begin
- Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP;
- ExStyle := ExStyle or WS_EX_TOPMOST or WS_EX_TOOLWINDOW;
- WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
- WindowClass.Style := WindowClass.Style or CS_DROPSHADOW;
- end;
- end;
- procedure TTBPopupWindow.CreateWnd;
- const
- WM_CHANGEUISTATE = $0127;
- WM_QUERYUISTATE = $0129;
- UIS_INITIALIZE = 3;
- UISF_HIDEACCEL = $2;
- var
- B: Boolean;
- begin
- inherited;
- { On a top-level popup window, send WM_CHANGEUISTATE & WM_QUERYUISTATE
- messages to the window to see if the last input came from the keyboard
- and if the accelerator keys should be shown }
- if (FView.ParentView = nil) and not FAccelsVisibilitySet then begin
- FAccelsVisibilitySet := True;
- SendMessage(Handle, WM_CHANGEUISTATE, UIS_INITIALIZE, 0);
- B := (SendMessage(Handle, WM_QUERYUISTATE, 0, 0) and UISF_HIDEACCEL = 0);
- FView.SetAccelsVisibility(B);
- end;
- end;
- procedure TTBPopupWindow.DestroyWindowHandle;
- begin
- { Before destroying the window handle, we must stop any animation, otherwise
- the animation thread will use an invalid handle }
- TBEndAnimation(WindowHandle);
- { Cleanly destroy any timers before the window handle is destroyed }
- if Assigned(FView) then
- FView.StopAllTimers;
- NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, WindowHandle, OBJID_CLIENT,
- CHILDID_SELF);
- inherited;
- end;
- procedure TTBPopupWindow.WMGetObject(var Message: TMessage);
- begin
- if not FView.HandleWMGetObject(Message) then
- inherited;
- end;
- procedure TTBPopupWindow.CMShowingChanged(var Message: TMessage);
- const
- ShowFlags: array[Boolean] of UINT = (
- SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW,
- SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
- SPI_GETMENUFADE = $1012;
- var
- Animate: BOOL;
- Blend: Boolean;
- begin
- { Must override TCustomForm/TForm's CM_SHOWINGCHANGED handler so that the
- form doesn't get activated when Visible is set to True. }
- { Handle animation. NOTE: I do not recommend trying to enable animation on
- Windows 95 and NT 4.0 because there's a difference in the way the
- SetWindowPos works on those versions. See the comment in the
- TBStartAnimation function of TB2Anim.pas. }
- {$IFNDEF TB2K_NO_ANIMATION}
- if ((FView.ParentView = nil) or not(vsNoAnimation in FView.FParentView.FState)) and
- Showing and (FView.Selected = nil) and not IsWindowVisible(WindowHandle) and
- SystemParametersInfo(SPI_GETMENUANIMATION, 0, @Animate, 0) and Animate then begin
- Blend := SystemParametersInfo(SPI_GETMENUFADE, 0, @Animate, 0) and Animate;
- if Blend or (FAnimationDirection <> []) then begin
- if SendMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_ANIMSTART, 0) = 0 then
- begin
- { Start animation only if WM_TB2K_POPUPSHOWING returns zero (or not handled) }
- TBStartAnimation(WindowHandle, Blend, FAnimationDirection);
- Exit;
- end;
- end;
- end;
- {$ENDIF}
- { No animation... }
- if not Showing then begin
- { Call TBEndAnimation to ensure WS_EX_LAYERED style is removed before
- hiding, otherwise windows under the popup window aren't repainted
- properly. }
- TBEndAnimation(WindowHandle);
- end;
- SetWindowPos(WindowHandle, 0, 0, 0, 0, 0, ShowFlags[Showing]);
- if Showing then SendNotifyMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_NOANIM, 0);
- end;
- procedure TTBPopupWindow.WMTB2kAnimationEnded(var Message: TMessage);
- begin
- SendNotifyMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_ANIMFINISHED, 0);
- end;
- procedure TTBPopupWindow.WMTB2kStepAnimation(var Message: TMessage);
- begin
- TBStepAnimation(Message);
- end;
- procedure TTBPopupWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
- begin
- { May be necessary in some cases... }
- TBEndAnimation(WindowHandle);
- inherited;
- end;
- procedure TTBPopupWindow.WMPaint(var Message: TWMPaint);
- begin
- { Must abort animation when a WM_PAINT message is received }
- TBEndAnimation(WindowHandle);
- inherited;
- end;
- procedure TTBPopupWindow.Paint;
- begin
- FView.DrawSubitems(Canvas);
- PaintScrollArrows;
- end;
- procedure TTBPopupWindow.PaintScrollArrows;
- procedure DrawArrow(const R: TRect; ADown: Boolean);
- var
- X, Y: Integer;
- P: array[0..2] of TPoint;
- begin
- X := (R.Left + R.Right) div 2;
- Y := (R.Top + R.Bottom) div 2;
- Dec(Y);
- P[0].X := X-3;
- P[0].Y := Y;
- P[1].X := X+3;
- P[1].Y := Y;
- P[2].X := X;
- P[2].Y := Y;
- if ADown then
- Inc(P[2].Y, 3)
- else begin
- Inc(P[0].Y, 3);
- Inc(P[1].Y, 3);
- end;
- Canvas.Pen.Color := tbMenuTextColor;
- Canvas.Brush.Color := tbMenuTextColor;
- Canvas.Polygon(P);
- end;
- begin
- if FView.FShowUpArrow then
- DrawArrow(Rect(0, 0, ClientWidth, tbMenuScrollArrowHeight), False);
- if FView.FShowDownArrow then
- DrawArrow(Bounds(0, ClientHeight - tbMenuScrollArrowHeight,
- ClientWidth, tbMenuScrollArrowHeight), True);
- end;
- procedure TTBPopupWindow.WMClose(var Message: TWMClose);
- begin
- { do nothing -- ignore Alt+F4 keypresses }
- end;
- procedure TTBPopupWindow.WMNCCalcSize(var Message: TWMNCCalcSize);
- begin
- with GetNCSize do
- InflateRect(Message.CalcSize_Params^.rgrc[0], -X, -Y);
- inherited;
- end;
- procedure PopupWindowNCPaintProc(Control: TControl; Wnd: HWND; DC: HDC; AppData: Longint);
- var
- R: TRect;
- {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
- Brush: HBRUSH;
- {$ENDIF}
- begin
- GetWindowRect(Wnd, R); OffsetRect(R, -R.Left, -R.Top);
- {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
- if not AreFlatMenusEnabled then begin
- {$ENDIF}
- DrawEdge(DC, R, EDGE_RAISED, BF_RECT or BF_ADJUST);
- FrameRect(DC, R, GetSysColorBrush(COLOR_BTNFACE));
- {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
- end
- else begin
- FrameRect(DC, R, GetSysColorBrush(COLOR_BTNSHADOW));
- Brush := CreateSolidBrush(ColorToRGB(TTBPopupWindow(AppData).Color));
- InflateRect(R, -1, -1);
- FrameRect(DC, R, Brush);
- InflateRect(R, -1, -1);
- FrameRect(DC, R, Brush);
- DeleteObject(Brush);
- end;
- {$ENDIF}
- end;
- procedure TTBPopupWindow.WMNCPaint(var Message: TMessage);
- var
- DC: HDC;
- begin
- DC := GetWindowDC(Handle);
- try
- SelectNCUpdateRgn(Handle, DC, HRGN(Message.WParam));
- PopupWindowNCPaintProc(Self, Handle, DC, Longint(Self));
- finally
- ReleaseDC(Handle, DC);
- end;
- end;
- procedure TTBPopupWindow.WMPrint(var Message: TMessage);
- begin
- HandleWMPrint(Self, Handle, Message, PopupWindowNCPaintProc, Longint(Self));
- end;
- procedure TTBPopupWindow.WMPrintClient(var Message: TMessage);
- begin
- HandleWMPrintClient(Self, Message);
- end;
- procedure TTBPopupWindow.CMHintShow(var Message: TCMHintShow);
- begin
- with Message.HintInfo^ do begin
- HintStr := '';
- if Assigned(FView.Selected) then begin
- CursorRect := FView.Selected.BoundsRect;
- HintStr := FView.FSelected.GetHintText;
- end;
- end;
- end;
- procedure TTBPopupWindow.CMHintShowPause(var Message: TMessage);
- begin
- // Hint was not active previously
- if not Boolean(Message.WParam) then
- begin
- PInteger(Message.LParam)^ := PInteger(Message.LParam)^ * 2;
- end;
- end;
- { TTBItemContainer }
- constructor TTBItemContainer.Create(AOwner: TComponent);
- begin
- inherited;
- FItem := TTBRootItem.Create(Self);
- FItem.ParentComponent := Self;
- end;
- destructor TTBItemContainer.Destroy;
- begin
- FItem.Free;
- inherited;
- end;
- function TTBItemContainer.GetItems: TTBCustomItem;
- begin
- Result := FItem;
- end;
- procedure TTBItemContainer.GetChildren(Proc: TGetChildProc; Root: TComponent);
- begin
- FItem.GetChildren(Proc, Root);
- end;
- function TTBItemContainer.GetImages: TCustomImageList;
- begin
- Result := FItem.SubMenuImages;
- end;
- procedure TTBItemContainer.SetImages(Value: TCustomImageList);
- begin
- FItem.SubMenuImages := Value;
- end;
- { TTBPopupMenu }
- constructor TTBPopupMenu.Create(AOwner: TComponent);
- begin
- inherited;
- FItem := GetRootItemClass.Create(Self);
- FItem.ParentComponent := Self;
- FItem.OnClick := RootItemClick;
- end;
- destructor TTBPopupMenu.Destroy;
- begin
- FItem.Free;
- inherited;
- end;
- function TTBPopupMenu.GetItems: TTBCustomItem;
- begin
- Result := FItem;
- end;
- procedure TTBPopupMenu.GetChildren(Proc: TGetChildProc; Root: TComponent);
- begin
- FItem.GetChildren(Proc, Root);
- end;
- procedure TTBPopupMenu.SetChildOrder(Child: TComponent; Order: Integer);
- begin
- FItem.SetChildOrder(Child, Order);
- end;
- function TTBPopupMenu.GetRootItemClass: TTBRootItemClass;
- begin
- Result := TTBRootItem;
- end;
- function TTBPopupMenu.GetImages: TCustomImageList;
- begin
- Result := FItem.SubMenuImages;
- end;
- function TTBPopupMenu.GetLinkSubitems: TTBCustomItem;
- begin
- Result := FItem.LinkSubitems;
- end;
- function TTBPopupMenu.GetOptions: TTBItemOptions;
- begin
- Result := FItem.Options;
- end;
- procedure TTBPopupMenu.SetImages(Value: TCustomImageList);
- begin
- FItem.SubMenuImages := Value;
- end;
- procedure TTBPopupMenu.SetLinkSubitems(Value: TTBCustomItem);
- begin
- FItem.LinkSubitems := Value;
- end;
- procedure TTBPopupMenu.SetOptions(Value: TTBItemOptions);
- begin
- FItem.Options := Value;
- end;
- procedure TTBPopupMenu.RootItemClick(Sender: TObject);
- begin
- if Sender = FItem then
- Sender := Self;
- DoPopup(Sender);
- end;
- procedure TTBPopupMenu.Popup(X, Y: Integer);
- begin
- PopupEx(X, Y, False);
- end;
- function TTBPopupMenu.PopupEx(X, Y: Integer;
- ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
- begin
- SetPopupPoint(Point(X, Y));
- Result := FItem.Popup(X, Y, TrackButton = tbRightButton,
- TTBPopupAlignment(Alignment), ReturnClickedItemOnly);
- end;
- function TTBPopupMenu.IsShortCut(var Message: TWMKey): Boolean;
- begin
- Result := FItem.IsShortCut(Message);
- end;
- { TTBImageList }
- constructor TTBCustomImageList.Create(AOwner: TComponent);
- begin
- inherited;
- FCheckedImagesChangeLink := TChangeLink.Create;
- FCheckedImagesChangeLink.OnChange := ImageListChanged;
- FDisabledImagesChangeLink := TChangeLink.Create;
- FDisabledImagesChangeLink.OnChange := ImageListChanged;
- FHotImagesChangeLink := TChangeLink.Create;
- FHotImagesChangeLink.OnChange := ImageListChanged;
- FImagesBitmap := TBitmap.Create;
- FImagesBitmap.OnChange := ImagesBitmapChanged;
- FImagesBitmapMaskColor := clFuchsia;
- end;
- destructor TTBCustomImageList.Destroy;
- begin
- FreeAndNil(FImagesBitmap);
- FreeAndNil(FHotImagesChangeLink);
- FreeAndNil(FDisabledImagesChangeLink);
- FreeAndNil(FCheckedImagesChangeLink);
- inherited;
- end;
- procedure TTBCustomImageList.ImagesBitmapChanged(Sender: TObject);
- begin
- if not ImagesBitmap.Empty then begin
- Clear;
- AddMasked(ImagesBitmap, FImagesBitmapMaskColor);
- end;
- end;
- procedure TTBCustomImageList.ImageListChanged(Sender: TObject);
- begin
- Change;
- end;
- procedure TTBCustomImageList.DefineProperties(Filer: TFiler);
- type
- TProc = procedure(ASelf: TObject; Filer: TFiler);
- begin
- if (Filer is TReader) or FImagesBitmap.Empty then
- inherited
- else
- { Bypass TCustomImageList.DefineProperties when we've got an ImageBitmap }
- TProc(@TComponentAccess.DefineProperties)(Self, Filer);
- end;
- procedure TTBCustomImageList.DrawState(Canvas: TCanvas; X, Y, Index: Integer;
- Enabled, Selected, Checked: Boolean);
- begin
- if not Enabled and Assigned(DisabledImages) then
- DisabledImages.Draw(Canvas, X, Y, Index)
- else if Checked and Assigned(CheckedImages) then
- CheckedImages.Draw(Canvas, X, Y, Index, Enabled)
- else if Selected and Assigned(HotImages) then
- HotImages.Draw(Canvas, X, Y, Index, Enabled)
- else
- Draw(Canvas, X, Y, Index, Enabled);
- end;
- procedure TTBCustomImageList.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- inherited;
- if Operation = opRemove then begin
- if AComponent = CheckedImages then CheckedImages := nil;
- if AComponent = DisabledImages then DisabledImages := nil;
- if AComponent = HotImages then HotImages := nil;
- end;
- end;
- procedure TTBCustomImageList.ChangeImages(var AImageList: TCustomImageList;
- Value: TCustomImageList; AChangeLink: TChangeLink);
- begin
- if Value = Self then
- Value := nil;
- if AImageList <> Value then begin
- if Assigned(AImageList) then
- AImageList.UnregisterChanges(AChangeLink);
- AImageList := Value;
- if Assigned(Value) then begin
- Value.RegisterChanges(AChangeLink);
- Value.FreeNotification(Self);
- end;
- { Don't call Change while loading because it causes the Delphi IDE to
- think the form has been modified (?). Also, don't call Change while
- destroying since there's no reason to. }
- if not(csLoading in ComponentState) and
- not(csDestroying in ComponentState) then
- Change;
- end;
- end;
- procedure TTBCustomImageList.SetCheckedImages(Value: TCustomImageList);
- begin
- ChangeImages(FCheckedImages, Value, FCheckedImagesChangeLink);
- end;
- procedure TTBCustomImageList.SetDisabledImages(Value: TCustomImageList);
- begin
- ChangeImages(FDisabledImages, Value, FDisabledImagesChangeLink);
- end;
- procedure TTBCustomImageList.SetHotImages(Value: TCustomImageList);
- begin
- ChangeImages(FHotImages, Value, FHotImagesChangeLink);
- end;
- procedure TTBCustomImageList.SetImagesBitmap(Value: TBitmap);
- begin
- FImagesBitmap.Assign(Value);
- end;
- procedure TTBCustomImageList.SetImagesBitmapMaskColor(Value: TColor);
- begin
- if FImagesBitmapMaskColor <> Value then begin
- FImagesBitmapMaskColor := Value;
- ImagesBitmapChanged(nil);
- end;
- end;
- { TTBBaseAccObject }
- { According to the MSAA docs:
- "With Active Accessibility 2.0, servers can return E_NOTIMPL from IDispatch
- methods and Active Accessibility will implement the IAccessible interface
- for them."
- And there was much rejoicing. }
- function TTBBaseAccObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
- NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
- begin
- Result := E_NOTIMPL;
- end;
- function TTBBaseAccObject.GetTypeInfo(Index, LocaleID: Integer;
- out TypeInfo): HResult;
- begin
- Result := E_NOTIMPL;
- end;
- function TTBBaseAccObject.GetTypeInfoCount(out Count: Integer): HResult;
- begin
- Result := E_NOTIMPL;
- end;
- function TTBBaseAccObject.Invoke(DispID: Integer; const IID: TGUID;
- LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
- ArgErr: Pointer): HResult;
- begin
- Result := E_NOTIMPL;
- end;
- { Initialization & finalization }
- var
- ToolbarFonts: TDictionary<Integer, TFont>;
- ToolbarFont: TFont;
- function CreateToolbarFont(PixelsPerInch: Integer): HFONT;
- var
- NonClientMetrics: TNonClientMetrics;
- begin
- FillChar(NonClientMetrics, SizeOf(NonClientMetrics), 0);
- NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
- Assert(HasSystemParametersInfoForPixelsPerInch);
- if SystemParametersInfoForPixelsPerInch(SPI_GETNONCLIENTMETRICS, SizeOf(NonClientMetrics), @NonClientMetrics, 0, PixelsPerInch) then
- begin
- Result := CreateFontIndirect(NonClientMetrics.lfMenuFont);
- end
- else
- begin
- Result := 0;
- end;
- end;
- function GetToolbarFont(Control: TControl; PixelsPerInch: Integer): TFont; overload;
- var
- H: HFONT;
- begin
- // Temporary redundant legacy fallback to limit impact of per-monitor DPI change
- if not HasSystemParametersInfoForPixelsPerInch then
- begin
- Result := ToolbarFont;
- end
- else
- begin
- // See the comment in TTBView.GetFont
- if not Assigned(ToolbarFonts) then
- begin
- Result := nil;
- end
- else
- begin
- if PixelsPerInch < 0 then
- begin
- PixelsPerInch := GetControlPixelsPerInch(Control);
- end;
- if not ToolbarFonts.TryGetValue(PixelsPerInch, Result) then
- begin
- H := CreateToolbarFont(PixelsPerInch);
- if H <> 0 then
- begin
- Result := TFont.Create;
- Result.Handle := H;
- ToolbarFonts.Add(PixelsPerInch, Result);
- end
- else
- begin
- Result := nil;
- end;
- end
- end;
- end;
- end;
- function GetToolbarFont(PixelsPerInch: Integer): TFont; overload;
- begin
- Result := GetToolbarFont(nil, PixelsPerInch);
- end;
- function GetToolbarFont(Control: TControl): TFont; overload;
- begin
- Result := GetToolbarFont(Control, -1);
- end;
- procedure TBInitToolbarSystemFont;
- var
- NonClientMetrics: TNonClientMetrics;
- FontPair: TPair<Integer, TFont>;
- begin
- NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
- if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
- begin
- ToolbarFont.Handle := CreateFontIndirect(NonClientMetrics.lfMenuFont);
- end;
- for FontPair in ToolbarFonts do
- begin
- FontPair.Value.Handle := CreateToolbarFont(FontPair.Key);
- end;
- end;
- procedure TBFinalizeToolbarSystemFont;
- var
- Font: TFont;
- begin
- for Font in ToolbarFonts.Values do
- begin
- Font.Free;
- end;
- end;
- initialization
- ToolbarFonts := TDictionary<Integer, TFont>.Create;
- ToolbarFont := TFont.Create;
- TBInitToolbarSystemFont;
- finalization
- DestroyClickWnd;
- FreeAndNil(ToolbarFont);
- TBFinalizeToolbarSystemFont;
- FreeAndNil(ToolbarFonts);
- end.
|