TB2Item.pas 222 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905
  1. unit TB2Item;
  2. {
  3. Toolbar2000
  4. Copyright (C) 1998-2005 by Jordan Russell
  5. All rights reserved.
  6. The contents of this file are subject to the "Toolbar2000 License"; you may
  7. not use or distribute this file except in compliance with the
  8. "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
  9. TB2k-LICENSE.txt or at:
  10. http://www.jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
  11. Alternatively, the contents of this file may be used under the terms of the
  12. GNU General Public License (the "GPL"), in which case the provisions of the
  13. GPL are applicable instead of those in the "Toolbar2000 License". A copy of
  14. the GPL may be found in GPL-LICENSE.txt or at:
  15. http://www.jrsoftware.org/files/tb2k/GPL-LICENSE.txt
  16. If you wish to allow use of your version of this file only under the terms of
  17. the GPL and not to allow others to use your version of this file under the
  18. "Toolbar2000 License", indicate your decision by deleting the provisions
  19. above and replace them with the notice and other provisions required by the
  20. GPL. If you do not delete the provisions above, a recipient may use your
  21. version of this file under either the "Toolbar2000 License" or the GPL.
  22. $jrsoftware: tb2k/Source/TB2Item.pas,v 1.277 2005/06/23 21:55:44 jr Exp $
  23. }
  24. interface
  25. {$I TB2Ver.inc}
  26. {x$DEFINE TB2K_NO_ANIMATION}
  27. { Enabling the above define disables all menu animation. For debugging
  28. purpose only. }
  29. {x$DEFINE TB2K_USE_STRICT_O2K_MENU_STYLE}
  30. { Enabling the above define forces it to use clBtnFace for the menu color
  31. instead of clMenu, and disables the use of flat menu borders on Windows
  32. XP with themes enabled. }
  33. uses
  34. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  35. StdCtrls, CommCtrl, Menus, ActnList, ImgList, TB2Anim;
  36. const
  37. WM_TB2K_POPUPSHOWING = WM_USER + 554;
  38. { Parameter in LParam of WM_TB2K_POPUPSHOWING }
  39. TPS_ANIMSTART = 1; // animation query: if Result <> 0, do not animate!
  40. TPS_ANIMFINISHED = 2; // only fired when animation thread is done
  41. TPS_NOANIM = 3; // fired when animation is done, or if showing with no animation
  42. type
  43. TTBCustomItem = class;
  44. TTBCustomItemClass = class of TTBCustomItem;
  45. TTBCustomItemActionLink = class;
  46. TTBCustomItemActionLinkClass = class of TTBCustomItemActionLink;
  47. TTBItemViewer = class;
  48. TTBItemViewerClass = class of TTBItemViewer;
  49. TTBPopupWindow = class;
  50. TTBPopupWindowClass = class of TTBPopupWindow;
  51. TTBView = class;
  52. TTBDoneAction = (tbdaNone, tbdaCancel, tbdaClickItem, tbdaOpenSystemMenu,
  53. tbdaHelpContext);
  54. PTBDoneActionData = ^TTBDoneActionData;
  55. TTBDoneActionData = record
  56. DoneAction: TTBDoneAction;
  57. case TTBDoneAction of
  58. tbdaClickItem: (ClickItem: TTBCustomItem; Sound: Boolean);
  59. tbdaOpenSystemMenu: (Wnd: HWND; Key: Cardinal);
  60. tbdaHelpContext: (ContextID: Integer);
  61. end;
  62. TTBInsertItemProc = procedure(AParent: TComponent; AItem: TTBCustomItem) of object;
  63. TTBItemChangedAction = (tbicInserted, tbicDeleting, tbicSubitemsChanged,
  64. tbicSubitemsBeginUpdate, tbicSubitemsEndUpdate, tbicInvalidate,
  65. tbicInvalidateAndResize, tbicRecreateItemViewers, tbicNameChanged,
  66. tbicSubMenuImagesChanged);
  67. TTBItemChangedProc = procedure(Sender: TTBCustomItem; Relayed: Boolean;
  68. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem) of object;
  69. TTBItemData = record
  70. Item: TTBCustomItem;
  71. end;
  72. PTBItemDataArray = ^TTBItemDataArray;
  73. TTBItemDataArray = array[0..$7FFFFFFF div SizeOf(TTBItemData)-1] of TTBItemData;
  74. TTBItemDisplayMode = (nbdmDefault, nbdmTextOnly, nbdmTextOnlyInMenus, nbdmImageAndText);
  75. TTBItemOption = (tboDefault, tboDropdownArrow, tboImageAboveCaption,
  76. tboLongHintInMenuOnly, tboNoAutoHint, tboNoRotation, tboSameWidth,
  77. tboShowHint, tboToolbarStyle, tboToolbarSize);
  78. TTBItemOptions = set of TTBItemOption;
  79. TTBItemStyle = set of (tbisSubmenu, tbisSelectable, tbisSeparator,
  80. tbisEmbeddedGroup, tbisClicksTransparent, tbisCombo, tbisNoAutoOpen,
  81. tbisSubitemsEditable, tbisNoLineBreak, tbisRightAlign, tbisDontSelectFirst,
  82. tbisRedrawOnSelChange, tbisRedrawOnMouseOverChange, tbisStretch);
  83. TTBPopupAlignment = (tbpaLeft, tbpaRight, tbpaCenter);
  84. TTBPopupEvent = procedure(Sender: TTBCustomItem; FromLink: Boolean) of object;
  85. TTBSelectEvent = procedure(Sender: TTBCustomItem; Viewer: TTBItemViewer;
  86. Selecting: Boolean) of object;
  87. ETBItemError = class(Exception);
  88. TTBImageChangeLink = class(TChangeLink)
  89. private
  90. FLastWidth, FLastHeight: Integer;
  91. end;
  92. {$IFNDEF JR_D5}
  93. TImageIndex = type Integer;
  94. {$ENDIF}
  95. TTBPopupPositionRec = record
  96. PositionAsSubmenu: Boolean;
  97. Alignment: TTBPopupAlignment;
  98. Opposite: Boolean;
  99. MonitorRect: TRect;
  100. ParentItemRect: TRect;
  101. NCSizeX: Integer;
  102. NCSizeY: Integer;
  103. X, Y, W, H: Integer;
  104. AnimDir: TTBAnimationDirection;
  105. PlaySound: Boolean;
  106. end;
  107. TTBCustomItem = class(TComponent)
  108. private
  109. FActionLink: TTBCustomItemActionLink;
  110. FAutoCheck: Boolean;
  111. FCaption: String;
  112. FChecked: Boolean;
  113. FDisplayMode: TTBItemDisplayMode;
  114. FEnabled: Boolean;
  115. FEffectiveOptions: TTBItemOptions;
  116. FGroupIndex: Integer;
  117. FHelpContext: THelpContext;
  118. FHint: String;
  119. FImageIndex: TImageIndex;
  120. FImages: TCustomImageList;
  121. FImagesChangeLink: TTBImageChangeLink;
  122. FItems: PTBItemDataArray;
  123. FItemCount: Integer;
  124. FItemStyle: TTBItemStyle;
  125. FLinkParents: TList;
  126. FMaskOptions: TTBItemOptions;
  127. FOptions: TTBItemOptions;
  128. FInheritOptions: Boolean;
  129. FNotifyList: TList;
  130. FOnClick: TNotifyEvent;
  131. FOnPopup: TTBPopupEvent;
  132. FOnSelect: TTBSelectEvent;
  133. FParent: TTBCustomItem;
  134. FParentComponent: TComponent;
  135. FRadioItem: Boolean;
  136. FShortCut: TShortCut;
  137. FSubMenuImages: TCustomImageList;
  138. FSubMenuImagesChangeLink: TTBImageChangeLink;
  139. FLinkSubitems: TTBCustomItem;
  140. FVisible: Boolean;
  141. procedure DoActionChange(Sender: TObject);
  142. function ChangeImages(var AImages: TCustomImageList;
  143. const Value: TCustomImageList; var AChangeLink: TTBImageChangeLink): Boolean;
  144. class procedure ClickWndProc(var Message: TMessage);
  145. function FindItemWithShortCut(AShortCut: TShortCut;
  146. var ATopmostParent: TTBCustomItem): TTBCustomItem;
  147. function FixOptions(const AOptions: TTBItemOptions): TTBItemOptions;
  148. function GetAction: TBasicAction;
  149. function GetItem(Index: Integer): TTBCustomItem;
  150. procedure ImageListChangeHandler(Sender: TObject);
  151. procedure InternalNotify(Ancestor: TTBCustomItem; NestingLevel: Integer;
  152. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  153. {$IFDEF JR_D6}
  154. function IsAutoCheckStored: Boolean;
  155. {$ENDIF}
  156. function IsCaptionStored: Boolean;
  157. function IsCheckedStored: Boolean;
  158. function IsEnabledStored: Boolean;
  159. function IsHelpContextStored: Boolean;
  160. function IsHintStored: Boolean;
  161. function IsImageIndexStored: Boolean;
  162. function IsOnClickStored: Boolean;
  163. function IsShortCutStored: Boolean;
  164. function IsVisibleStored: Boolean;
  165. procedure Notify(Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  166. procedure RefreshOptions;
  167. procedure SetAction(Value: TBasicAction);
  168. procedure SetCaption(Value: String);
  169. procedure SetChecked(Value: Boolean);
  170. procedure SetDisplayMode(Value: TTBItemDisplayMode);
  171. procedure SetEnabled(Value: Boolean);
  172. procedure SetGroupIndex(Value: Integer);
  173. procedure SetImageIndex(Value: TImageIndex);
  174. procedure SetImages(Value: TCustomImageList);
  175. procedure SetInheritOptions(Value: Boolean);
  176. procedure SetLinkSubitems(Value: TTBCustomItem);
  177. procedure SetMaskOptions(Value: TTBItemOptions);
  178. procedure SetOptions(Value: TTBItemOptions);
  179. procedure SetRadioItem(Value: Boolean);
  180. procedure SetSubMenuImages(Value: TCustomImageList);
  181. procedure SetVisible(Value: Boolean);
  182. procedure SubMenuImagesChanged;
  183. procedure TurnSiblingsOff;
  184. protected
  185. procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); dynamic;
  186. procedure Change(NeedResize: Boolean); virtual;
  187. function CreatePopup(const ParentView: TTBView; const ParentViewer: TTBItemViewer;
  188. const PositionAsSubmenu, SelectFirstItem, Customizing: Boolean;
  189. const APopupPoint: TPoint; const Alignment: TTBPopupAlignment): TTBPopupWindow; virtual;
  190. procedure DoPopup(Sender: TTBCustomItem; FromLink: Boolean); virtual;
  191. procedure EnabledChanged; virtual;
  192. function GetActionLinkClass: TTBCustomItemActionLinkClass; dynamic;
  193. function GetChevronParentView: TTBView; virtual;
  194. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  195. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; virtual;
  196. procedure GetPopupPosition(ParentView: TTBView;
  197. PopupWindow: TTBPopupWindow; var PopupPositionRec: TTBPopupPositionRec); virtual;
  198. function GetPopupWindowClass: TTBPopupWindowClass; virtual;
  199. procedure IndexError;
  200. procedure Loaded; override;
  201. function NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean; virtual;
  202. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  203. function OpenPopup(const SelectFirstItem, TrackRightButton: Boolean;
  204. const PopupPoint: TPoint; const Alignment: TTBPopupAlignment;
  205. const ReturnClickedItemOnly: Boolean): TTBCustomItem;
  206. procedure RecreateItemViewers;
  207. procedure SetChildOrder(Child: TComponent; Order: Integer); override;
  208. procedure SetName(const NewName: TComponentName); override;
  209. procedure SetParentComponent(Value: TComponent); override;
  210. property ActionLink: TTBCustomItemActionLink read FActionLink write FActionLink;
  211. property ItemStyle: TTBItemStyle read FItemStyle write FItemStyle;
  212. public
  213. constructor Create(AOwner: TComponent); override;
  214. destructor Destroy; override;
  215. function HasParent: Boolean; override;
  216. function GetParentComponent: TComponent; override;
  217. procedure Add(AItem: TTBCustomItem);
  218. procedure Clear;
  219. procedure Click; virtual;
  220. function ContainsItem(AItem: TTBCustomItem): Boolean;
  221. procedure Delete(Index: Integer);
  222. function GetShortCutText: String;
  223. function IndexOf(AItem: TTBCustomItem): Integer;
  224. procedure InitiateAction; virtual;
  225. procedure Insert(NewIndex: Integer; AItem: TTBCustomItem);
  226. function IsShortCut(var Message: TWMKey): Boolean;
  227. procedure Move(CurIndex, NewIndex: Integer);
  228. function Popup(X, Y: Integer; TrackRightButton: Boolean;
  229. Alignment: TTBPopupAlignment = tbpaLeft;
  230. ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
  231. procedure PostClick;
  232. procedure RegisterNotification(ANotify: TTBItemChangedProc);
  233. procedure Remove(Item: TTBCustomItem);
  234. procedure UnregisterNotification(ANotify: TTBItemChangedProc);
  235. procedure ViewBeginUpdate;
  236. procedure ViewEndUpdate;
  237. property Action: TBasicAction read GetAction write SetAction;
  238. property AutoCheck: Boolean read FAutoCheck write FAutoCheck {$IFDEF JR_D6} stored IsAutoCheckStored {$ENDIF} default False;
  239. property Caption: String read FCaption write SetCaption stored IsCaptionStored;
  240. property Count: Integer read FItemCount;
  241. property Checked: Boolean read FChecked write SetChecked stored IsCheckedStored default False;
  242. property DisplayMode: TTBItemDisplayMode read FDisplayMode write SetDisplayMode default nbdmDefault;
  243. property EffectiveOptions: TTBItemOptions read FEffectiveOptions;
  244. property Enabled: Boolean read FEnabled write SetEnabled stored IsEnabledStored default True;
  245. property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
  246. property HelpContext: THelpContext read FHelpContext write FHelpContext stored IsHelpContextStored default 0;
  247. property Hint: String read FHint write FHint stored IsHintStored;
  248. property ImageIndex: TImageIndex read FImageIndex write SetImageIndex stored IsImageIndexStored default -1;
  249. property Images: TCustomImageList read FImages write SetImages;
  250. property InheritOptions: Boolean read FInheritOptions write SetInheritOptions default True;
  251. property Items[Index: Integer]: TTBCustomItem read GetItem; default;
  252. property LinkSubitems: TTBCustomItem read FLinkSubitems write SetLinkSubitems;
  253. property MaskOptions: TTBItemOptions read FMaskOptions write SetMaskOptions default [];
  254. property Options: TTBItemOptions read FOptions write SetOptions default [];
  255. property Parent: TTBCustomItem read FParent;
  256. property ParentComponent: TComponent read FParentComponent write FParentComponent;
  257. property RadioItem: Boolean read FRadioItem write SetRadioItem default False;
  258. property ShortCut: TShortCut read FShortCut write FShortCut stored IsShortCutStored default 0;
  259. property SubMenuImages: TCustomImageList read FSubMenuImages write SetSubMenuImages;
  260. property Visible: Boolean read FVisible write SetVisible stored IsVisibleStored default True;
  261. property OnClick: TNotifyEvent read FOnClick write FOnClick stored IsOnClickStored;
  262. property OnPopup: TTBPopupEvent read FOnPopup write FOnPopup;
  263. property OnSelect: TTBSelectEvent read FOnSelect write FOnSelect;
  264. end;
  265. TTBCustomItemActionLink = class(TActionLink)
  266. protected
  267. FClient: TTBCustomItem;
  268. procedure AssignClient(AClient: TObject); override;
  269. {$IFDEF JR_D6}
  270. function IsAutoCheckLinked: Boolean; virtual;
  271. {$ENDIF}
  272. function IsCaptionLinked: Boolean; override;
  273. function IsCheckedLinked: Boolean; override;
  274. function IsEnabledLinked: Boolean; override;
  275. function IsHelpContextLinked: Boolean; override;
  276. function IsHintLinked: Boolean; override;
  277. function IsImageIndexLinked: Boolean; override;
  278. function IsShortCutLinked: Boolean; override;
  279. function IsVisibleLinked: Boolean; override;
  280. function IsOnExecuteLinked: Boolean; override;
  281. {$IFDEF JR_D6}
  282. procedure SetAutoCheck(Value: Boolean); override;
  283. {$ENDIF}
  284. procedure SetCaption(const Value: String); override;
  285. procedure SetChecked(Value: Boolean); override;
  286. procedure SetEnabled(Value: Boolean); override;
  287. procedure SetHelpContext(Value: THelpContext); override;
  288. procedure SetHint(const Value: String); override;
  289. procedure SetImageIndex(Value: Integer); override;
  290. procedure SetShortCut(Value: TShortCut); override;
  291. procedure SetVisible(Value: Boolean); override;
  292. procedure SetOnExecute(Value: TNotifyEvent); override;
  293. end;
  294. TTBBaseAccObject = class(TInterfacedObject, IDispatch)
  295. public
  296. procedure ClientIsDestroying; virtual; abstract;
  297. { IDispatch }
  298. function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  299. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  300. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  301. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  302. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  303. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  304. end;
  305. TTBItemViewer = class
  306. private
  307. FBoundsRect: TRect;
  308. FClipped: Boolean;
  309. FGroupLevel: Integer;
  310. FItem: TTBCustomItem;
  311. FOffEdge: Boolean;
  312. FShow: Boolean;
  313. FView: TTBView;
  314. procedure AccSelect(const AExecute: Boolean);
  315. function GetIndex: Integer;
  316. protected
  317. FAccObjectInstance: TTBBaseAccObject;
  318. procedure CalcSize(const Canvas: TCanvas; var AWidth, AHeight: Integer);
  319. virtual;
  320. function CaptionShown: Boolean; dynamic;
  321. function DoExecute: Boolean; virtual;
  322. procedure DrawItemCaption(const Canvas: TCanvas; ARect: TRect;
  323. const ACaption: String; ADrawDisabledShadow: Boolean; AFormat: UINT); virtual;
  324. procedure Entering(OldSelected: TTBItemViewer); virtual;
  325. function GetAccRole: Integer; virtual;
  326. function GetAccValue(var Value: WideString): Boolean; virtual;
  327. function GetCaptionText: String; virtual;
  328. procedure GetCursor(const Pt: TPoint; var ACursor: HCURSOR); virtual;
  329. function GetImageList: TCustomImageList;
  330. function ImageShown: Boolean;
  331. function IsRotated: Boolean;
  332. function IsToolbarSize: Boolean; virtual;
  333. function IsPtInButtonPart(X, Y: Integer): Boolean; virtual;
  334. procedure KeyDown(var Key: Word; Shift: TShiftState); virtual;
  335. procedure Leaving; virtual;
  336. procedure LosingCapture; virtual;
  337. procedure MouseDown(Shift: TShiftState; X, Y: Integer;
  338. var MouseDownOnMenu: Boolean); virtual;
  339. procedure MouseMove(X, Y: Integer); virtual;
  340. procedure MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean); virtual;
  341. procedure MouseWheel(WheelDelta: Integer; X, Y: Integer); virtual;
  342. procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
  343. IsSelected, IsPushed, UseDisabledShadow: Boolean); virtual;
  344. procedure PostAccSelect(const AExecute: Boolean);
  345. function UsesSameWidth: Boolean; virtual;
  346. public
  347. State: set of (tbisInvalidated, tbisLineSep);
  348. property BoundsRect: TRect read FBoundsRect;
  349. property Clipped: Boolean read FClipped;
  350. property Index: Integer read GetIndex;
  351. property Item: TTBCustomItem read FItem;
  352. property OffEdge: Boolean read FOffEdge;
  353. property Show: Boolean read FShow;
  354. property View: TTBView read FView;
  355. constructor Create(AView: TTBView; AItem: TTBCustomItem; AGroupLevel: Integer); virtual;
  356. destructor Destroy; override;
  357. procedure Execute(AGivePriority: Boolean);
  358. function GetAccObject: IDispatch;
  359. function GetHintText: String;
  360. function IsAccessible: Boolean;
  361. function IsToolbarStyle: Boolean; virtual;
  362. function ScreenToClient(const P: TPoint): TPoint;
  363. end;
  364. PTBItemViewerArray = ^TTBItemViewerArray;
  365. TTBItemViewerArray = array[0..$7FFFFFFF div SizeOf(TTBItemViewer)-1] of TTBItemViewer;
  366. TTBViewOrientation = (tbvoHorizontal, tbvoVertical, tbvoFloating);
  367. TTBEnterToolbarLoopOptions = set of (tbetMouseDown, tbetExecuteSelected,
  368. tbetFromMSAA);
  369. TTBViewState = set of (vsModal, vsMouseInWindow, vsDrawInOrder, vsOppositePopup,
  370. vsIgnoreFirstMouseUp, vsShowAccels, vsDropDownMenus, vsNoAnimation);
  371. TTBViewStyle = set of (vsMenuBar, vsUseHiddenAccels, vsAlwaysShowHints);
  372. TTBViewTimerID = (tiOpen, tiClose, tiScrollUp, tiScrollDown);
  373. TTBViewClass = class of TTBView;
  374. TTBView = class(TComponent)
  375. private
  376. FActiveTimers: set of TTBViewTimerID;
  377. FBackgroundColor: TColor;
  378. FBaseSize: TPoint;
  379. FCapture: Boolean;
  380. FCaptureWnd: HWND;
  381. FChevronOffset: Integer;
  382. FChevronParentView: TTBView;
  383. FChevronSize: Integer;
  384. FCurParentItem: TTBCustomItem;
  385. FCustomizing: Boolean;
  386. FDoneActionData: TTBDoneActionData;
  387. FInternalViewersAtEnd: Integer;
  388. FInternalViewersAtFront: Integer;
  389. FIsPopup: Boolean;
  390. FIsToolbar: Boolean;
  391. FMaxHeight: Integer;
  392. FMonitorRect: TRect;
  393. FMouseOverSelected: Boolean;
  394. FNewViewersGetHighestPriority: Boolean;
  395. FOpenViewer: TTBItemViewer;
  396. FOpenViewerView: TTBView;
  397. FOpenViewerWindow: TTBPopupWindow;
  398. FParentView: TTBView;
  399. FParentItem: TTBCustomItem;
  400. FPriorityList: TList;
  401. FOrientation: TTBViewOrientation;
  402. FScrollOffset: Integer;
  403. FSelected: TTBItemViewer;
  404. FSelectedViaMouse: Boolean;
  405. FShowDownArrow: Boolean;
  406. FShowUpArrow: Boolean;
  407. FState: TTBViewState;
  408. FStyle: TTBViewStyle;
  409. FUpdating: Integer;
  410. FUsePriorityList: Boolean;
  411. FValidated: Boolean;
  412. FViewerCount: Integer;
  413. FViewers: PTBItemViewerArray;
  414. FWindow: TWinControl;
  415. FWrapOffset: Integer;
  416. procedure DeletingViewer(Viewer: TTBItemViewer);
  417. procedure DrawItem(Viewer: TTBItemViewer; DrawTo: TCanvas; Offscreen: Boolean);
  418. procedure FreeViewers;
  419. procedure ImagesChanged;
  420. function InsertItemViewers(const NewIndex: Integer;
  421. const AItem: TTBCustomItem; const AGroupLevel: Integer;
  422. const AddToPriorityList, TopOfPriorityList: Boolean): Integer;
  423. procedure ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
  424. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  425. procedure LinkNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
  426. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  427. procedure RecreateItemViewer(const I: Integer);
  428. procedure Scroll(ADown: Boolean);
  429. procedure SetCustomizing(Value: Boolean);
  430. procedure SetSelected(Value: TTBItemViewer);
  431. procedure SetUsePriorityList(Value: Boolean);
  432. procedure StartTimer(const ATimer: TTBViewTimerID; const Interval: Integer);
  433. procedure StopAllTimers;
  434. procedure StopTimer(const ATimer: TTBViewTimerID);
  435. procedure UpdateCurParentItem;
  436. protected
  437. FAccObjectInstance: TTBBaseAccObject;
  438. procedure AutoSize(AWidth, AHeight: Integer); virtual;
  439. function CalculatePositions(const CanMoveControls: Boolean;
  440. const AOrientation: TTBViewOrientation;
  441. AWrapOffset, AChevronOffset, AChevronSize: Integer;
  442. var ABaseSize, TotalSize: TPoint;
  443. var AWrappedLines: Integer): Boolean;
  444. procedure DoUpdatePositions(var ASize: TPoint); virtual;
  445. function GetChevronItem: TTBCustomItem; virtual;
  446. procedure GetMargins(AOrientation: TTBViewOrientation; var Margins: TRect);
  447. virtual;
  448. function GetMDIButtonsItem: TTBCustomItem; virtual;
  449. function GetMDISystemMenuItem: TTBCustomItem; virtual;
  450. function GetParentToolbarView: TTBView;
  451. function GetRootView: TTBView;
  452. function HandleWMGetObject(var Message: TMessage): Boolean;
  453. procedure InitiateActions;
  454. procedure KeyDown(var Key: Word; Shift: TShiftState); virtual;
  455. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  456. procedure SetAccelsVisibility(AShowAccels: Boolean);
  457. procedure SetState(AState: TTBViewState);
  458. property DoneActionData: TTBDoneActionData read FDoneActionData write FDoneActionData;
  459. property ShowDownArrow: Boolean read FShowDownArrow; {vb+}
  460. property ShowUpArrow: Boolean read FShowUpArrow; {vb+}
  461. public
  462. constructor CreateView(AOwner: TComponent; AParentView: TTBView;
  463. AParentItem: TTBCustomItem; AWindow: TWinControl;
  464. AIsToolbar, ACustomizing, AUsePriorityList: Boolean); virtual;
  465. destructor Destroy; override;
  466. procedure BeginUpdate;
  467. procedure CancelCapture;
  468. procedure CancelChildPopups;
  469. procedure CancelMode;
  470. procedure CloseChildPopups;
  471. function ContainsView(AView: TTBView): Boolean;
  472. procedure DrawSubitems(ACanvas: TCanvas);
  473. procedure EndModal;
  474. procedure EndModalWithClick(AViewer: TTBItemViewer);
  475. procedure EndModalWithHelp(AContextID: Integer);
  476. procedure EndModalWithSystemMenu(AWnd: HWND; AKey: Cardinal);
  477. procedure EndUpdate;
  478. procedure EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions);
  479. procedure ExecuteSelected(AGivePriority: Boolean);
  480. function Find(Item: TTBCustomItem): TTBItemViewer;
  481. function FirstSelectable: TTBItemViewer;
  482. function GetAccObject: IDispatch;
  483. function GetCaptureWnd: HWND;
  484. function GetFont: TFont; virtual;
  485. procedure GetOffEdgeControlList(const List: TList);
  486. procedure GivePriority(AViewer: TTBItemViewer);
  487. function HighestPriorityViewer: TTBItemViewer;
  488. procedure Invalidate(AViewer: TTBItemViewer);
  489. procedure InvalidatePositions; virtual;
  490. function IndexOf(AViewer: TTBItemViewer): Integer;
  491. function IsModalEnding: Boolean;
  492. function NextSelectable(CurViewer: TTBItemViewer; GoForward: Boolean): TTBItemViewer;
  493. function NextSelectableWithAccel(CurViewer: TTBItemViewer; Key: Char;
  494. RequirePrimaryAccel: Boolean; var IsOnlyItemWithAccel: Boolean): TTBItemViewer;
  495. procedure NotifyFocusEvent;
  496. function OpenChildPopup(const SelectFirstItem: Boolean): Boolean;
  497. procedure RecreateAllViewers;
  498. procedure ScrollSelectedIntoView;
  499. procedure Select(Value: TTBItemViewer; ViaMouse: Boolean);
  500. procedure SetCapture;
  501. procedure TryValidatePositions;
  502. procedure UpdateSelection(const P: PPoint; const AllowNewSelection: Boolean);
  503. function UpdatePositions: TPoint;
  504. procedure ValidatePositions;
  505. function ViewerFromPoint(const P: TPoint): TTBItemViewer;
  506. property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor;
  507. property BaseSize: TPoint read FBaseSize;
  508. property Capture: Boolean read FCapture;
  509. property ChevronOffset: Integer read FChevronOffset write FChevronOffset;
  510. property ChevronSize: Integer read FChevronSize write FChevronSize;
  511. property Customizing: Boolean read FCustomizing write SetCustomizing;
  512. property IsPopup: Boolean read FIsPopup;
  513. property IsToolbar: Boolean read FIsToolbar;
  514. property MouseOverSelected: Boolean read FMouseOverSelected;
  515. property NewViewersGetHighestPriority: Boolean read FNewViewersGetHighestPriority
  516. write FNewViewersGetHighestPriority;
  517. property ParentView: TTBView read FParentView;
  518. property ParentItem: TTBCustomItem read FParentItem;
  519. property OpenViewer: TTBItemViewer read FOpenViewer;
  520. property OpenViewerView: TTBView read FOpenViewerView;
  521. property Orientation: TTBViewOrientation read FOrientation write FOrientation;
  522. property Selected: TTBItemViewer read FSelected write SetSelected;
  523. property SelectedViaMouse: Boolean read FSelectedViaMouse;
  524. property State: TTBViewState read FState;
  525. property Style: TTBViewStyle read FStyle write FStyle;
  526. property UsePriorityList: Boolean read FUsePriorityList write SetUsePriorityList;
  527. property Viewers: PTBItemViewerArray read FViewers;
  528. property ViewerCount: Integer read FViewerCount;
  529. property Window: TWinControl read FWindow;
  530. property WrapOffset: Integer read FWrapOffset write FWrapOffset;
  531. end;
  532. TTBRootItemClass = class of TTBRootItem;
  533. TTBRootItem = class(TTBCustomItem);
  534. { same as TTBCustomItem, except there's a property editor for it }
  535. TTBItem = class(TTBCustomItem)
  536. published
  537. property Action;
  538. property AutoCheck;
  539. property Caption;
  540. property Checked;
  541. property DisplayMode;
  542. property Enabled;
  543. property GroupIndex;
  544. property HelpContext;
  545. property Hint;
  546. property ImageIndex;
  547. property Images;
  548. property InheritOptions;
  549. property MaskOptions;
  550. property Options;
  551. property RadioItem;
  552. property ShortCut;
  553. property Visible;
  554. property OnClick;
  555. property OnSelect;
  556. end;
  557. TTBGroupItem = class(TTBCustomItem)
  558. public
  559. constructor Create(AOwner: TComponent); override;
  560. published
  561. property InheritOptions;
  562. property LinkSubitems;
  563. property MaskOptions;
  564. property Options;
  565. end;
  566. TTBSubmenuItem = class(TTBCustomItem)
  567. private
  568. function GetDropdownCombo: Boolean;
  569. procedure SetDropdownCombo(Value: Boolean);
  570. public
  571. constructor Create(AOwner: TComponent); override;
  572. published
  573. property Action;
  574. property AutoCheck;
  575. property Caption;
  576. property Checked;
  577. //property DisplayAsToolbar;
  578. property DisplayMode;
  579. property DropdownCombo: Boolean read GetDropdownCombo write SetDropdownCombo default False;
  580. property Enabled;
  581. property GroupIndex;
  582. property HelpContext;
  583. property Hint;
  584. property ImageIndex;
  585. property Images;
  586. property InheritOptions;
  587. property LinkSubitems;
  588. property MaskOptions;
  589. property Options;
  590. property RadioItem;
  591. property ShortCut;
  592. property SubMenuImages;
  593. property Visible;
  594. property OnClick;
  595. property OnPopup;
  596. property OnSelect;
  597. end;
  598. TTBSeparatorItem = class(TTBCustomItem)
  599. private
  600. FBlank: Boolean;
  601. procedure SetBlank(Value: Boolean);
  602. protected
  603. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
  604. public
  605. constructor Create(AOwner: TComponent); override;
  606. published
  607. property Blank: Boolean read FBlank write SetBlank default False;
  608. property Hint;
  609. property Visible;
  610. end;
  611. TTBSeparatorItemViewer = class(TTBItemViewer)
  612. protected
  613. procedure CalcSize(const Canvas: TCanvas;
  614. var AWidth, AHeight: Integer); override;
  615. procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
  616. IsSelected, IsPushed, UseDisabledShadow: Boolean); override;
  617. function UsesSameWidth: Boolean; override;
  618. end;
  619. TTBControlItem = class(TTBCustomItem)
  620. private
  621. FControl: TControl;
  622. FDontFreeControl: Boolean;
  623. procedure SetControl(Value: TControl);
  624. protected
  625. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  626. public
  627. constructor Create(AOwner: TComponent); override;
  628. constructor CreateControlItem(AOwner: TComponent; AControl: TControl);
  629. destructor Destroy; override;
  630. property DontFreeControl: Boolean read FDontFreeControl write FDontFreeControl;
  631. published
  632. property Control: TControl read FControl write SetControl;
  633. end;
  634. TTBPopupView = class(TTBView)
  635. protected
  636. procedure AutoSize(AWidth, AHeight: Integer); override;
  637. public
  638. function GetFont: TFont; override;
  639. end;
  640. ITBPopupWindow = interface
  641. ['{E45CBE74-1ECF-44CB-B064-6D45B1924708}']
  642. end;
  643. TTBPopupWindow = class(TCustomControl, ITBPopupWindow)
  644. private
  645. FAccelsVisibilitySet: Boolean;
  646. FAnimationDirection: TTBAnimationDirection;
  647. FView: TTBView;
  648. procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
  649. procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  650. procedure WMClose(var Message: TWMClose); message WM_CLOSE;
  651. procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  652. procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT;
  653. procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  654. procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  655. procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  656. procedure WMPrint(var Message: TMessage); message WM_PRINT;
  657. procedure WMPrintClient(var Message: TMessage); message WM_PRINTCLIENT;
  658. procedure WMTB2kStepAnimation(var Message: TMessage); message WM_TB2K_STEPANIMATION;
  659. procedure WMTB2kAnimationEnded (var Message: TMessage); message WM_TB2K_ANIMATIONENDED;
  660. protected
  661. procedure CreateParams(var Params: TCreateParams); override;
  662. procedure CreateWnd; override;
  663. procedure DestroyWindowHandle; override;
  664. function GetNCSize: TPoint; dynamic;
  665. function GetViewClass: TTBViewClass; dynamic;
  666. procedure Paint; override;
  667. procedure PaintScrollArrows; virtual;
  668. property AnimationDirection: TTBAnimationDirection read FAnimationDirection;
  669. public
  670. constructor CreatePopupWindow(AOwner: TComponent; const AParentView: TTBView;
  671. const AItem: TTBCustomItem; const ACustomizing: Boolean); virtual;
  672. destructor Destroy; override;
  673. procedure BeforeDestruction; override;
  674. property View: TTBView read FView;
  675. end;
  676. ITBItems = interface
  677. ['{A5C0D7CC-3EC4-4090-A0F8-3D03271877EA}']
  678. function GetItems: TTBCustomItem;
  679. end;
  680. TTBItemContainer = class(TComponent, ITBItems)
  681. private
  682. FItem: TTBRootItem;
  683. function GetImages: TCustomImageList;
  684. function GetItems: TTBCustomItem;
  685. procedure SetImages(Value: TCustomImageList);
  686. protected
  687. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  688. public
  689. constructor Create(AOwner: TComponent); override;
  690. destructor Destroy; override;
  691. property Items: TTBRootItem read FItem;
  692. published
  693. property Images: TCustomImageList read GetImages write SetImages;
  694. end;
  695. TTBPopupMenu = class(TPopupMenu, ITBItems)
  696. private
  697. FItem: TTBRootItem;
  698. //procedure SetItems(Value: TTBCustomItem);
  699. function GetImages: TCustomImageList;
  700. function GetItems: TTBCustomItem;
  701. function GetLinkSubitems: TTBCustomItem;
  702. function GetOptions: TTBItemOptions;
  703. procedure RootItemClick(Sender: TObject);
  704. procedure SetImages(Value: TCustomImageList);
  705. procedure SetLinkSubitems(Value: TTBCustomItem);
  706. procedure SetOptions(Value: TTBItemOptions);
  707. protected
  708. {$IFNDEF JR_D5}
  709. procedure DoPopup(Sender: TObject);
  710. {$ENDIF}
  711. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  712. function GetRootItemClass: TTBRootItemClass; dynamic;
  713. procedure SetChildOrder(Child: TComponent; Order: Integer); override;
  714. public
  715. constructor Create(AOwner: TComponent); override;
  716. destructor Destroy; override;
  717. function IsShortCut(var Message: TWMKey): Boolean; override;
  718. procedure Popup(X, Y: Integer); override;
  719. function PopupEx(X, Y: Integer; ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
  720. published
  721. property Images: TCustomImageList read GetImages write SetImages;
  722. property Items: TTBRootItem read FItem;
  723. property LinkSubitems: TTBCustomItem read GetLinkSubitems write SetLinkSubitems;
  724. property Options: TTBItemOptions read GetOptions write SetOptions default [];
  725. end;
  726. TTBCustomImageList = class(TImageList)
  727. private
  728. FCheckedImages: TCustomImageList;
  729. FCheckedImagesChangeLink: TChangeLink;
  730. FDisabledImages: TCustomImageList;
  731. FDisabledImagesChangeLink: TChangeLink;
  732. FHotImages: TCustomImageList;
  733. FHotImagesChangeLink: TChangeLink;
  734. FImagesBitmap: TBitmap;
  735. FImagesBitmapMaskColor: TColor;
  736. procedure ChangeImages(var AImageList: TCustomImageList;
  737. Value: TCustomImageList; AChangeLink: TChangeLink);
  738. procedure ImageListChanged(Sender: TObject);
  739. procedure ImagesBitmapChanged(Sender: TObject);
  740. procedure SetCheckedImages(Value: TCustomImageList);
  741. procedure SetDisabledImages(Value: TCustomImageList);
  742. procedure SetHotImages(Value: TCustomImageList);
  743. procedure SetImagesBitmap(Value: TBitmap);
  744. procedure SetImagesBitmapMaskColor(Value: TColor);
  745. protected
  746. procedure DefineProperties(Filer: TFiler); override;
  747. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  748. property CheckedImages: TCustomImageList read FCheckedImages write SetCheckedImages;
  749. property DisabledImages: TCustomImageList read FDisabledImages write SetDisabledImages;
  750. property HotImages: TCustomImageList read FHotImages write SetHotImages;
  751. property ImagesBitmap: TBitmap read FImagesBitmap write SetImagesBitmap;
  752. property ImagesBitmapMaskColor: TColor read FImagesBitmapMaskColor
  753. write SetImagesBitmapMaskColor default clFuchsia;
  754. public
  755. constructor Create(AOwner: TComponent); override;
  756. destructor Destroy; override;
  757. procedure DrawState(Canvas: TCanvas; X, Y, Index: Integer;
  758. Enabled, Selected, Checked: Boolean); virtual;
  759. end;
  760. TTBImageList = class(TTBCustomImageList)
  761. published
  762. property CheckedImages;
  763. property DisabledImages;
  764. property HotImages;
  765. property ImagesBitmap;
  766. property ImagesBitmapMaskColor;
  767. end;
  768. const
  769. {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
  770. tbMenuBkColor = clMenu;
  771. tbMenuTextColor = clMenuText;
  772. {$ELSE}
  773. tbMenuBkColor = clBtnFace;
  774. tbMenuTextColor = clBtnText;
  775. {$ENDIF}
  776. tbMenuVerticalMargin = 4;
  777. tbMenuImageTextSpace = 1;
  778. tbMenuLeftTextMargin = 2;
  779. tbMenuRightTextMargin = 3;
  780. tbMenuSeparatorOffset = 12;
  781. tbMenuScrollArrowHeight = 19;
  782. tbDropdownArrowWidth = 8;
  783. tbDropdownArrowMargin = 3;
  784. tbDropdownComboArrowWidth = 11;
  785. tbDropdownComboMargin = 2;
  786. tbLineSpacing = 6;
  787. tbLineSepOffset = 1;
  788. tbDockedLineSepOffset = 4;
  789. WM_TB2K_CLICKITEM = WM_USER + $100;
  790. procedure TBInitToolbarSystemFont;
  791. var
  792. ToolbarFont: TFont;
  793. type
  794. TTBModalHandler = class
  795. private
  796. FCreatedWnd: Boolean;
  797. FInited: Boolean;
  798. FWnd: HWND;
  799. FRootPopup: TTBPopupWindow;
  800. procedure WndProc(var Msg: TMessage);
  801. public
  802. constructor Create(AExistingWnd: HWND);
  803. destructor Destroy; override;
  804. procedure Loop(const RootView: TTBView; const AMouseDown, AExecuteSelected,
  805. AFromMSAA, TrackRightButton: Boolean);
  806. property RootPopup: TTBPopupWindow read FRootPopup write FRootPopup;
  807. property Wnd: HWND read FWnd;
  808. end;
  809. function ProcessDoneAction(const DoneActionData: TTBDoneActionData;
  810. const ReturnClickedItemOnly: Boolean): TTBCustomItem;
  811. implementation
  812. uses
  813. MMSYSTEM, TB2Consts, TB2Common, IMM, TB2Acc;
  814. var
  815. LastPos: TPoint;
  816. threadvar
  817. ClickWndRefCount: Integer;
  818. ClickWnd: HWND;
  819. ClickList: TList;
  820. type
  821. PItemChangedNotificationData = ^TItemChangedNotificationData;
  822. TItemChangedNotificationData = record
  823. Proc: TTBItemChangedProc;
  824. RefCount: Integer;
  825. end;
  826. TComponentAccess = class(TComponent);
  827. TControlAccess = class(TControl);
  828. const
  829. ViewTimerBaseID = 9000;
  830. MaxGroupLevel = 10;
  831. { Misc. }
  832. procedure DestroyClickWnd;
  833. begin
  834. if ClickWnd <> 0 then begin
  835. {$IFDEF JR_D6}Classes.{$ENDIF} DeallocateHWnd(ClickWnd);
  836. ClickWnd := 0;
  837. end;
  838. FreeAndNil(ClickList);
  839. end;
  840. procedure ReferenceClickWnd;
  841. begin
  842. Inc(ClickWndRefCount);
  843. end;
  844. procedure ReleaseClickWnd;
  845. begin
  846. Dec(ClickWndRefCount);
  847. if ClickWndRefCount = 0 then
  848. DestroyClickWnd;
  849. end;
  850. procedure QueueClick(const AItem: TObject; const AArg: Integer);
  851. { Adds an item to ClickList and posts a message to handle it. AItem must be
  852. either a TTBCustomItem or TTBItemViewer. }
  853. var
  854. I: Integer;
  855. begin
  856. if ClickWnd = 0 then
  857. ClickWnd := {$IFDEF JR_D6}Classes.{$ENDIF} AllocateHWnd(TTBCustomItem.ClickWndProc);
  858. if ClickList = nil then
  859. ClickList := TList.Create;
  860. { Add a new item to ClickList or replace an empty one }
  861. I := ClickList.IndexOf(nil);
  862. if I = -1 then
  863. I := ClickList.Add(AItem)
  864. else
  865. ClickList[I] := AItem;
  866. PostMessage(ClickWnd, WM_TB2K_CLICKITEM, AArg, I);
  867. end;
  868. procedure RemoveFromClickList(const AItem: TObject);
  869. { Any class that potentially calls QueueClick needs to call RemoveFromClickList
  870. before an instance is destroyed to ensure that any references to the
  871. instance still in ClickList are removed. }
  872. var
  873. I: Integer;
  874. begin
  875. if Assigned(ClickList) and Assigned(AItem) then
  876. for I := 0 to ClickList.Count-1 do
  877. if ClickList[I] = AItem then
  878. ClickList[I] := Pointer(1);
  879. { ^ The special value of Pointer(1) is assigned to the item instead of
  880. of nil because we want the index to stay reserved until the
  881. WM_TB2K_CLICKITEM message for the index is processed. We don't want
  882. the WM_TB2K_CLICKITEM message that's still in the queue to later
  883. refer to a different item; this would result in queued clicks being
  884. processed in the wrong order in a case like this:
  885. A.PostClick; B.PostClick; A.Free; C.PostClick;
  886. C's click would end up being processed before A's, because C would
  887. get A's index. }
  888. end;
  889. function ProcessDoneAction(const DoneActionData: TTBDoneActionData;
  890. const ReturnClickedItemOnly: Boolean): TTBCustomItem;
  891. begin
  892. Result := nil;
  893. case DoneActionData.DoneAction of
  894. tbdaNone: ;
  895. tbdaClickItem: begin
  896. if DoneActionData.Sound and NeedToPlaySound('MenuCommand') then
  897. PlaySound('MenuCommand', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
  898. Result := DoneActionData.ClickItem;
  899. if not ReturnClickedItemOnly then
  900. Result.PostClick;
  901. end;
  902. tbdaOpenSystemMenu: begin
  903. SendMessage(DoneActionData.Wnd, WM_SYSCOMMAND, SC_KEYMENU, DoneActionData.Key);
  904. end;
  905. tbdaHelpContext: begin
  906. { Based on code in TPopupList.WndProc: }
  907. if Assigned(Screen.ActiveForm) and
  908. (biHelp in Screen.ActiveForm.BorderIcons) then
  909. Application.HelpCommand(HELP_CONTEXTPOPUP, DoneActionData.ContextID)
  910. else
  911. Application.HelpContext(DoneActionData.ContextID);
  912. end;
  913. end;
  914. end;
  915. { TTBItemDataArray routines }
  916. procedure InsertIntoItemArray(var AItems: PTBItemDataArray;
  917. var AItemCount: Integer; NewIndex: Integer; AItem: TTBCustomItem);
  918. begin
  919. ReallocMem(AItems, (AItemCount+1) * SizeOf(AItems[0]));
  920. if NewIndex < AItemCount then
  921. System.Move(AItems[NewIndex], AItems[NewIndex+1],
  922. (AItemCount-NewIndex) * SizeOf(AItems[0]));
  923. AItems[NewIndex].Item := AItem;
  924. Inc(AItemCount);
  925. end;
  926. procedure DeleteFromItemArray(var AItems: PTBItemDataArray;
  927. var AItemCount: Integer; Index: Integer);
  928. begin
  929. Dec(AItemCount);
  930. if Index < AItemCount then
  931. System.Move(AItems[Index+1], AItems[Index],
  932. (AItemCount-Index) * SizeOf(AItems[0]));
  933. ReallocMem(AItems, AItemCount * SizeOf(AItems[0]));
  934. end;
  935. procedure InsertIntoViewerArray(var AItems: PTBItemViewerArray;
  936. var AItemCount: Integer; NewIndex: Integer; AItem: TTBItemViewer);
  937. begin
  938. ReallocMem(AItems, (AItemCount+1) * SizeOf(AItems[0]));
  939. if NewIndex < AItemCount then
  940. System.Move(AItems[NewIndex], AItems[NewIndex+1],
  941. (AItemCount-NewIndex) * SizeOf(AItems[0]));
  942. AItems[NewIndex] := AItem;
  943. Inc(AItemCount);
  944. end;
  945. procedure DeleteFromViewerArray(var AItems: PTBItemViewerArray;
  946. var AItemCount: Integer; Index: Integer);
  947. begin
  948. Dec(AItemCount);
  949. if Index < AItemCount then
  950. System.Move(AItems[Index+1], AItems[Index],
  951. (AItemCount-Index) * SizeOf(AItems[0]));
  952. ReallocMem(AItems, AItemCount * SizeOf(AItems[0]));
  953. end;
  954. { TTBCustomItemActionLink }
  955. procedure TTBCustomItemActionLink.AssignClient(AClient: TObject);
  956. begin
  957. FClient := AClient as TTBCustomItem;
  958. end;
  959. {$IFDEF JR_D6}
  960. function TTBCustomItemActionLink.IsAutoCheckLinked: Boolean;
  961. begin
  962. Result := (FClient.AutoCheck = (Action as TCustomAction).AutoCheck);
  963. end;
  964. {$ENDIF}
  965. function TTBCustomItemActionLink.IsCaptionLinked: Boolean;
  966. begin
  967. Result := inherited IsCaptionLinked and
  968. (FClient.Caption = (Action as TCustomAction).Caption);
  969. end;
  970. function TTBCustomItemActionLink.IsCheckedLinked: Boolean;
  971. begin
  972. Result := inherited IsCheckedLinked and
  973. (FClient.Checked = (Action as TCustomAction).Checked);
  974. end;
  975. function TTBCustomItemActionLink.IsEnabledLinked: Boolean;
  976. begin
  977. Result := inherited IsEnabledLinked and
  978. (FClient.Enabled = (Action as TCustomAction).Enabled);
  979. end;
  980. function TTBCustomItemActionLink.IsHelpContextLinked: Boolean;
  981. begin
  982. Result := inherited IsHelpContextLinked and
  983. (FClient.HelpContext = (Action as TCustomAction).HelpContext);
  984. end;
  985. function TTBCustomItemActionLink.IsHintLinked: Boolean;
  986. begin
  987. Result := inherited IsHintLinked and
  988. (FClient.Hint = (Action as TCustomAction).Hint);
  989. end;
  990. function TTBCustomItemActionLink.IsImageIndexLinked: Boolean;
  991. begin
  992. Result := inherited IsImageIndexLinked and
  993. (FClient.ImageIndex = (Action as TCustomAction).ImageIndex);
  994. end;
  995. function TTBCustomItemActionLink.IsShortCutLinked: Boolean;
  996. begin
  997. Result := inherited IsShortCutLinked and
  998. (FClient.ShortCut = (Action as TCustomAction).ShortCut);
  999. end;
  1000. function TTBCustomItemActionLink.IsVisibleLinked: Boolean;
  1001. begin
  1002. Result := inherited IsVisibleLinked and
  1003. (FClient.Visible = (Action as TCustomAction).Visible);
  1004. end;
  1005. function TTBCustomItemActionLink.IsOnExecuteLinked: Boolean;
  1006. begin
  1007. Result := inherited IsOnExecuteLinked and
  1008. MethodsEqual(TMethod(FClient.OnClick), TMethod(Action.OnExecute));
  1009. end;
  1010. {$IFDEF JR_D6}
  1011. procedure TTBCustomItemActionLink.SetAutoCheck(Value: Boolean);
  1012. begin
  1013. if IsAutoCheckLinked then FClient.AutoCheck := Value;
  1014. end;
  1015. {$ENDIF}
  1016. procedure TTBCustomItemActionLink.SetCaption(const Value: string);
  1017. begin
  1018. if IsCaptionLinked then FClient.Caption := Value;
  1019. end;
  1020. procedure TTBCustomItemActionLink.SetChecked(Value: Boolean);
  1021. begin
  1022. if IsCheckedLinked then FClient.Checked := Value;
  1023. end;
  1024. procedure TTBCustomItemActionLink.SetEnabled(Value: Boolean);
  1025. begin
  1026. if IsEnabledLinked then FClient.Enabled := Value;
  1027. end;
  1028. procedure TTBCustomItemActionLink.SetHelpContext(Value: THelpContext);
  1029. begin
  1030. if IsHelpContextLinked then FClient.HelpContext := Value;
  1031. end;
  1032. procedure TTBCustomItemActionLink.SetHint(const Value: string);
  1033. begin
  1034. if IsHintLinked then FClient.Hint := Value;
  1035. end;
  1036. procedure TTBCustomItemActionLink.SetImageIndex(Value: Integer);
  1037. begin
  1038. if IsImageIndexLinked then FClient.ImageIndex := Value;
  1039. end;
  1040. procedure TTBCustomItemActionLink.SetShortCut(Value: TShortCut);
  1041. begin
  1042. if IsShortCutLinked then FClient.ShortCut := Value;
  1043. end;
  1044. procedure TTBCustomItemActionLink.SetVisible(Value: Boolean);
  1045. begin
  1046. if IsVisibleLinked then FClient.Visible := Value;
  1047. end;
  1048. procedure TTBCustomItemActionLink.SetOnExecute(Value: TNotifyEvent);
  1049. begin
  1050. if IsOnExecuteLinked then FClient.OnClick := Value;
  1051. end;
  1052. { TTBCustomItem }
  1053. {}function ItemContainingItems(const AItem: TTBCustomItem): TTBCustomItem;
  1054. begin
  1055. if Assigned(AItem) and Assigned(AItem.FLinkSubitems) then
  1056. Result := AItem.FLinkSubitems
  1057. else
  1058. Result := AItem;
  1059. end;
  1060. constructor TTBCustomItem.Create(AOwner: TComponent);
  1061. begin
  1062. inherited;
  1063. FEnabled := True;
  1064. FImageIndex := -1;
  1065. FInheritOptions := True;
  1066. FItemStyle := [tbisSelectable, tbisRedrawOnSelChange, tbisRedrawOnMouseOverChange];
  1067. FVisible := True;
  1068. ReferenceClickWnd;
  1069. end;
  1070. destructor TTBCustomItem.Destroy;
  1071. var
  1072. I: Integer;
  1073. begin
  1074. Destroying;
  1075. RemoveFromClickList(Self);
  1076. { Changed in 0.33. Moved FParent.Remove call *after* the child items are
  1077. deleted. }
  1078. for I := Count-1 downto 0 do
  1079. Items[I].Free;
  1080. if Assigned(FParent) then
  1081. FParent.Remove(Self);
  1082. FreeMem(FItems);
  1083. FActionLink.Free;
  1084. FActionLink := nil;
  1085. FreeAndNil(FSubMenuImagesChangeLink);
  1086. FreeAndNil(FImagesChangeLink);
  1087. inherited;
  1088. if Assigned(FNotifyList) then begin
  1089. for I := FNotifyList.Count-1 downto 0 do
  1090. Dispose(PItemChangedNotificationData(FNotifyList[I]));
  1091. FNotifyList.Free;
  1092. end;
  1093. FLinkParents.Free;
  1094. ReleaseClickWnd;
  1095. end;
  1096. {$IFDEF JR_D6}
  1097. function TTBCustomItem.IsAutoCheckStored: Boolean;
  1098. begin
  1099. Result := (ActionLink = nil) or not FActionLink.IsAutoCheckLinked;
  1100. end;
  1101. {$ENDIF}
  1102. function TTBCustomItem.IsCaptionStored: Boolean;
  1103. begin
  1104. Result := (ActionLink = nil) or not FActionLink.IsCaptionLinked;
  1105. end;
  1106. function TTBCustomItem.IsCheckedStored: Boolean;
  1107. begin
  1108. Result := (ActionLink = nil) or not FActionLink.IsCheckedLinked;
  1109. end;
  1110. function TTBCustomItem.IsEnabledStored: Boolean;
  1111. begin
  1112. Result := (ActionLink = nil) or not FActionLink.IsEnabledLinked;
  1113. end;
  1114. function TTBCustomItem.IsHintStored: Boolean;
  1115. begin
  1116. Result := (ActionLink = nil) or not FActionLink.IsHintLinked;
  1117. end;
  1118. function TTBCustomItem.IsHelpContextStored: Boolean;
  1119. begin
  1120. Result := (ActionLink = nil) or not FActionLink.IsHelpContextLinked;
  1121. end;
  1122. function TTBCustomItem.IsImageIndexStored: Boolean;
  1123. begin
  1124. Result := (ActionLink = nil) or not FActionLink.IsImageIndexLinked;
  1125. end;
  1126. function TTBCustomItem.IsShortCutStored: Boolean;
  1127. begin
  1128. Result := (ActionLink = nil) or not FActionLink.IsShortCutLinked;
  1129. end;
  1130. function TTBCustomItem.IsVisibleStored: Boolean;
  1131. begin
  1132. Result := (ActionLink = nil) or not FActionLink.IsVisibleLinked;
  1133. end;
  1134. function TTBCustomItem.IsOnClickStored: Boolean;
  1135. begin
  1136. Result := (ActionLink = nil) or not FActionLink.IsOnExecuteLinked;
  1137. end;
  1138. function TTBCustomItem.GetAction: TBasicAction;
  1139. begin
  1140. if FActionLink <> nil then
  1141. Result := FActionLink.Action
  1142. else
  1143. Result := nil;
  1144. end;
  1145. function TTBCustomItem.GetActionLinkClass: TTBCustomItemActionLinkClass;
  1146. begin
  1147. Result := TTBCustomItemActionLink;
  1148. end;
  1149. procedure TTBCustomItem.DoActionChange(Sender: TObject);
  1150. begin
  1151. if Sender = Action then ActionChange(Sender, False);
  1152. end;
  1153. procedure TTBCustomItem.ActionChange(Sender: TObject; CheckDefaults: Boolean);
  1154. begin
  1155. if Action is TCustomAction then
  1156. with TCustomAction(Sender) do
  1157. begin
  1158. {$IFDEF JR_D6}
  1159. if not CheckDefaults or (Self.AutoCheck = False) then
  1160. Self.AutoCheck := AutoCheck;
  1161. {$ENDIF}
  1162. if not CheckDefaults or (Self.Caption = '') then
  1163. Self.Caption := Caption;
  1164. if not CheckDefaults or (Self.Checked = False) then
  1165. Self.Checked := Checked;
  1166. if not CheckDefaults or (Self.Enabled = True) then
  1167. Self.Enabled := Enabled;
  1168. if not CheckDefaults or (Self.HelpContext = 0) then
  1169. Self.HelpContext := HelpContext;
  1170. if not CheckDefaults or (Self.Hint = '') then
  1171. Self.Hint := Hint;
  1172. if not CheckDefaults or (Self.ImageIndex = -1) then
  1173. Self.ImageIndex := ImageIndex;
  1174. if not CheckDefaults or (Self.ShortCut = scNone) then
  1175. Self.ShortCut := ShortCut;
  1176. if not CheckDefaults or (Self.Visible = True) then
  1177. Self.Visible := Visible;
  1178. if not CheckDefaults or not Assigned(Self.OnClick) then
  1179. Self.OnClick := OnExecute;
  1180. end;
  1181. end;
  1182. procedure TTBCustomItem.SetAction(Value: TBasicAction);
  1183. begin
  1184. if Value = nil then begin
  1185. FActionLink.Free;
  1186. FActionLink := nil;
  1187. end
  1188. else begin
  1189. if FActionLink = nil then
  1190. FActionLink := GetActionLinkClass.Create(Self);
  1191. FActionLink.Action := Value;
  1192. FActionLink.OnChange := DoActionChange;
  1193. { Note: Delphi's Controls.pas and Menus.pas merely check for
  1194. "csLoading in Value.ComponentState" here. But that doesn't help when
  1195. the Action property references an action on another form / data module
  1196. that has already finished loading. So we check two things:
  1197. 1. csLoading in Value.ComponentState
  1198. 2. csLoading in ComponentState
  1199. In the typical case where the item and action list reside on the same
  1200. form, #1 and #2 are both true.
  1201. Only #1 is true when Action references an action on another form / data
  1202. module that is created *after* the item (e.g. if Form1.TBItem1.Action =
  1203. Form2.Action1, and Form1 is created before Form2).
  1204. Only #2 is true when Action references an action on another form / data
  1205. module that is created *before* the item (e.g. if Form2.TBItem1.Action =
  1206. Form1.Action1, and Form1 is created before Form2). }
  1207. ActionChange(Value, (csLoading in Value.ComponentState) or
  1208. (csLoading in ComponentState));
  1209. Value.FreeNotification(Self);
  1210. end;
  1211. end;
  1212. procedure TTBCustomItem.InitiateAction;
  1213. begin
  1214. if FActionLink <> nil then FActionLink.Update;
  1215. end;
  1216. procedure TTBCustomItem.Loaded;
  1217. begin
  1218. inherited;
  1219. if Action <> nil then ActionChange(Action, True);
  1220. end;
  1221. procedure TTBCustomItem.GetChildren(Proc: TGetChildProc; Root: TComponent);
  1222. var
  1223. I: Integer;
  1224. begin
  1225. for I := 0 to FItemCount-1 do
  1226. Proc(FItems[I].Item);
  1227. end;
  1228. procedure TTBCustomItem.SetChildOrder(Child: TComponent; Order: Integer);
  1229. var
  1230. I: Integer;
  1231. begin
  1232. I := IndexOf(Child as TTBCustomItem);
  1233. if I <> -1 then
  1234. Move(I, Order);
  1235. end;
  1236. function TTBCustomItem.HasParent: Boolean;
  1237. begin
  1238. Result := True;
  1239. end;
  1240. function TTBCustomItem.GetParentComponent: TComponent;
  1241. begin
  1242. if (FParent <> nil) and (FParent.FParentComponent <> nil) then
  1243. Result := FParent.FParentComponent
  1244. else
  1245. Result := FParent;
  1246. end;
  1247. procedure TTBCustomItem.SetName(const NewName: TComponentName);
  1248. begin
  1249. if Name <> NewName then begin
  1250. inherited;
  1251. if Assigned(FParent) then
  1252. FParent.Notify(tbicNameChanged, -1, Self);
  1253. end;
  1254. end;
  1255. procedure TTBCustomItem.SetParentComponent(Value: TComponent);
  1256. var
  1257. Intf: ITBItems;
  1258. begin
  1259. if FParent <> nil then FParent.Remove(Self);
  1260. if Value <> nil then begin
  1261. if Value is TTBCustomItem then
  1262. TTBCustomItem(Value).Add(Self)
  1263. else if Value.GetInterface(ITBItems, Intf) then
  1264. Intf.GetItems.Add(Self);
  1265. end;
  1266. end;
  1267. procedure TTBCustomItem.Notification(AComponent: TComponent;
  1268. Operation: TOperation);
  1269. begin
  1270. inherited;
  1271. if Operation = opRemove then begin
  1272. RemoveFromList(FLinkParents, AComponent);
  1273. if AComponent = Action then Action := nil;
  1274. if AComponent = Images then Images := nil;
  1275. if AComponent = SubMenuImages then SubMenuImages := nil;
  1276. if AComponent = LinkSubitems then LinkSubitems := nil;
  1277. end;
  1278. end;
  1279. procedure TTBCustomItem.IndexError;
  1280. begin
  1281. raise ETBItemError.Create(STBToolbarIndexOutOfBounds);
  1282. end;
  1283. class procedure TTBCustomItem.ClickWndProc(var Message: TMessage);
  1284. var
  1285. List: TList;
  1286. I: Integer;
  1287. Item: TObject;
  1288. begin
  1289. if Message.Msg = WM_TB2K_CLICKITEM then begin
  1290. List := ClickList; { optimization... }
  1291. if Assigned(List) then begin
  1292. I := Message.LParam;
  1293. if (I >= 0) and (I < List.Count) then begin
  1294. Item := List[I];
  1295. List[I] := nil;
  1296. if Item = Pointer(1) then { is it a destroyed item? }
  1297. Item := nil;
  1298. end
  1299. else
  1300. Item := nil;
  1301. { Remove trailing nil items from ClickList. This is not *necessary*, but
  1302. it will make RemoveFromClickList faster if we clean out items that
  1303. aren't used, and may never be used again. }
  1304. for I := List.Count-1 downto 0 do begin
  1305. if List[I] = nil then
  1306. List.Delete(I)
  1307. else
  1308. Break;
  1309. end;
  1310. if Assigned(Item) then begin
  1311. try
  1312. if Item is TTBCustomItem then
  1313. TTBCustomItem(Item).Click
  1314. else if Item is TTBItemViewer then
  1315. TTBItemViewer(Item).AccSelect(Message.WParam <> 0);
  1316. except
  1317. Application.HandleException(Item);
  1318. end;
  1319. end;
  1320. end;
  1321. end
  1322. else
  1323. with Message do
  1324. Result := DefWindowProc(ClickWnd, Msg, wParam, lParam);
  1325. end;
  1326. procedure TTBCustomItem.PostClick;
  1327. { Posts a message to the message queue that causes the item's Click handler to
  1328. be executed when control is returned to the message loop.
  1329. This should be called instead of Click when a WM_SYSCOMMAND message is
  1330. (possibly) currently being handled, because TApplication.WndProc's
  1331. CM_APPSYSCOMMAND handler disables the VCL's processing of focus messages
  1332. until the Perform(WM_SYSCOMMAND, ...) call returns. (An OnClick handler which
  1333. calls TForm.ShowModal needs focus messages to be enabled or else the form
  1334. will be shown with no initial focus.) }
  1335. begin
  1336. QueueClick(Self, 0);
  1337. end;
  1338. procedure TTBCustomItem.Click;
  1339. begin
  1340. if Enabled then begin
  1341. { Following code based on D6's TMenuItem.Click }
  1342. {$IFDEF JR_D6}
  1343. if (not Assigned(ActionLink) and AutoCheck) or
  1344. (Assigned(ActionLink) and not ActionLink.IsAutoCheckLinked and AutoCheck) then
  1345. {$ELSE}
  1346. if AutoCheck then
  1347. {$ENDIF}
  1348. Checked := not Checked;
  1349. { Following code based on D4's TControl.Click }
  1350. { Call OnClick if assigned and not equal to associated action's OnExecute.
  1351. If associated action's OnExecute assigned then call it, otherwise, call
  1352. OnClick. }
  1353. if Assigned(FOnClick) and (Action <> nil) and
  1354. not MethodsEqual(TMethod(FOnClick), TMethod(Action.OnExecute)) then
  1355. FOnClick(Self)
  1356. else
  1357. if not(csDesigning in ComponentState) and (ActionLink <> nil) then
  1358. ActionLink.Execute {$IFDEF JR_D6}(Self){$ENDIF}
  1359. else
  1360. if Assigned(FOnClick) then
  1361. FOnClick(Self);
  1362. end;
  1363. end;
  1364. function TTBCustomItem.GetItem(Index: Integer): TTBCustomItem;
  1365. begin
  1366. if (Index < 0) or (Index >= FItemCount) then IndexError;
  1367. Result := FItems[Index].Item;
  1368. end;
  1369. procedure TTBCustomItem.Add(AItem: TTBCustomItem);
  1370. begin
  1371. Insert(Count, AItem);
  1372. end;
  1373. procedure TTBCustomItem.InternalNotify(Ancestor: TTBCustomItem;
  1374. NestingLevel: Integer; Action: TTBItemChangedAction; Index: Integer;
  1375. Item: TTBCustomItem);
  1376. { Note: Ancestor is Item's parent, or in the case of a group item relayed
  1377. notification, it can also be a group item which *links* to Item's parent
  1378. (i.e. ItemContainingItems(Ancestor) = Item.Parent). }
  1379. procedure RelayToParentOf(const AItem: TTBCustomItem);
  1380. begin
  1381. if NestingLevel > MaxGroupLevel then
  1382. Exit;
  1383. if (tbisEmbeddedGroup in AItem.ItemStyle) and Assigned(AItem.Parent) then begin
  1384. if Ancestor = Self then
  1385. AItem.Parent.InternalNotify(AItem, NestingLevel + 1, Action, Index, Item)
  1386. else
  1387. { Don't alter Ancestor on subsequent relays; only on the first. }
  1388. AItem.Parent.InternalNotify(Ancestor, NestingLevel + 1, Action, Index, Item);
  1389. end;
  1390. end;
  1391. var
  1392. I: Integer;
  1393. P: TTBCustomItem;
  1394. SaveProc: TTBItemChangedProc;
  1395. begin
  1396. { If Self is a group item, relay the notification to the parent }
  1397. RelayToParentOf(Self);
  1398. { If any group items are linked to Self, relay the notification to
  1399. those items' parents }
  1400. if Assigned(FLinkParents) then
  1401. for I := 0 to FLinkParents.Count-1 do begin
  1402. P := FLinkParents[I];
  1403. if P <> Parent then
  1404. RelayToParentOf(P);
  1405. end;
  1406. if Assigned(FNotifyList) then begin
  1407. I := 0;
  1408. while I < FNotifyList.Count do begin
  1409. with PItemChangedNotificationData(FNotifyList[I])^ do begin
  1410. SaveProc := Proc;
  1411. Proc(Ancestor, Ancestor <> Self, Action, Index, Item);
  1412. end;
  1413. { Is I now out of bounds? }
  1414. if I >= FNotifyList.Count then
  1415. Break;
  1416. { Only proceed to the next index if the list didn't change }
  1417. if MethodsEqual(TMethod(PItemChangedNotificationData(FNotifyList[I])^.Proc),
  1418. TMethod(SaveProc)) then
  1419. Inc(I);
  1420. end;
  1421. end;
  1422. end;
  1423. procedure TTBCustomItem.Notify(Action: TTBItemChangedAction; Index: Integer;
  1424. Item: TTBCustomItem);
  1425. begin
  1426. InternalNotify(Self, 0, Action, Index, Item);
  1427. end;
  1428. procedure TTBCustomItem.ViewBeginUpdate;
  1429. begin
  1430. Notify(tbicSubitemsBeginUpdate, -1, nil);
  1431. end;
  1432. procedure TTBCustomItem.ViewEndUpdate;
  1433. begin
  1434. Notify(tbicSubitemsEndUpdate, -1, nil);
  1435. end;
  1436. procedure TTBCustomItem.Insert(NewIndex: Integer; AItem: TTBCustomItem);
  1437. begin
  1438. if Assigned(AItem.FParent) then
  1439. raise ETBItemError.Create(STBToolbarItemReinserted);
  1440. if (NewIndex < 0) or (NewIndex > FItemCount) then IndexError;
  1441. InsertIntoItemArray(FItems, FItemCount, NewIndex, AItem);
  1442. AItem.FParent := Self;
  1443. ViewBeginUpdate;
  1444. try
  1445. Notify(tbicInserted, NewIndex, AItem);
  1446. AItem.RefreshOptions;
  1447. finally
  1448. ViewEndUpdate;
  1449. end;
  1450. end;
  1451. procedure TTBCustomItem.Delete(Index: Integer);
  1452. begin
  1453. if (Index < 0) or (Index >= FItemCount) then IndexError;
  1454. Notify(tbicDeleting, Index, FItems[Index].Item);
  1455. FItems[Index].Item.FParent := nil;
  1456. DeleteFromItemArray(FItems, FItemCount, Index);
  1457. end;
  1458. function TTBCustomItem.IndexOf(AItem: TTBCustomItem): Integer;
  1459. var
  1460. I: Integer;
  1461. begin
  1462. for I := 0 to FItemCount-1 do
  1463. if FItems[I].Item = AItem then begin
  1464. Result := I;
  1465. Exit;
  1466. end;
  1467. Result := -1;
  1468. end;
  1469. procedure TTBCustomItem.Remove(Item: TTBCustomItem);
  1470. var
  1471. I: Integer;
  1472. begin
  1473. I := IndexOf(Item);
  1474. //if I = -1 then raise ETBItemError.Create(STBToolbarItemNotFound);
  1475. if I <> -1 then
  1476. Delete(I);
  1477. end;
  1478. procedure TTBCustomItem.Clear;
  1479. var
  1480. I: Integer;
  1481. begin
  1482. for I := Count-1 downto 0 do
  1483. Items[I].Free;
  1484. end;
  1485. procedure TTBCustomItem.Move(CurIndex, NewIndex: Integer);
  1486. var
  1487. Item: TTBCustomItem;
  1488. begin
  1489. if CurIndex <> NewIndex then begin
  1490. if (NewIndex < 0) or (NewIndex >= FItemCount) then IndexError;
  1491. Item := Items[CurIndex];
  1492. ViewBeginUpdate;
  1493. try
  1494. Delete(CurIndex);
  1495. Insert(NewIndex, Item);
  1496. finally
  1497. ViewEndUpdate;
  1498. end;
  1499. end;
  1500. end;
  1501. function TTBCustomItem.ContainsItem(AItem: TTBCustomItem): Boolean;
  1502. begin
  1503. while Assigned(AItem) and (AItem <> Self) do
  1504. AItem := AItem.Parent;
  1505. Result := Assigned(AItem);
  1506. end;
  1507. procedure TTBCustomItem.RegisterNotification(ANotify: TTBItemChangedProc);
  1508. var
  1509. I: Integer;
  1510. Data: PItemChangedNotificationData;
  1511. begin
  1512. if FNotifyList = nil then FNotifyList := TList.Create;
  1513. for I := 0 to FNotifyList.Count-1 do
  1514. with PItemChangedNotificationData(FNotifyList[I])^ do
  1515. if MethodsEqual(TMethod(ANotify), TMethod(Proc)) then begin
  1516. Inc(RefCount);
  1517. Exit;
  1518. end;
  1519. FNotifyList.Expand;
  1520. New(Data);
  1521. Data.Proc := ANotify;
  1522. Data.RefCount := 1;
  1523. FNotifyList.Add(Data);
  1524. end;
  1525. procedure TTBCustomItem.UnregisterNotification(ANotify: TTBItemChangedProc);
  1526. var
  1527. I: Integer;
  1528. Data: PItemChangedNotificationData;
  1529. begin
  1530. if Assigned(FNotifyList) then
  1531. for I := 0 to FNotifyList.Count-1 do begin
  1532. Data := FNotifyList[I];
  1533. if MethodsEqual(TMethod(Data.Proc), TMethod(ANotify)) then begin
  1534. Dec(Data.RefCount);
  1535. if Data.RefCount = 0 then begin
  1536. FNotifyList.Delete(I);
  1537. Dispose(Data);
  1538. if FNotifyList.Count = 0 then begin
  1539. FNotifyList.Free;
  1540. FNotifyList := nil;
  1541. end;
  1542. end;
  1543. Break;
  1544. end;
  1545. end;
  1546. end;
  1547. function TTBCustomItem.GetPopupWindowClass: TTBPopupWindowClass;
  1548. begin
  1549. Result := TTBPopupWindow;
  1550. end;
  1551. procedure TTBCustomItem.DoPopup(Sender: TTBCustomItem; FromLink: Boolean);
  1552. begin
  1553. if Assigned(FOnPopup) then
  1554. FOnPopup(Sender, FromLink);
  1555. if not(tbisCombo in ItemStyle) then
  1556. Click;
  1557. end;
  1558. var
  1559. PlayedSound: Boolean = False;
  1560. procedure TTBCustomItem.GetPopupPosition(ParentView: TTBView;
  1561. PopupWindow: TTBPopupWindow; var PopupPositionRec: TTBPopupPositionRec);
  1562. var
  1563. X2, Y2: Integer;
  1564. RepeatCalcX: Boolean;
  1565. function CountObscured(X, Y, W, H: Integer): Integer;
  1566. var
  1567. I: Integer;
  1568. P: TPoint;
  1569. V: TTBItemViewer;
  1570. begin
  1571. Result := 0;
  1572. if ParentView = nil then
  1573. Exit;
  1574. P := ParentView.FWindow.ClientToScreen(Point(0, 0));
  1575. Dec(X, P.X);
  1576. Dec(Y, P.Y);
  1577. Inc(W, X);
  1578. Inc(H, Y);
  1579. for I := 0 to ParentView.FViewerCount-1 do begin
  1580. V := ParentView.FViewers[I];
  1581. if V.Show and (V.BoundsRect.Left >= X) and (V.BoundsRect.Right <= W) and
  1582. (V.BoundsRect.Top >= Y) and (V.BoundsRect.Bottom <= H) then
  1583. Inc(Result);
  1584. end;
  1585. end;
  1586. begin
  1587. with PopupPositionRec do
  1588. begin
  1589. { Adjust the Y position of the popup window }
  1590. { If the window is going off the bottom of the monitor, try placing it
  1591. above the parent item }
  1592. if (Y + H > MonitorRect.Bottom) and
  1593. ((ParentView = nil) or (ParentView.FOrientation <> tbvoVertical)) then begin
  1594. if not PositionAsSubmenu then
  1595. Y2 := ParentItemRect.Top
  1596. else
  1597. Y2 := ParentItemRect.Bottom + NCSizeY;
  1598. Dec(Y2, H);
  1599. { Only place it above the parent item if it isn't going to go off the
  1600. top of the monitor }
  1601. if Y2 >= MonitorRect.Top then
  1602. Y := Y2;
  1603. end;
  1604. { If it's still going off the bottom (which can be possible if a menu bar
  1605. was off the screen to begin with), clip it to the bottom of the monitor }
  1606. if Y + H > MonitorRect.Bottom then
  1607. Y := MonitorRect.Bottom - H;
  1608. if Y < MonitorRect.Top then
  1609. Y := MonitorRect.Top;
  1610. { Other adjustments to the position of the popup window }
  1611. if not PositionAsSubmenu then begin
  1612. if (ParentView = nil) and (Alignment = tbpaRight) and (X < MonitorRect.Left) then
  1613. Inc(X, W);
  1614. if X + W > MonitorRect.Right then begin
  1615. if Assigned(ParentView) or (Alignment <> tbpaLeft) then
  1616. X := MonitorRect.Right;
  1617. Dec(X, W);
  1618. end;
  1619. if X < MonitorRect.Left then
  1620. X := MonitorRect.Left;
  1621. if (ParentView = nil) or (ParentView.FOrientation <> tbvoVertical) then begin
  1622. Y2 := ParentItemRect.Top - H;
  1623. if Y2 >= MonitorRect.Top then begin
  1624. { Would the popup window obscure less items if it popped out to the
  1625. top instead? }
  1626. if (CountObscured(X, Y2, W, H) < CountObscured(X, Y, W, H)) or
  1627. ((Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
  1628. (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left)) then
  1629. Y := Y2;
  1630. end;
  1631. { Make sure a tall popup window doesn't overlap the parent item }
  1632. if (Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
  1633. (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left) then begin
  1634. if ParentItemRect.Right + W <= MonitorRect.Right then
  1635. X := ParentItemRect.Right
  1636. else
  1637. X := ParentItemRect.Left - W;
  1638. if X < MonitorRect.Top then
  1639. X := MonitorRect.Top;
  1640. end;
  1641. end
  1642. else begin
  1643. X2 := ParentItemRect.Right;
  1644. if X2 + W <= MonitorRect.Right then begin
  1645. { Would the popup window obscure less items if it popped out to the
  1646. right instead? }
  1647. if (CountObscured(X2, Y, W, H) < CountObscured(X, Y, W, H)) or
  1648. ((Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
  1649. (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left)) then
  1650. X := X2;
  1651. end;
  1652. { Make sure a wide popup window doesn't overlap the parent item }
  1653. if (Y < ParentItemRect.Bottom) and (Y + H > ParentItemRect.Top) and
  1654. (X < ParentItemRect.Right) and (X + W > ParentItemRect.Left) then begin
  1655. if ParentItemRect.Bottom + H <= MonitorRect.Bottom then
  1656. Y := ParentItemRect.Bottom
  1657. else
  1658. Y := ParentItemRect.Top - H;
  1659. if Y < MonitorRect.Top then
  1660. Y := MonitorRect.Top;
  1661. end;
  1662. end;
  1663. end
  1664. else begin
  1665. { Make nested submenus go from left to right on the screen. Each it
  1666. runs out of space on the screen, switch directions }
  1667. repeat
  1668. RepeatCalcX := False;
  1669. X2 := X;
  1670. if Opposite or (X2 + W > MonitorRect.Right) then begin
  1671. if Assigned(ParentView) then
  1672. X2 := ParentItemRect.Left + NCSizeX;
  1673. Dec(X2, W);
  1674. if not Opposite then
  1675. Include(PopupWindow.View.FState, vsOppositePopup)
  1676. else begin
  1677. if X2 < MonitorRect.Left then begin
  1678. Opposite := False;
  1679. RepeatCalcX := True;
  1680. end
  1681. else
  1682. Include(PopupWindow.View.FState, vsOppositePopup);
  1683. end;
  1684. end;
  1685. until not RepeatCalcX;
  1686. X := X2;
  1687. if X < MonitorRect.Left then
  1688. X := MonitorRect.Left;
  1689. end;
  1690. { Determine animation direction }
  1691. AnimDir := [];
  1692. if not PositionAsSubmenu then begin
  1693. if Y >= ParentItemRect.Bottom then
  1694. Include(AnimDir, tbadDown)
  1695. else if Y + H <= ParentItemRect.Top then
  1696. Include(AnimDir, tbadUp);
  1697. if X >= ParentItemRect.Right then
  1698. Include(AnimDir, tbadRight)
  1699. else if X + W <= ParentItemRect.Left then
  1700. Include(AnimDir, tbadLeft);
  1701. end
  1702. else begin
  1703. if X + W div 2 >= ParentItemRect.Left + (ParentItemRect.Right - ParentItemRect.Left) div 2 then
  1704. Include(AnimDir, tbadRight)
  1705. else
  1706. Include(AnimDir, tbadLeft);
  1707. end;
  1708. end;
  1709. end;
  1710. function TTBCustomItem.CreatePopup(const ParentView: TTBView;
  1711. const ParentViewer: TTBItemViewer; const PositionAsSubmenu, SelectFirstItem,
  1712. Customizing: Boolean; const APopupPoint: TPoint;
  1713. const Alignment: TTBPopupAlignment): TTBPopupWindow;
  1714. var
  1715. EventItem, ParentItem: TTBCustomItem;
  1716. Opposite: Boolean;
  1717. ChevronParentView: TTBView;
  1718. X, Y, W, H: Integer;
  1719. P: TPoint;
  1720. ParentItemRect: TRect;
  1721. MonitorRect: TRect;
  1722. PopupRec: TTBPopupPositionRec;
  1723. NCSize: TPoint;
  1724. begin
  1725. EventItem := ItemContainingItems(Self);
  1726. if EventItem <> Self then
  1727. EventItem.DoPopup(Self, True);
  1728. DoPopup(Self, False);
  1729. ChevronParentView := GetChevronParentView;
  1730. if ChevronParentView = nil then
  1731. ParentItem := Self
  1732. else
  1733. ParentItem := ChevronParentView.FParentItem;
  1734. Opposite := Assigned(ParentView) and (vsOppositePopup in ParentView.FState);
  1735. Result := GetPopupWindowClass.CreatePopupWindow(nil, ParentView, ParentItem,
  1736. Customizing);
  1737. try
  1738. if Assigned(ChevronParentView) then begin
  1739. ChevronParentView.FreeNotification(Result.View);
  1740. Result.View.FChevronParentView := ChevronParentView;
  1741. Result.View.FIsToolbar := True;
  1742. Result.View.Style := Result.View.Style +
  1743. (ChevronParentView.Style * [vsAlwaysShowHints]);
  1744. Result.Color := clBtnFace;
  1745. end;
  1746. { Calculate ParentItemRect, and MonitorRect (the rectangle of the monitor
  1747. that the popup window will be confined to) }
  1748. if Assigned(ParentView) then begin
  1749. ParentView.ValidatePositions;
  1750. ParentItemRect := ParentViewer.BoundsRect;
  1751. P := ParentView.FWindow.ClientToScreen(Point(0, 0));
  1752. OffsetRect(ParentItemRect, P.X, P.Y);
  1753. if not IsRectEmpty(ParentView.FMonitorRect) then
  1754. MonitorRect := ParentView.FMonitorRect
  1755. else
  1756. {MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, False);} {vb-}
  1757. MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, True); {vb+}
  1758. end
  1759. else begin
  1760. ParentItemRect.TopLeft := APopupPoint;
  1761. ParentItemRect.BottomRight := APopupPoint;
  1762. {MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, False);} {vb-}
  1763. MonitorRect := GetRectOfMonitorContainingPoint(APopupPoint, True); {vb+}
  1764. end;
  1765. Result.View.FMonitorRect := MonitorRect;
  1766. { Initialize item positions and size of the popup window }
  1767. NCSize := Result.GetNCSize;
  1768. if ChevronParentView = nil then
  1769. Result.View.FMaxHeight := (MonitorRect.Bottom - MonitorRect.Top) -
  1770. (NCSize.Y * 2)
  1771. else
  1772. Result.View.WrapOffset := (MonitorRect.Right - MonitorRect.Left) -
  1773. (NCSize.X * 2);
  1774. if SelectFirstItem then
  1775. Result.View.Selected := Result.View.FirstSelectable;
  1776. Result.View.UpdatePositions;
  1777. W := Result.Width;
  1778. H := Result.Height;
  1779. { Calculate initial X,Y position of the popup window }
  1780. if Assigned(ParentView) then begin
  1781. if not PositionAsSubmenu then begin
  1782. if ChevronParentView = nil then begin
  1783. if (ParentView = nil) or (ParentView.FOrientation <> tbvoVertical) then begin
  1784. if GetSystemMetrics(SM_MENUDROPALIGNMENT) = 0 then
  1785. X := ParentItemRect.Left
  1786. else
  1787. X := ParentItemRect.Right - W;
  1788. Y := ParentItemRect.Bottom;
  1789. end
  1790. else begin
  1791. X := ParentItemRect.Left - W;
  1792. Y := ParentItemRect.Top;
  1793. end;
  1794. end
  1795. else begin
  1796. if ChevronParentView.FOrientation <> tbvoVertical then begin
  1797. X := ParentItemRect.Right - W;
  1798. Y := ParentItemRect.Bottom;
  1799. end
  1800. else begin
  1801. X := ParentItemRect.Left - W;
  1802. Y := ParentItemRect.Top;
  1803. end;
  1804. end;
  1805. end
  1806. else begin
  1807. X := ParentItemRect.Right - NCSize.X;
  1808. Y := ParentItemRect.Top - NCSize.Y;
  1809. end;
  1810. end
  1811. else begin
  1812. X := APopupPoint.X;
  1813. Y := APopupPoint.Y;
  1814. case Alignment of
  1815. tbpaRight: Dec(X, W);
  1816. tbpaCenter: Dec(X, W div 2);
  1817. end;
  1818. end;
  1819. PopupRec.PositionAsSubmenu := PositionAsSubmenu;
  1820. PopupRec.Alignment := Alignment;
  1821. PopupRec.Opposite := Opposite;
  1822. PopupRec.MonitorRect := MonitorRect;
  1823. PopupRec.ParentItemRect := ParentItemRect;
  1824. PopupRec.NCSizeX := NCSize.X;
  1825. PopupRec.NCSizeY := NCSize.Y;
  1826. PopupRec.X := X;
  1827. PopupRec.Y := Y;
  1828. PopupRec.W := W;
  1829. PopupRec.H := H;
  1830. PopupRec.AnimDir := [];
  1831. PopupRec.PlaySound := True;
  1832. GetPopupPosition(ParentView, Result, PopupRec);
  1833. X := PopupRec.X;
  1834. Y := PopupRec.Y;
  1835. W := PopupRec.W;
  1836. H := PopupRec.H;
  1837. Result.FAnimationDirection := PopupRec.AnimDir;
  1838. Result.SetBounds(X, Y, W, H);
  1839. if Assigned(ParentView) then begin
  1840. Result.FreeNotification(ParentView);
  1841. ParentView.FOpenViewerWindow := Result;
  1842. ParentView.FOpenViewerView := Result.View;
  1843. ParentView.FOpenViewer := ParentViewer;
  1844. if ParentView.FIsToolbar then begin
  1845. Include(ParentView.FState, vsDropDownMenus);
  1846. ParentView.Invalidate(ParentViewer);
  1847. ParentView.FWindow.Update;
  1848. end;
  1849. end;
  1850. Include(Result.View.FState, vsDrawInOrder);
  1851. if not PopupRec.PlaySound or not NeedToPlaySound('MenuPopup') then begin
  1852. { Don't call PlaySound if we don't have to }
  1853. Result.Visible := True;
  1854. end
  1855. else begin
  1856. if not PlayedSound then begin
  1857. { Work around Windows 2000 "bug" where there's a 1/3 second delay upon the
  1858. first call to PlaySound (or sndPlaySound) by painting the window
  1859. completely first. This way the delay isn't very noticable. }
  1860. PlayedSound := True;
  1861. Result.Visible := True;
  1862. Result.Update;
  1863. PlaySound('MenuPopup', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
  1864. end
  1865. else begin
  1866. PlaySound('MenuPopup', 0, SND_ALIAS or SND_ASYNC or SND_NODEFAULT or SND_NOSTOP);
  1867. Result.Visible := True;
  1868. end;
  1869. end;
  1870. CallNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, Result.View.FWindow.Handle,
  1871. OBJID_CLIENT, CHILDID_SELF);
  1872. { Call NotifyFocusEvent now that the window is visible }
  1873. if Assigned(Result.View.Selected) then
  1874. Result.View.NotifyFocusEvent;
  1875. except
  1876. Result.Free;
  1877. raise;
  1878. end;
  1879. end;
  1880. function TTBCustomItem.OpenPopup(const SelectFirstItem, TrackRightButton: Boolean;
  1881. const PopupPoint: TPoint; const Alignment: TTBPopupAlignment;
  1882. const ReturnClickedItemOnly: Boolean): TTBCustomItem;
  1883. var
  1884. ModalHandler: TTBModalHandler;
  1885. Popup: TTBPopupWindow;
  1886. DoneActionData: TTBDoneActionData;
  1887. begin
  1888. ModalHandler := TTBModalHandler.Create(0);
  1889. try
  1890. Popup := CreatePopup(nil, nil, False, SelectFirstItem, False, PopupPoint,
  1891. Alignment);
  1892. try
  1893. Include(Popup.View.FState, vsIgnoreFirstMouseUp);
  1894. ModalHandler.RootPopup := Popup;
  1895. ModalHandler.Loop(Popup.View, False, False, False, TrackRightButton);
  1896. DoneActionData := Popup.View.FDoneActionData;
  1897. finally
  1898. ModalHandler.RootPopup := nil;
  1899. { Remove vsModal state from the root view before any TTBView.Destroy
  1900. methods get called, so that NotifyFocusEvent becomes a no-op }
  1901. Exclude(Popup.View.FState, vsModal);
  1902. Popup.Free;
  1903. end;
  1904. finally
  1905. ModalHandler.Free;
  1906. end;
  1907. Result := ProcessDoneAction(DoneActionData, ReturnClickedItemOnly);
  1908. end;
  1909. function TTBCustomItem.Popup(X, Y: Integer; TrackRightButton: Boolean;
  1910. Alignment: TTBPopupAlignment = tbpaLeft;
  1911. ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
  1912. var
  1913. P: TPoint;
  1914. begin
  1915. P.X := X;
  1916. P.Y := Y;
  1917. Result := OpenPopup(False, TrackRightButton, P, Alignment,
  1918. ReturnClickedItemOnly);
  1919. end;
  1920. function TTBCustomItem.FindItemWithShortCut(AShortCut: TShortCut;
  1921. var ATopmostParent: TTBCustomItem): TTBCustomItem;
  1922. function DoItem(AParentItem: TTBCustomItem; LinkDepth: Integer): TTBCustomItem;
  1923. var
  1924. I: Integer;
  1925. NewParentItem, Item: TTBCustomItem;
  1926. begin
  1927. Result := nil;
  1928. NewParentItem := AParentItem;
  1929. if Assigned(NewParentItem.LinkSubitems) then begin
  1930. NewParentItem := NewParentItem.LinkSubitems;
  1931. Inc(LinkDepth);
  1932. if LinkDepth > 25 then
  1933. Exit; { prevent infinite link recursion }
  1934. end;
  1935. for I := 0 to NewParentItem.Count-1 do begin
  1936. Item := NewParentItem.Items[I];
  1937. if Item.ShortCut = AShortCut then begin
  1938. Result := Item;
  1939. Exit;
  1940. end;
  1941. Result := DoItem(Item, LinkDepth);
  1942. if Assigned(Result) then begin
  1943. ATopmostParent := Item;
  1944. Exit;
  1945. end;
  1946. end;
  1947. end;
  1948. begin
  1949. ATopmostParent := nil;
  1950. Result := DoItem(Self, 0);
  1951. end;
  1952. function TTBCustomItem.IsShortCut(var Message: TWMKey): Boolean;
  1953. var
  1954. ShortCut: TShortCut;
  1955. ShiftState: TShiftState;
  1956. ShortCutItem, TopmostItem, Item, EventItem: TTBCustomItem;
  1957. I: Integer;
  1958. label 1;
  1959. begin
  1960. Result := False;
  1961. ShiftState := KeyDataToShiftState(Message.KeyData);
  1962. ShortCut := Menus.ShortCut(Message.CharCode, ShiftState);
  1963. 1:ShortCutItem := FindItemWithShortCut(ShortCut, TopmostItem);
  1964. if Assigned(ShortCutItem) then begin
  1965. { Send OnPopup/OnClick events to ShortCutItem's parents so that they can
  1966. update the Enabled state of ShortCutItem if needed }
  1967. Item := Self;
  1968. repeat
  1969. if not Item.Enabled then
  1970. Exit;
  1971. EventItem := ItemContainingItems(Item);
  1972. if not(csDesigning in ComponentState) then begin
  1973. for I := 0 to EventItem.Count-1 do
  1974. EventItem.Items[I].InitiateAction;
  1975. end;
  1976. if not(tbisEmbeddedGroup in Item.ItemStyle) then begin
  1977. if EventItem <> Item then begin
  1978. try
  1979. EventItem.DoPopup(Item, True);
  1980. except
  1981. Application.HandleException(Self);
  1982. end;
  1983. end;
  1984. try
  1985. Item.DoPopup(Item, False);
  1986. except
  1987. Application.HandleException(Self);
  1988. end;
  1989. end;
  1990. ShortCutItem := Item.FindItemWithShortCut(ShortCut, TopmostItem);
  1991. if ShortCutItem = nil then
  1992. { Can no longer find the shortcut inside TopmostItem. Start over
  1993. because the shortcut might have moved. }
  1994. goto 1;
  1995. Item := TopmostItem;
  1996. until Item = nil;
  1997. if ShortCutItem.Enabled then begin
  1998. try
  1999. ShortCutItem.Click;
  2000. except
  2001. Application.HandleException(Self);
  2002. end;
  2003. Result := True;
  2004. end;
  2005. end;
  2006. end;
  2007. function TTBCustomItem.GetChevronParentView: TTBView;
  2008. begin
  2009. Result := nil;
  2010. end;
  2011. function TTBCustomItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  2012. begin
  2013. Result := TTBItemViewer;
  2014. end;
  2015. function TTBCustomItem.NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean;
  2016. begin
  2017. Result := False;
  2018. end;
  2019. function TTBCustomItem.GetShortCutText: String;
  2020. var
  2021. P: Integer;
  2022. begin
  2023. P := Pos(#9, Caption);
  2024. if P = 0 then begin
  2025. if ShortCut <> 0 then
  2026. Result := ShortCutToText(ShortCut)
  2027. else
  2028. Result := '';
  2029. end
  2030. else
  2031. Result := Copy(Caption, P+1, Maxint);
  2032. end;
  2033. procedure TTBCustomItem.Change(NeedResize: Boolean);
  2034. const
  2035. ItemChangedActions: array[Boolean] of TTBItemChangedAction =
  2036. (tbicInvalidate, tbicInvalidateAndResize);
  2037. begin
  2038. if Assigned(FParent) then
  2039. FParent.Notify(ItemChangedActions[NeedResize], -1, Self);
  2040. end;
  2041. procedure TTBCustomItem.RecreateItemViewers;
  2042. begin
  2043. if Assigned(FParent) then
  2044. FParent.Notify(tbicRecreateItemViewers, -1, Self);
  2045. end;
  2046. procedure TTBCustomItem.ImageListChangeHandler(Sender: TObject);
  2047. var
  2048. Resize: Boolean;
  2049. begin
  2050. if Sender = FSubMenuImages then begin
  2051. FSubMenuImagesChangeLink.FLastWidth := FSubMenuImages.Width;
  2052. FSubMenuImagesChangeLink.FLastHeight := FSubMenuImages.Height;
  2053. SubMenuImagesChanged;
  2054. end
  2055. else begin
  2056. { Sender is FImages }
  2057. Resize := False;
  2058. if (FImagesChangeLink.FLastWidth <> FImages.Width) or
  2059. (FImagesChangeLink.FLastHeight <> FImages.Height) then begin
  2060. FImagesChangeLink.FLastWidth := FImages.Width;
  2061. FImagesChangeLink.FLastHeight := FImages.Height;
  2062. Resize := True;
  2063. end;
  2064. Change(Resize);
  2065. end;
  2066. end;
  2067. procedure TTBCustomItem.SubMenuImagesChanged;
  2068. begin
  2069. Notify(tbicSubMenuImagesChanged, -1, nil);
  2070. end;
  2071. procedure TTBCustomItem.TurnSiblingsOff;
  2072. var
  2073. I: Integer;
  2074. Item: TTBCustomItem;
  2075. begin
  2076. if (GroupIndex <> 0) and Assigned(FParent) then begin
  2077. for I := 0 to FParent.Count-1 do begin
  2078. Item := FParent[I];
  2079. if (Item <> Self) and (Item.GroupIndex = GroupIndex) then
  2080. Item.Checked := False;
  2081. end;
  2082. end;
  2083. end;
  2084. procedure TTBCustomItem.SetCaption(Value: String);
  2085. begin
  2086. if FCaption <> Value then begin
  2087. FCaption := Value;
  2088. Change(True);
  2089. end;
  2090. end;
  2091. procedure TTBCustomItem.SetChecked(Value: Boolean);
  2092. begin
  2093. if FChecked <> Value then begin
  2094. FChecked := Value;
  2095. Change(False);
  2096. if Value then
  2097. TurnSiblingsOff;
  2098. end;
  2099. end;
  2100. procedure TTBCustomItem.SetDisplayMode(Value: TTBItemDisplayMode);
  2101. begin
  2102. if FDisplayMode <> Value then begin
  2103. FDisplayMode := Value;
  2104. Change(True);
  2105. end;
  2106. end;
  2107. procedure TTBCustomItem.EnabledChanged;
  2108. begin
  2109. Change(False);
  2110. end;
  2111. procedure TTBCustomItem.SetEnabled(Value: Boolean);
  2112. begin
  2113. if FEnabled <> Value then begin
  2114. FEnabled := Value;
  2115. EnabledChanged;
  2116. end;
  2117. end;
  2118. procedure TTBCustomItem.SetGroupIndex(Value: Integer);
  2119. begin
  2120. if FGroupIndex <> Value then begin
  2121. FGroupIndex := Value;
  2122. if Checked then
  2123. TurnSiblingsOff;
  2124. end;
  2125. end;
  2126. procedure TTBCustomItem.SetImageIndex(Value: TImageIndex);
  2127. var
  2128. HadNoImage: Boolean;
  2129. begin
  2130. if FImageIndex <> Value then begin
  2131. HadNoImage := FImageIndex = -1;
  2132. FImageIndex := Value;
  2133. Change(HadNoImage xor (Value = -1));
  2134. end;
  2135. end;
  2136. function TTBCustomItem.ChangeImages(var AImages: TCustomImageList;
  2137. const Value: TCustomImageList; var AChangeLink: TTBImageChangeLink): Boolean;
  2138. { Returns True if image list was resized }
  2139. var
  2140. LastWidth, LastHeight: Integer;
  2141. begin
  2142. Result := False;
  2143. LastWidth := -1;
  2144. LastHeight := -1;
  2145. if Assigned(AImages) then begin
  2146. LastWidth := AImages.Width;
  2147. LastHeight := AImages.Height;
  2148. AImages.UnregisterChanges(AChangeLink);
  2149. if Value = nil then begin
  2150. AChangeLink.Free;
  2151. AChangeLink := nil;
  2152. Result := True;
  2153. end;
  2154. end;
  2155. AImages := Value;
  2156. if Assigned(Value) then begin
  2157. Result := (Value.Width <> LastWidth) or (Value.Height <> LastHeight);
  2158. if AChangeLink = nil then begin
  2159. AChangeLink := TTBImageChangeLink.Create;
  2160. AChangeLink.FLastWidth := Value.Width;
  2161. AChangeLink.FLastHeight := Value.Height;
  2162. AChangeLink.OnChange := ImageListChangeHandler;
  2163. end;
  2164. Value.RegisterChanges(AChangeLink);
  2165. Value.FreeNotification(Self);
  2166. end;
  2167. end;
  2168. procedure TTBCustomItem.SetImages(Value: TCustomImageList);
  2169. begin
  2170. if FImages <> Value then
  2171. Change(ChangeImages(FImages, Value, FImagesChangeLink));
  2172. end;
  2173. procedure TTBCustomItem.SetSubMenuImages(Value: TCustomImageList);
  2174. begin
  2175. if FSubMenuImages <> Value then begin
  2176. ChangeImages(FSubMenuImages, Value, FSubMenuImagesChangeLink);
  2177. SubMenuImagesChanged;
  2178. end;
  2179. end;
  2180. procedure TTBCustomItem.SetInheritOptions(Value: Boolean);
  2181. begin
  2182. if FInheritOptions <> Value then begin
  2183. FInheritOptions := Value;
  2184. RefreshOptions;
  2185. end;
  2186. end;
  2187. procedure TTBCustomItem.SetLinkSubitems(Value: TTBCustomItem);
  2188. begin
  2189. if Value = Self then
  2190. Value := nil;
  2191. if FLinkSubitems <> Value then begin
  2192. if Assigned(FLinkSubitems) then
  2193. RemoveFromList(FLinkSubitems.FLinkParents, Self);
  2194. FLinkSubitems := Value;
  2195. if Assigned(Value) then begin
  2196. Value.FreeNotification(Self);
  2197. AddToList(Value.FLinkParents, Self);
  2198. end;
  2199. Notify(tbicSubitemsChanged, -1, nil);
  2200. end;
  2201. end;
  2202. function TTBCustomItem.FixOptions(const AOptions: TTBItemOptions): TTBItemOptions;
  2203. begin
  2204. Result := AOptions;
  2205. if not(tboToolbarStyle in Result) then
  2206. Exclude(Result, tboToolbarSize);
  2207. end;
  2208. procedure TTBCustomItem.RefreshOptions;
  2209. const
  2210. NonInheritedOptions = [tboDefault];
  2211. ChangeOptions = [tboDefault, tboDropdownArrow, tboImageAboveCaption,
  2212. tboNoRotation, tboSameWidth, tboToolbarStyle, tboToolbarSize];
  2213. var
  2214. OldOptions, NewOptions: TTBItemOptions;
  2215. I: Integer;
  2216. Item: TTBCustomItem;
  2217. begin
  2218. OldOptions := FEffectiveOptions;
  2219. if FInheritOptions and Assigned(FParent) then
  2220. NewOptions := FParent.FEffectiveOptions - NonInheritedOptions
  2221. else
  2222. NewOptions := [];
  2223. NewOptions := FixOptions(NewOptions - FMaskOptions + FOptions);
  2224. if FEffectiveOptions <> NewOptions then begin
  2225. FEffectiveOptions := NewOptions;
  2226. if (OldOptions * ChangeOptions) <> (NewOptions * ChangeOptions) then
  2227. Change(True);
  2228. for I := 0 to FItemCount-1 do begin
  2229. Item := FItems[I].Item;
  2230. if Item.FInheritOptions then
  2231. Item.RefreshOptions;
  2232. end;
  2233. end;
  2234. end;
  2235. procedure TTBCustomItem.SetMaskOptions(Value: TTBItemOptions);
  2236. begin
  2237. if FMaskOptions <> Value then begin
  2238. FMaskOptions := Value;
  2239. RefreshOptions;
  2240. end;
  2241. end;
  2242. procedure TTBCustomItem.SetOptions(Value: TTBItemOptions);
  2243. begin
  2244. Value := FixOptions(Value);
  2245. if FOptions <> Value then begin
  2246. FOptions := Value;
  2247. RefreshOptions;
  2248. end;
  2249. end;
  2250. procedure TTBCustomItem.SetRadioItem(Value: Boolean);
  2251. begin
  2252. if FRadioItem <> Value then begin
  2253. FRadioItem := Value;
  2254. Change(False);
  2255. end;
  2256. end;
  2257. procedure TTBCustomItem.SetVisible(Value: Boolean);
  2258. begin
  2259. if FVisible <> Value then begin
  2260. FVisible := Value;
  2261. Change(True);
  2262. end;
  2263. end;
  2264. { TTBGroupItem }
  2265. constructor TTBGroupItem.Create(AOwner: TComponent);
  2266. begin
  2267. inherited;
  2268. ItemStyle := ItemStyle + [tbisEmbeddedGroup, tbisSubitemsEditable];
  2269. end;
  2270. { TTBSubmenuItem }
  2271. constructor TTBSubmenuItem.Create(AOwner: TComponent);
  2272. begin
  2273. inherited;
  2274. ItemStyle := ItemStyle + [tbisSubMenu, tbisSubitemsEditable];
  2275. end;
  2276. function TTBSubmenuItem.GetDropdownCombo: Boolean;
  2277. begin
  2278. Result := tbisCombo in ItemStyle;
  2279. end;
  2280. procedure TTBSubmenuItem.SetDropdownCombo(Value: Boolean);
  2281. begin
  2282. if (tbisCombo in ItemStyle) <> Value then begin
  2283. if Value then
  2284. ItemStyle := ItemStyle + [tbisCombo]
  2285. else
  2286. ItemStyle := ItemStyle - [tbisCombo];
  2287. Change(True);
  2288. end;
  2289. end;
  2290. { TTBSeparatorItem }
  2291. constructor TTBSeparatorItem.Create(AOwner: TComponent);
  2292. begin
  2293. inherited;
  2294. ItemStyle := ItemStyle - [tbisSelectable, tbisRedrawOnSelChange,
  2295. tbisRedrawOnMouseOverChange] + [tbisSeparator, tbisClicksTransparent];
  2296. end;
  2297. function TTBSeparatorItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  2298. begin
  2299. Result := TTBSeparatorItemViewer;
  2300. end;
  2301. procedure TTBSeparatorItem.SetBlank(Value: Boolean);
  2302. begin
  2303. if FBlank <> Value then begin
  2304. FBlank := Value;
  2305. Change(False);
  2306. end;
  2307. end;
  2308. { TTBSeparatorItemViewer }
  2309. procedure TTBSeparatorItemViewer.CalcSize(const Canvas: TCanvas;
  2310. var AWidth, AHeight: Integer);
  2311. begin
  2312. if not IsToolbarStyle then
  2313. Inc(AHeight, DivRoundUp(GetTextHeight(Canvas.Handle) * 2, 3))
  2314. else begin
  2315. AWidth := 6;
  2316. AHeight := 6;
  2317. end;
  2318. end;
  2319. procedure TTBSeparatorItemViewer.Paint(const Canvas: TCanvas;
  2320. const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
  2321. var
  2322. DC: HDC;
  2323. R: TRect;
  2324. ToolbarStyle, Horiz, LineSep: Boolean;
  2325. begin
  2326. DC := Canvas.Handle;
  2327. if TTBSeparatorItem(Item).FBlank then
  2328. Exit;
  2329. R := ClientAreaRect;
  2330. ToolbarStyle := IsToolbarStyle;
  2331. Horiz := not ToolbarStyle or (View.FOrientation = tbvoVertical);
  2332. LineSep := tbisLineSep in State;
  2333. if LineSep then
  2334. Horiz := not Horiz;
  2335. if Horiz then begin
  2336. R.Top := R.Bottom div 2 - 1;
  2337. if not ToolbarStyle then
  2338. InflateRect(R, -tbMenuSeparatorOffset, 0)
  2339. else if LineSep then begin
  2340. if View.FOrientation = tbvoFloating then
  2341. InflateRect(R, -tbLineSepOffset, 0)
  2342. else
  2343. InflateRect(R, -tbDockedLineSepOffset, 0);
  2344. end;
  2345. DrawEdge(DC, R, EDGE_ETCHED, BF_TOP);
  2346. end
  2347. else begin
  2348. R.Left := R.Right div 2 - 1;
  2349. if LineSep then
  2350. InflateRect(R, 0, -tbDockedLineSepOffset);
  2351. DrawEdge(DC, R, EDGE_ETCHED, BF_LEFT);
  2352. end;
  2353. end;
  2354. function TTBSeparatorItemViewer.UsesSameWidth: Boolean;
  2355. begin
  2356. Result := False;
  2357. end;
  2358. { TTBControlItem }
  2359. constructor TTBControlItem.Create(AOwner: TComponent);
  2360. begin
  2361. inherited;
  2362. ItemStyle := ItemStyle - [tbisSelectable] + [tbisClicksTransparent];
  2363. end;
  2364. constructor TTBControlItem.CreateControlItem(AOwner: TComponent;
  2365. AControl: TControl);
  2366. begin
  2367. FControl := AControl;
  2368. AControl.FreeNotification(Self);
  2369. Create(AOwner);
  2370. end;
  2371. destructor TTBControlItem.Destroy;
  2372. begin
  2373. inherited;
  2374. { Free the associated control *after* the item is completely destroyed }
  2375. if not FDontFreeControl and Assigned(FControl) and
  2376. not(csAncestor in FControl.ComponentState) then
  2377. FControl.Free;
  2378. end;
  2379. procedure TTBControlItem.Notification(AComponent: TComponent;
  2380. Operation: TOperation);
  2381. begin
  2382. inherited;
  2383. if (Operation = opRemove) and (AComponent = FControl) then
  2384. Control := nil;
  2385. end;
  2386. procedure TTBControlItem.SetControl(Value: TControl);
  2387. begin
  2388. if FControl <> Value then begin
  2389. FControl := Value;
  2390. if Assigned(Value) then
  2391. Value.FreeNotification(Self);
  2392. Change(True);
  2393. end;
  2394. end;
  2395. { TTBItemViewer }
  2396. constructor TTBItemViewer.Create(AView: TTBView; AItem: TTBCustomItem;
  2397. AGroupLevel: Integer);
  2398. begin
  2399. FItem := AItem;
  2400. FView := AView;
  2401. FGroupLevel := AGroupLevel;
  2402. ReferenceClickWnd;
  2403. end;
  2404. destructor TTBItemViewer.Destroy;
  2405. begin
  2406. RemoveFromClickList(Self);
  2407. if Assigned(FAccObjectInstance) then begin
  2408. FAccObjectInstance.ClientIsDestroying;
  2409. FAccObjectInstance := nil;
  2410. end;
  2411. inherited;
  2412. ReleaseClickWnd;
  2413. end;
  2414. function TTBItemViewer.GetAccObject: IDispatch;
  2415. begin
  2416. if FAccObjectInstance = nil then begin
  2417. if not InitializeOleAcc then begin
  2418. Result := nil;
  2419. Exit;
  2420. end;
  2421. FAccObjectInstance := TTBItemViewerAccObject.Create(Self);
  2422. end;
  2423. Result := FAccObjectInstance;
  2424. end;
  2425. procedure TTBItemViewer.AccSelect(const AExecute: Boolean);
  2426. { Called by ClickWndProc when an item of type TTBItemViewer is in ClickList }
  2427. var
  2428. Obj: IDispatch;
  2429. begin
  2430. { Ensure FAccObjectInstance is created by calling GetAccObject }
  2431. Obj := GetAccObject;
  2432. if Assigned(Obj) then
  2433. (FAccObjectInstance as TTBItemViewerAccObject).HandleAccSelect(AExecute);
  2434. end;
  2435. procedure TTBItemViewer.PostAccSelect(const AExecute: Boolean);
  2436. { Internally called by TTBItemViewerAccObject. Don't call directly. }
  2437. begin
  2438. QueueClick(Self, Ord(AExecute));
  2439. end;
  2440. function TTBItemViewer.IsAccessible: Boolean;
  2441. { Returns True if MSAA clients should know about the viewer, specifically
  2442. if it's either shown, off-edge, or clipped (in other words, not completely
  2443. invisible/inaccessible). }
  2444. begin
  2445. { Note: Can't simply check Item.Visible because the chevron item's Visible
  2446. property is always True }
  2447. Result := Show or OffEdge or Clipped;
  2448. end;
  2449. function TTBItemViewer.GetCaptionText: String;
  2450. var
  2451. P: Integer;
  2452. begin
  2453. Result := Item.Caption;
  2454. P := Pos(#9, Result);
  2455. if P <> 0 then
  2456. SetLength(Result, P-1);
  2457. end;
  2458. function TTBItemViewer.GetHintText: String;
  2459. var P: Integer;
  2460. begin
  2461. Result := GetShortHint(Item.Hint);
  2462. { If there is no short hint, use the caption for the hint. Like Office,
  2463. strip any trailing colon or ellipsis. }
  2464. if (Result = '') and not(tboNoAutoHint in Item.EffectiveOptions) and
  2465. (not(tbisSubmenu in Item.ItemStyle) or (tbisCombo in Item.ItemStyle) or
  2466. not CaptionShown) then
  2467. Result := StripAccelChars(StripTrailingPunctuation(GetCaptionText));
  2468. { Call associated action's OnHint event handler to post-process the hint }
  2469. if Assigned(Item.ActionLink) and
  2470. (Item.ActionLink.Action is TCustomAction) then begin
  2471. if not TCustomAction(Item.ActionLink.Action).DoHint(Result) then
  2472. Result := '';
  2473. { Note: TControlActionLink.DoShowHint actually misinterprets the result
  2474. of DoHint, but we get it right... }
  2475. end;
  2476. { Add shortcut text }
  2477. if (Result <> '') and Application.HintShortCuts then
  2478. begin
  2479. { Custom shortcut }
  2480. P := Pos(#9, Item.Caption);
  2481. if (P <> 0) and (P < Length(Item.Caption)) then
  2482. Result := Format('%s (%s)', [Result, Copy(Item.Caption, P+ 1, MaxInt)])
  2483. else
  2484. if (Item.ShortCut <> scNone) then
  2485. Result := Format('%s (%s)', [Result, ShortCutToText(Item.ShortCut)]);
  2486. end;
  2487. end;
  2488. function TTBItemViewer.CaptionShown: Boolean;
  2489. begin
  2490. Result := (GetCaptionText <> '') and (not IsToolbarSize or
  2491. (Item.ImageIndex < 0) or (Item.DisplayMode in [nbdmTextOnly, nbdmImageAndText])) or
  2492. (tboImageAboveCaption in Item.EffectiveOptions);
  2493. end;
  2494. function TTBItemViewer.ImageShown: Boolean;
  2495. begin
  2496. {}{should also return false if Images=nil (use UsedImageList?)}
  2497. ImageShown := (Item.ImageIndex >= 0) and
  2498. ((Item.DisplayMode in [nbdmDefault, nbdmImageAndText]) or
  2499. (IsToolbarStyle and (Item.DisplayMode = nbdmTextOnlyInMenus)));
  2500. end;
  2501. function TTBItemViewer.GetImageList: TCustomImageList;
  2502. var
  2503. V: TTBView;
  2504. begin
  2505. Result := Item.Images;
  2506. if Assigned(Result) then
  2507. Exit;
  2508. V := View;
  2509. repeat
  2510. if Assigned(V.FCurParentItem) then begin
  2511. Result := V.FCurParentItem.SubMenuImages;
  2512. if Assigned(Result) then
  2513. Break;
  2514. end;
  2515. if Assigned(V.FParentItem) then begin
  2516. Result := V.FParentItem.SubMenuImages;
  2517. if Assigned(Result) then
  2518. Break;
  2519. end;
  2520. V := V.FParentView;
  2521. until V = nil;
  2522. end;
  2523. function TTBItemViewer.IsRotated: Boolean;
  2524. { Returns True if the caption should be drawn with rotated (vertical) text,
  2525. underneath the image }
  2526. begin
  2527. Result := (View.Orientation = tbvoVertical) and
  2528. not (tboNoRotation in Item.EffectiveOptions) and
  2529. not (tboImageAboveCaption in Item.EffectiveOptions);
  2530. end;
  2531. procedure TTBItemViewer.CalcSize(const Canvas: TCanvas;
  2532. var AWidth, AHeight: Integer);
  2533. var
  2534. ToolbarStyle: Boolean;
  2535. DC: HDC;
  2536. TextMetrics: TTextMetric;
  2537. H, LeftMargin: Integer;
  2538. ImgList: TCustomImageList;
  2539. S: String;
  2540. RotatedFont, SaveFont: HFONT;
  2541. begin
  2542. ToolbarStyle := IsToolbarStyle;
  2543. DC := Canvas.Handle;
  2544. ImgList := GetImageList;
  2545. if ToolbarStyle then begin
  2546. AWidth := 6;
  2547. AHeight := 6;
  2548. end
  2549. else begin
  2550. AWidth := 0;
  2551. AHeight := 0;
  2552. end;
  2553. if not ToolbarStyle or CaptionShown then begin
  2554. if not IsRotated then begin
  2555. GetTextMetrics(DC, TextMetrics);
  2556. Inc(AHeight, TextMetrics.tmHeight);
  2557. Inc(AWidth, GetTextWidth(DC, GetCaptionText, True));
  2558. if ToolbarStyle then
  2559. Inc(AWidth, 6);
  2560. end
  2561. else begin
  2562. { Vertical text isn't always the same size as horizontal text, so we have
  2563. to select the rotated font into the DC to get an accurate size }
  2564. RotatedFont := CreateRotatedFont(DC);
  2565. SaveFont := SelectObject(DC, RotatedFont);
  2566. GetTextMetrics(DC, TextMetrics);
  2567. Inc(AWidth, TextMetrics.tmHeight);
  2568. Inc(AHeight, GetTextWidth(DC, GetCaptionText, True));
  2569. if ToolbarStyle then
  2570. Inc(AHeight, 6);
  2571. SelectObject(DC, SaveFont);
  2572. DeleteObject(RotatedFont);
  2573. end;
  2574. end;
  2575. if ToolbarStyle and ImageShown and Assigned(ImgList) then begin
  2576. if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then begin
  2577. Inc(AWidth, ImgList.Width + 1);
  2578. if AHeight < ImgList.Height + 6 then
  2579. AHeight := ImgList.Height + 6;
  2580. end
  2581. else begin
  2582. Inc(AHeight, ImgList.Height);
  2583. if AWidth < ImgList.Width + 7 then
  2584. AWidth := ImgList.Width + 7;
  2585. end;
  2586. end;
  2587. if ToolbarStyle and (tbisSubmenu in Item.ItemStyle) then begin
  2588. if tbisCombo in Item.ItemStyle then
  2589. Inc(AWidth, tbDropdownComboArrowWidth)
  2590. else
  2591. if tboDropdownArrow in Item.EffectiveOptions then begin
  2592. if View.Orientation <> tbvoVertical then
  2593. Inc(AWidth, tbDropdownArrowWidth)
  2594. else
  2595. Inc(AHeight, tbDropdownArrowWidth);
  2596. end;
  2597. end;
  2598. if not ToolbarStyle then begin
  2599. Inc(AHeight, TextMetrics.tmExternalLeading + tbMenuVerticalMargin);
  2600. if Assigned(ImgList) then begin
  2601. H := ImgList.Height + 3;
  2602. if H > AHeight then
  2603. AHeight := H;
  2604. LeftMargin := MulDiv(ImgList.Width + 3, AHeight, H);
  2605. end
  2606. else
  2607. LeftMargin := AHeight;
  2608. Inc(AWidth, LeftMargin + tbMenuImageTextSpace + tbMenuLeftTextMargin +
  2609. tbMenuRightTextMargin);
  2610. S := Item.GetShortCutText;
  2611. if S <> '' then
  2612. Inc(AWidth, (AHeight - 6) + GetTextWidth(DC, S, True));
  2613. Inc(AWidth, AHeight);
  2614. end;
  2615. end;
  2616. procedure TTBItemViewer.DrawItemCaption(const Canvas: TCanvas; ARect: TRect;
  2617. const ACaption: String; ADrawDisabledShadow: Boolean; AFormat: UINT);
  2618. var
  2619. DC: HDC;
  2620. procedure Draw;
  2621. begin
  2622. if not IsRotated then
  2623. DrawText(DC, PChar(ACaption), Length(ACaption), ARect, AFormat)
  2624. else
  2625. DrawRotatedText(DC, ACaption, ARect, AFormat);
  2626. end;
  2627. var
  2628. ShadowColor, HighlightColor, SaveTextColor: DWORD;
  2629. begin
  2630. DC := Canvas.Handle;
  2631. if not ADrawDisabledShadow then
  2632. Draw
  2633. else begin
  2634. ShadowColor := GetSysColor(COLOR_BTNSHADOW);
  2635. HighlightColor := GetSysColor(COLOR_BTNHIGHLIGHT);
  2636. OffsetRect(ARect, 1, 1);
  2637. SaveTextColor := SetTextColor(DC, HighlightColor);
  2638. Draw;
  2639. OffsetRect(ARect, -1, -1);
  2640. SetTextColor(DC, ShadowColor);
  2641. Draw;
  2642. SetTextColor(DC, SaveTextColor);
  2643. end;
  2644. end;
  2645. procedure TTBItemViewer.Paint(const Canvas: TCanvas;
  2646. const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
  2647. var
  2648. ShowEnabled, HasArrow: Boolean;
  2649. MenuCheckWidth, MenuCheckHeight: Integer;
  2650. function GetDrawTextFlags: UINT;
  2651. begin
  2652. Result := 0;
  2653. if not AreKeyboardCuesEnabled and (vsUseHiddenAccels in View.FStyle) and
  2654. not(vsShowAccels in View.FState) then
  2655. Result := DT_HIDEPREFIX;
  2656. end;
  2657. procedure DrawSubmenuArrow;
  2658. var
  2659. BR: TRect;
  2660. Bmp: TBitmap;
  2661. procedure DrawWithColor(AColor: TColor);
  2662. const
  2663. ROP_DSPDxax = $00E20746;
  2664. var
  2665. DC: HDC;
  2666. SaveTextColor, SaveBkColor: TColorRef;
  2667. begin
  2668. Canvas.Brush.Color := AColor;
  2669. DC := Canvas.Handle;
  2670. SaveTextColor := SetTextColor(DC, clWhite);
  2671. SaveBkColor := SetBkColor(DC, clBlack);
  2672. BitBlt(DC, BR.Left, BR.Top, MenuCheckWidth, MenuCheckHeight,
  2673. Bmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  2674. SetBkColor(DC, SaveBkColor);
  2675. SetTextColor(DC, SaveTextColor);
  2676. Canvas.Brush.Style := bsClear;
  2677. end;
  2678. begin
  2679. Bmp := TBitmap.Create;
  2680. try
  2681. Bmp.Monochrome := True;
  2682. Bmp.Width := MenuCheckWidth;
  2683. Bmp.Height := MenuCheckHeight;
  2684. BR := Rect(0, 0, MenuCheckWidth, MenuCheckHeight);
  2685. DrawFrameControl(Bmp.Canvas.Handle, BR, DFC_MENU, DFCS_MENUARROW);
  2686. OffsetRect(BR, ClientAreaRect.Right - MenuCheckWidth,
  2687. ClientAreaRect.Top + ((ClientAreaRect.Bottom - ClientAreaRect.Top) - MenuCheckHeight) div 2);
  2688. if not UseDisabledShadow then begin
  2689. if ShowEnabled and (tbisCombo in Item.ItemStyle) and IsSelected then begin
  2690. OffsetRect(BR, 1, 1);
  2691. DrawWithColor(clBtnText);
  2692. end
  2693. else
  2694. DrawWithColor(Canvas.Font.Color);
  2695. end
  2696. else begin
  2697. OffsetRect(BR, 1, 1);
  2698. DrawWithColor(clBtnHighlight);
  2699. OffsetRect(BR, -1, -1);
  2700. DrawWithColor(clBtnShadow);
  2701. end;
  2702. finally
  2703. Bmp.Free;
  2704. end;
  2705. end;
  2706. procedure DrawDropdownArrow(R: TRect; Rotated: Boolean);
  2707. procedure DrawWithColor(AColor: TColor);
  2708. var
  2709. X, Y: Integer;
  2710. P: array[0..2] of TPoint;
  2711. begin
  2712. X := (R.Left + R.Right) div 2;
  2713. Y := (R.Top + R.Bottom) div 2;
  2714. if not Rotated then begin
  2715. Dec(Y);
  2716. P[0].X := X-2;
  2717. P[0].Y := Y;
  2718. P[1].X := X+2;
  2719. P[1].Y := Y;
  2720. P[2].X := X;
  2721. P[2].Y := Y+2;
  2722. end
  2723. else begin
  2724. Dec(X);
  2725. P[0].X := X;
  2726. P[0].Y := Y+2;
  2727. P[1].X := X;
  2728. P[1].Y := Y-2;
  2729. P[2].X := X-2;
  2730. P[2].Y := Y;
  2731. end;
  2732. Canvas.Pen.Color := AColor;
  2733. Canvas.Brush.Color := AColor;
  2734. Canvas.Polygon(P);
  2735. end;
  2736. begin
  2737. if not UseDisabledShadow then
  2738. DrawWithColor(Canvas.Font.Color)
  2739. else begin
  2740. OffsetRect(R, 1, 1);
  2741. DrawWithColor(clBtnHighlight);
  2742. OffsetRect(R, -1, -1);
  2743. DrawWithColor(clBtnShadow);
  2744. end;
  2745. end;
  2746. function GetDitherBitmap: TBitmap;
  2747. begin
  2748. Result := AllocPatternBitmap(clBtnFace, clBtnHighlight);
  2749. Result.HandleType := bmDDB; { needed for Win95, or else brush is solid white }
  2750. end;
  2751. const
  2752. EdgeStyles: array[Boolean] of UINT = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
  2753. CheckMarkPoints: array[0..11] of TPoint = (
  2754. { Black }
  2755. (X: -2; Y: -2), (X: 0; Y: 0), (X: 4; Y: -4),
  2756. (X: 4; Y: -3), (X: 0; Y: 1), (X: -2; Y: -1),
  2757. (X: -2; Y: -2),
  2758. { White }
  2759. (X: -3; Y: -2), (X: -3; Y: -1), (X: 0; Y: 2),
  2760. (X: 5; Y: -3), (X: 5; Y: -5));
  2761. var
  2762. ToolbarStyle, ImageIsShown: Boolean;
  2763. R, RC, RD: TRect;
  2764. S: String;
  2765. ImgList: TCustomImageList;
  2766. I, X, Y: Integer;
  2767. Points: array[0..11] of TPoint;
  2768. DrawTextFlags: UINT;
  2769. LeftMargin: Integer;
  2770. TextMetrics: TTextMetric;
  2771. begin
  2772. ToolbarStyle := IsToolbarStyle;
  2773. ShowEnabled := Item.Enabled or View.Customizing;
  2774. HasArrow := (tbisSubmenu in Item.ItemStyle) and
  2775. ((tbisCombo in Item.ItemStyle) or (tboDropdownArrow in Item.EffectiveOptions));
  2776. MenuCheckWidth := GetSystemMetrics(SM_CXMENUCHECK);
  2777. MenuCheckHeight := GetSystemMetrics(SM_CYMENUCHECK);
  2778. ImgList := GetImageList;
  2779. ImageIsShown := ImageShown and Assigned(ImgList);
  2780. LeftMargin := 0;
  2781. if not ToolbarStyle then begin
  2782. if Assigned(ImgList) then
  2783. LeftMargin := MulDiv(ImgList.Width + 3, ClientAreaRect.Bottom, ImgList.Height + 3)
  2784. else
  2785. LeftMargin := ClientAreaRect.Bottom;
  2786. end;
  2787. { Border }
  2788. RC := ClientAreaRect;
  2789. if ToolbarStyle then begin
  2790. if HasArrow then begin
  2791. if tbisCombo in Item.ItemStyle then begin
  2792. Dec(RC.Right, tbDropdownComboMargin);
  2793. RD := RC;
  2794. Dec(RC.Right, tbDropdownComboArrowWidth - tbDropdownComboMargin);
  2795. RD.Left := RC.Right;
  2796. end
  2797. else begin
  2798. if View.Orientation <> tbvoVertical then
  2799. RD := Rect(RC.Right - tbDropdownArrowWidth - tbDropdownArrowMargin, 0,
  2800. RC.Right - tbDropdownArrowMargin, RC.Bottom)
  2801. else
  2802. RD := Rect(0, RC.Bottom - tbDropdownArrowWidth - tbDropdownArrowMargin,
  2803. RC.Right, RC.Bottom - tbDropdownArrowMargin);
  2804. end;
  2805. end
  2806. else
  2807. SetRectEmpty(RD);
  2808. if (IsSelected and ShowEnabled) or Item.Checked or
  2809. (csDesigning in Item.ComponentState) then begin
  2810. if not(tbisCombo in Item.ItemStyle) then
  2811. DrawEdge(Canvas.Handle, RC, EdgeStyles[IsPushed or Item.Checked], BF_RECT)
  2812. else begin
  2813. DrawEdge(Canvas.Handle, RC, EdgeStyles[(IsPushed and View.FCapture) or Item.Checked], BF_RECT);
  2814. if (IsSelected and ShowEnabled) or
  2815. (csDesigning in Item.ComponentState) then
  2816. DrawEdge(Canvas.Handle, RD, EdgeStyles[IsPushed and not View.FCapture], BF_RECT);
  2817. end;
  2818. end;
  2819. if HasArrow then begin
  2820. if not(tbisCombo in Item.ItemStyle) and IsPushed then
  2821. OffsetRect(RD, 1, 1);
  2822. DrawDropdownArrow(RD, not(tbisCombo in Item.ItemStyle) and
  2823. (View.Orientation = tbvoVertical));
  2824. end;
  2825. InflateRect(RC, -1, -1);
  2826. if Item.Checked and not (IsSelected and ShowEnabled) then begin
  2827. Canvas.Brush.Bitmap := GetDitherBitmap;
  2828. Canvas.FillRect(RC);
  2829. Canvas.Brush.Style := bsClear;
  2830. end;
  2831. InflateRect(RC, -1, -1);
  2832. if Item.Checked or
  2833. ((IsSelected and IsPushed) and
  2834. (not(tbisCombo in Item.ItemStyle) or View.FCapture)) then
  2835. OffsetRect(RC, 1, 1);
  2836. if HasArrow and not(tbisCombo in Item.ItemStyle) then begin
  2837. if View.Orientation <> tbvoVertical then
  2838. Dec(RC.Right, tbDropdownArrowWidth)
  2839. else
  2840. Dec(RC.Bottom, tbDropdownArrowWidth);
  2841. end;
  2842. end
  2843. else begin
  2844. { On selected menu items, fill the background with the selected color.
  2845. Note: This assumes the brush color was not changed from the initial
  2846. value. }
  2847. if IsSelected then begin
  2848. R := RC;
  2849. if ImageIsShown or Item.Checked then
  2850. Inc(R.Left, LeftMargin + tbMenuImageTextSpace);
  2851. if (tbisCombo in Item.ItemStyle) and IsSelected and ShowEnabled then
  2852. Dec(R.Right, MenuCheckWidth);
  2853. Canvas.FillRect(R);
  2854. end;
  2855. end;
  2856. { Adjust brush & font }
  2857. Canvas.Brush.Style := bsClear;
  2858. if tboDefault in Item.EffectiveOptions then
  2859. with Canvas.Font do Style := Style + [fsBold];
  2860. GetTextMetrics(Canvas.Handle, TextMetrics);
  2861. { Caption }
  2862. if CaptionShown then begin
  2863. S := GetCaptionText;
  2864. R := RC;
  2865. DrawTextFlags := GetDrawTextFlags;
  2866. if ToolbarStyle then begin
  2867. if ImageIsShown then begin
  2868. if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then
  2869. Inc(R.Left, ImgList.Width + 1)
  2870. else
  2871. Inc(R.Top, ImgList.Height + 1);
  2872. end;
  2873. DrawItemCaption(Canvas, R, S, UseDisabledShadow,
  2874. DT_SINGLELINE or DT_CENTER or DT_VCENTER or DrawTextFlags)
  2875. end
  2876. else begin
  2877. Inc(R.Left, LeftMargin + tbMenuImageTextSpace + tbMenuLeftTextMargin);
  2878. { Like standard menus, shift the text up one pixel if the text height
  2879. is 4 pixels less than the total item height. This is done so underlined
  2880. characters aren't displayed too low. }
  2881. if (R.Bottom - R.Top) - (TextMetrics.tmHeight + TextMetrics.tmExternalLeading) = tbMenuVerticalMargin then
  2882. Dec(R.Bottom);
  2883. Inc(R.Top, TextMetrics.tmExternalLeading);
  2884. DrawItemCaption(Canvas, R, S, UseDisabledShadow,
  2885. DT_SINGLELINE or DT_LEFT or DT_VCENTER or DrawTextFlags);
  2886. end;
  2887. end;
  2888. { Shortcut and/or submenu arrow (menus only) }
  2889. if not ToolbarStyle then begin
  2890. S := Item.GetShortCutText;
  2891. if S <> '' then begin
  2892. R := RC;
  2893. R.Left := R.Right - (R.Bottom - R.Top) - GetTextWidth(Canvas.Handle, S, True);
  2894. { Like standard menus, shift the text up one pixel if the text height
  2895. is 4 pixels less than the total item height. This is done so underlined
  2896. characters aren't displayed too low. }
  2897. if (R.Bottom - R.Top) - (TextMetrics.tmHeight + TextMetrics.tmExternalLeading) = tbMenuVerticalMargin then
  2898. Dec(R.Bottom);
  2899. Inc(R.Top, TextMetrics.tmExternalLeading);
  2900. DrawItemCaption(Canvas, R, S, UseDisabledShadow,
  2901. DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_NOPREFIX);
  2902. end;
  2903. if tbisSubmenu in Item.ItemStyle then begin
  2904. if tbisCombo in Item.ItemStyle then begin
  2905. R := RC;
  2906. R.Left := R.Right - MenuCheckWidth;
  2907. if IsSelected and ShowEnabled then
  2908. DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_RECT or BF_MIDDLE)
  2909. else begin
  2910. Dec(R.Left);
  2911. if not IsSelected then
  2912. DrawEdge(Canvas.Handle, R, EDGE_ETCHED, BF_LEFT)
  2913. else
  2914. DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_LEFT);
  2915. end;
  2916. end;
  2917. DrawSubmenuArrow;
  2918. end;
  2919. end;
  2920. { Image, or check box }
  2921. if ImageIsShown or (not ToolbarStyle and Item.Checked) then begin
  2922. R := RC;
  2923. if ToolbarStyle then begin
  2924. if not IsRotated and not(tboImageAboveCaption in Item.EffectiveOptions) then
  2925. R.Right := R.Left + ImgList.Width + 2
  2926. else
  2927. R.Bottom := R.Top + ImgList.Height + 2;
  2928. end
  2929. else begin
  2930. R.Right := R.Left + LeftMargin;
  2931. if (IsSelected and ShowEnabled) or Item.Checked then
  2932. DrawEdge(Canvas.Handle, R, EdgeStyles[Item.Checked], BF_RECT or BF_MIDDLE);
  2933. if Item.Checked and not IsSelected then begin
  2934. InflateRect(R, -1, -1);
  2935. Canvas.Brush.Bitmap := GetDitherBitmap;
  2936. Canvas.FillRect(R);
  2937. Canvas.Brush.Style := bsClear;
  2938. InflateRect(R, 1, 1);
  2939. end;
  2940. if Item.Checked then
  2941. OffsetRect(R, 1, 1);
  2942. end;
  2943. if ImageIsShown then begin
  2944. X := R.Left + ((R.Right - R.Left) - ImgList.Width) div 2;
  2945. Y := R.Top + ((R.Bottom - R.Top) - ImgList.Height) div 2;
  2946. if ImgList is TTBCustomImageList then
  2947. TTBCustomImageList(ImgList).DrawState(Canvas, X, Y, Item.ImageIndex,
  2948. ShowEnabled, IsSelected, Item.Checked)
  2949. else
  2950. ImgList.Draw(Canvas, X, Y, Item.ImageIndex, ShowEnabled);
  2951. end
  2952. else
  2953. if not ToolbarStyle and Item.Checked then begin
  2954. { Draw default check mark or radio button image when user hasn't
  2955. specified their own }
  2956. X := (R.Left + R.Right) div 2;
  2957. Y := (R.Top + R.Bottom) div 2;
  2958. if Item.RadioItem then begin
  2959. Canvas.Pen.Color := clBtnText;
  2960. Canvas.Brush.Color := clBtnText;
  2961. Canvas.RoundRect(X-3, Y-3, X+2, Y+2, 2, 2);
  2962. Canvas.Pen.Color := clBtnHighlight;
  2963. Canvas.Brush.Style := bsClear;
  2964. Canvas.RoundRect(X-4, Y-4, X+3, Y+3, 6, 6);
  2965. end
  2966. else begin
  2967. Dec(X, 2);
  2968. Inc(Y);
  2969. System.Move(CheckMarkPoints, Points, 12 * SizeOf(TPoint));
  2970. for I := Low(Points) to High(Points) do begin
  2971. Inc(Points[I].X, X);
  2972. Inc(Points[I].Y, Y);
  2973. end;
  2974. Canvas.Pen.Color := clBtnText;
  2975. Polyline(Canvas.Handle, Points[0], 7);
  2976. Canvas.Pen.Color := clBtnHighlight;
  2977. Polyline(Canvas.Handle, Points[7], 5);
  2978. end;
  2979. end;
  2980. end;
  2981. end;
  2982. procedure TTBItemViewer.GetCursor(const Pt: TPoint; var ACursor: HCURSOR);
  2983. begin
  2984. end;
  2985. function TTBItemViewer.GetIndex: Integer;
  2986. begin
  2987. Result := View.IndexOf(Self);
  2988. end;
  2989. function TTBItemViewer.IsToolbarSize: Boolean;
  2990. begin
  2991. Result := View.FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
  2992. end;
  2993. function TTBItemViewer.IsToolbarStyle: Boolean;
  2994. begin
  2995. Result := View.FIsToolbar or (tboToolbarStyle in Item.FEffectiveOptions);
  2996. end;
  2997. function TTBItemViewer.IsPtInButtonPart(X, Y: Integer): Boolean;
  2998. var
  2999. W: Integer;
  3000. begin
  3001. Result := not(tbisSubmenu in Item.ItemStyle);
  3002. if tbisCombo in Item.ItemStyle then begin
  3003. if IsToolbarStyle then
  3004. W := tbDropdownComboArrowWidth
  3005. else
  3006. W := GetSystemMetrics(SM_CXMENUCHECK);
  3007. Result := X < (BoundsRect.Right - BoundsRect.Left) - W;
  3008. end;
  3009. end;
  3010. procedure TTBItemViewer.MouseDown(Shift: TShiftState; X, Y: Integer;
  3011. var MouseDownOnMenu: Boolean);
  3012. procedure HandleDefaultDoubleClick(const View: TTBView);
  3013. { Looks for a tboDefault item in View and ends the modal loop if it finds
  3014. one. }
  3015. var
  3016. I: Integer;
  3017. Viewer: TTBItemViewer;
  3018. Item: TTBCustomItem;
  3019. begin
  3020. for I := 0 to View.FViewerCount-1 do begin
  3021. Viewer := View.FViewers[I];
  3022. Item := Viewer.Item;
  3023. if (Viewer.Show or Viewer.Clipped) and (tboDefault in Item.EffectiveOptions) and
  3024. (tbisSelectable in Item.ItemStyle) and Item.Enabled and Item.Visible then begin
  3025. Viewer.Execute(True);
  3026. Break;
  3027. end;
  3028. end;
  3029. end;
  3030. var
  3031. WasAlreadyOpen: Boolean;
  3032. begin
  3033. if not Item.Enabled then begin
  3034. if (View.FParentView = nil) and not View.FIsPopup then
  3035. View.EndModal;
  3036. Exit;
  3037. end;
  3038. if IsPtInButtonPart(X, Y) then begin
  3039. if IsToolbarStyle then begin
  3040. View.CancelChildPopups;
  3041. View.SetCapture;
  3042. View.Invalidate(Self);
  3043. end;
  3044. end
  3045. else begin
  3046. WasAlreadyOpen := (View.FOpenViewer = Self);
  3047. if View.OpenChildPopup(False) then begin
  3048. if WasAlreadyOpen and ((View.FParentView = nil) and not View.FIsPopup) then
  3049. MouseDownOnMenu := True;
  3050. if (ssDouble in Shift) and not(tbisCombo in Item.ItemStyle) then
  3051. HandleDefaultDoubleClick(View.FOpenViewerView);
  3052. end;
  3053. end;
  3054. end;
  3055. procedure TTBItemViewer.MouseMove(X, Y: Integer);
  3056. begin
  3057. end;
  3058. procedure TTBItemViewer.MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean);
  3059. var
  3060. HadCapture, IsToolbarItem: Boolean;
  3061. begin
  3062. HadCapture := View.FCapture;
  3063. View.CancelCapture;
  3064. IsToolbarItem := (View.FParentView = nil) and not View.FIsPopup;
  3065. if not View.FMouseOverSelected or not Item.Enabled or
  3066. (tbisClicksTransparent in Item.ItemStyle) then begin
  3067. if IsToolbarItem then
  3068. View.EndModal;
  3069. Exit;
  3070. end;
  3071. if (tbisSubmenu in Item.ItemStyle) and not IsPtInButtonPart(X, Y) then begin
  3072. if IsToolbarItem and MouseWasDownOnMenu then
  3073. View.EndModal;
  3074. end
  3075. else begin
  3076. { it's a 'normal' item }
  3077. if not IsToolbarStyle or HadCapture then
  3078. Execute(True);
  3079. end;
  3080. end;
  3081. procedure TTBItemViewer.MouseWheel(WheelDelta, X, Y: Integer);
  3082. begin
  3083. end;
  3084. procedure TTBItemViewer.LosingCapture;
  3085. begin
  3086. View.Invalidate(Self);
  3087. end;
  3088. procedure TTBItemViewer.Entering(OldSelected: TTBItemViewer);
  3089. begin
  3090. if Assigned(Item.FOnSelect) then
  3091. Item.FOnSelect(Item, Self, True);
  3092. end;
  3093. procedure TTBItemViewer.Leaving;
  3094. begin
  3095. if Assigned(Item.FOnSelect) then
  3096. Item.FOnSelect(Item, Self, False);
  3097. end;
  3098. procedure TTBItemViewer.KeyDown(var Key: Word; Shift: TShiftState);
  3099. begin
  3100. end;
  3101. function TTBItemViewer.ScreenToClient(const P: TPoint): TPoint;
  3102. begin
  3103. Result := View.FWindow.ScreenToClient(P);
  3104. Dec(Result.X, BoundsRect.Left);
  3105. Dec(Result.Y, BoundsRect.Top);
  3106. end;
  3107. function TTBItemViewer.UsesSameWidth: Boolean;
  3108. { If UsesSameWidth returns True, the item viewer's width will be expanded to
  3109. match the widest item viewer on the same view whose UsesSameWidth method
  3110. also returns True. }
  3111. begin
  3112. Result := (tboImageAboveCaption in Item.FEffectiveOptions) and
  3113. (tboSameWidth in Item.FEffectiveOptions) and IsToolbarSize;
  3114. end;
  3115. function TTBItemViewer.DoExecute: Boolean;
  3116. { Low-level 'execute' handler. Returns True if the caller should call
  3117. GivePriority on the viewer (normally, if the 'execute' operation was a
  3118. success and the modal loop is ending). }
  3119. begin
  3120. View.EndModalWithClick(Self);
  3121. Result := True;
  3122. end;
  3123. procedure TTBItemViewer.Execute(AGivePriority: Boolean);
  3124. { Calls DoExecute and, if applicable, View.GivePriority. Note that it is up to
  3125. the caller to check the viewer's visibility and enabled state. }
  3126. begin
  3127. if DoExecute and AGivePriority then
  3128. View.GivePriority(Self);
  3129. end;
  3130. function TTBItemViewer.GetAccRole: Integer;
  3131. { Returns the MSAA "role" of the viewer. }
  3132. const
  3133. { Constants from OleAcc.h }
  3134. ROLE_SYSTEM_CLIENT = $a;
  3135. ROLE_SYSTEM_MENUITEM = $c;
  3136. ROLE_SYSTEM_SEPARATOR = $15;
  3137. ROLE_SYSTEM_PUSHBUTTON = $2b;
  3138. ROLE_SYSTEM_BUTTONMENU = $39;
  3139. begin
  3140. if Item is TTBControlItem then
  3141. Result := ROLE_SYSTEM_CLIENT
  3142. else if tbisSeparator in Item.ItemStyle then
  3143. Result := ROLE_SYSTEM_SEPARATOR
  3144. else if View.IsPopup or (vsMenuBar in View.Style) then
  3145. Result := ROLE_SYSTEM_MENUITEM
  3146. else if tbisSubmenu in Item.ItemStyle then
  3147. Result := ROLE_SYSTEM_BUTTONMENU
  3148. else
  3149. Result := ROLE_SYSTEM_PUSHBUTTON;
  3150. end;
  3151. function TTBItemViewer.GetAccValue(var Value: WideString): Boolean;
  3152. { Gets the MSAA "value" text of the viewer. Returns True if something was
  3153. assigned to Value, or False if the viewer does not possess a "value". }
  3154. begin
  3155. Result := False;
  3156. end;
  3157. { TTBView }
  3158. constructor TTBView.CreateView(AOwner: TComponent; AParentView: TTBView;
  3159. AParentItem: TTBCustomItem; AWindow: TWinControl;
  3160. AIsToolbar, ACustomizing, AUsePriorityList: Boolean);
  3161. begin
  3162. Create(AOwner);
  3163. FBackgroundColor := clDefault;
  3164. FCustomizing := ACustomizing;
  3165. FIsPopup := not AIsToolbar;
  3166. FIsToolbar := AIsToolbar;
  3167. FNewViewersGetHighestPriority := True;
  3168. FParentView := AParentView;
  3169. FParentItem := AParentItem;
  3170. if Assigned(FParentItem) then begin
  3171. //FIsToolbar := FIsToolbar or FParentItem.FDisplayAsToolbar;
  3172. FParentItem.RegisterNotification(LinkNotification);
  3173. FParentItem.FreeNotification(Self);
  3174. end;
  3175. FUsePriorityList := AUsePriorityList;
  3176. FWindow := AWindow;
  3177. UpdateCurParentItem;
  3178. end;
  3179. destructor TTBView.Destroy;
  3180. begin
  3181. CloseChildPopups;
  3182. if Assigned(FAccObjectInstance) then begin
  3183. FAccObjectInstance.ClientIsDestroying;
  3184. { Get rid of our own reference to FAccObjectInstance. Normally the
  3185. reference count will be now be zero and FAccObjectInstance will be
  3186. freed, unless MSAA still holds a reference. }
  3187. FAccObjectInstance._Release;
  3188. FAccObjectInstance := nil;
  3189. end;
  3190. { If parent view is a toolbar, invalidate the open item so that it's
  3191. redrawn back in the "up" position }
  3192. if Assigned(ParentView) and ParentView.FIsToolbar then begin
  3193. Include(ParentView.FState, vsNoAnimation);
  3194. if Assigned(ParentView.FOpenViewer) then
  3195. ParentView.Invalidate(ParentView.FOpenViewer);
  3196. end;
  3197. if Assigned(FCurParentItem) then
  3198. FCurParentItem.UnregisterNotification(ItemNotification);
  3199. if Assigned(FParentItem) then
  3200. FParentItem.UnregisterNotification(LinkNotification);
  3201. inherited;
  3202. FPriorityList.Free;
  3203. FreeViewers;
  3204. { Now that we're destroyed, "focus" the parent view }
  3205. if Assigned(FParentView) then
  3206. FParentView.NotifyFocusEvent;
  3207. end;
  3208. function TTBView.GetAccObject: IDispatch;
  3209. begin
  3210. if FAccObjectInstance = nil then begin
  3211. if not InitializeOleAcc then begin
  3212. Result := nil;
  3213. Exit;
  3214. end;
  3215. FAccObjectInstance := TTBViewAccObject.Create(Self);
  3216. { Strictly as an optimization, take a reference for ourself and keep it
  3217. for the lifetime of the view. (Destroy calls _Release.) }
  3218. FAccObjectInstance._AddRef;
  3219. end;
  3220. Result := FAccObjectInstance;
  3221. end;
  3222. function TTBView.HandleWMGetObject(var Message: TMessage): Boolean;
  3223. begin
  3224. if (Message.LParam = Integer(OBJID_CLIENT)) and InitializeOleAcc then begin
  3225. Message.Result := LresultFromObjectFunc(ITBAccessible, Message.WParam, GetAccObject);
  3226. Result := True;
  3227. end
  3228. else
  3229. Result := False;
  3230. end;
  3231. procedure TTBView.UpdateCurParentItem;
  3232. var
  3233. Value: TTBCustomItem;
  3234. begin
  3235. Value := ItemContainingItems(FParentItem);
  3236. if FCurParentItem <> Value then begin
  3237. CloseChildPopups;
  3238. if Assigned(FCurParentItem) then
  3239. FCurParentItem.UnregisterNotification(ItemNotification);
  3240. FCurParentItem := Value;
  3241. if Assigned(Value) then
  3242. Value.RegisterNotification(ItemNotification);
  3243. RecreateAllViewers;
  3244. if Assigned(Value) and not(csDesigning in Value.ComponentState) then
  3245. InitiateActions;
  3246. end;
  3247. end;
  3248. procedure TTBView.InitiateActions;
  3249. var
  3250. I: Integer;
  3251. begin
  3252. { Use a 'while' instead of a 'for' since an InitiateAction implementation
  3253. may add/delete items }
  3254. I := 0;
  3255. while I < FViewerCount do begin
  3256. FViewers[I].Item.InitiateAction;
  3257. Inc(I);
  3258. end;
  3259. end;
  3260. procedure TTBView.Notification(AComponent: TComponent; Operation: TOperation);
  3261. begin
  3262. inherited;
  3263. if Operation = opRemove then begin
  3264. if AComponent = FParentItem then begin
  3265. FParentItem := nil;
  3266. UpdateCurParentItem;
  3267. if Assigned(FParentView) then
  3268. FParentView.CloseChildPopups;
  3269. end
  3270. else if AComponent = FOpenViewerWindow then begin
  3271. FOpenViewerWindow := nil;
  3272. FOpenViewerView := nil;
  3273. FOpenViewer := nil;
  3274. end
  3275. else if AComponent = FChevronParentView then
  3276. FChevronParentView := nil;
  3277. end
  3278. end;
  3279. function TTBView.ContainsView(AView: TTBView): Boolean;
  3280. begin
  3281. while Assigned(AView) and (AView <> Self) do
  3282. AView := AView.FParentView;
  3283. Result := Assigned(AView);
  3284. end;
  3285. function TTBView.GetRootView: TTBView;
  3286. begin
  3287. Result := Self;
  3288. while Assigned(Result.FParentView) do
  3289. Result := Result.FParentView;
  3290. end;
  3291. function TTBView.GetParentToolbarView: TTBView;
  3292. begin
  3293. Result := Self;
  3294. while Assigned(Result) and not Result.FIsToolbar do
  3295. Result := Result.FParentView;
  3296. end;
  3297. procedure TTBView.FreeViewers;
  3298. var
  3299. VI: PTBItemViewerArray;
  3300. I, C: Integer;
  3301. begin
  3302. if Assigned(FViewers) then begin
  3303. VI := FViewers;
  3304. C := FViewerCount;
  3305. FViewers := nil;
  3306. FViewerCount := 0;
  3307. for I := C-1 downto 0 do
  3308. FreeAndNil(VI[I]);
  3309. FreeMem(VI);
  3310. end;
  3311. end;
  3312. procedure TTBView.InvalidatePositions;
  3313. begin
  3314. if FValidated then begin
  3315. FValidated := False;
  3316. if Assigned(FWindow) and FWindow.HandleAllocated then
  3317. InvalidateRect(FWindow.Handle, nil, True);
  3318. end;
  3319. end;
  3320. procedure TTBView.ValidatePositions;
  3321. begin
  3322. if not FValidated then
  3323. UpdatePositions;
  3324. end;
  3325. procedure TTBView.TryValidatePositions;
  3326. begin
  3327. if (FUpdating = 0) and
  3328. (not Assigned(FParentItem) or not(csLoading in FParentItem.ComponentState)) and
  3329. (not Assigned(FParentItem.Owner) or not(csLoading in FParentItem.Owner.ComponentState)) then
  3330. ValidatePositions;
  3331. end;
  3332. (*procedure TTBView.TryRevalidatePositions;
  3333. begin
  3334. if FValidated then begin
  3335. if FUpdating = 0 then begin
  3336. FreePositions;
  3337. UpdatePositions;
  3338. end
  3339. else
  3340. InvalidatePositions;
  3341. end;
  3342. end;*)
  3343. function TTBView.Find(Item: TTBCustomItem): TTBItemViewer;
  3344. var
  3345. I: Integer;
  3346. begin
  3347. for I := 0 to FViewerCount-1 do
  3348. if FViewers[I].Item = Item then begin
  3349. Result := FViewers[I];
  3350. Exit;
  3351. end;
  3352. raise ETBItemError.Create(STBViewerNotFound);
  3353. end;
  3354. function TTBView.IndexOf(AViewer: TTBItemViewer): Integer;
  3355. var
  3356. I: Integer;
  3357. begin
  3358. if Assigned(AViewer) then
  3359. for I := 0 to FViewerCount-1 do
  3360. if FViewers[I] = AViewer then begin
  3361. Result := I;
  3362. Exit;
  3363. end;
  3364. Result := -1;
  3365. end;
  3366. procedure TTBView.DeletingViewer(Viewer: TTBItemViewer);
  3367. begin
  3368. if FSelected = Viewer then
  3369. FSelected := nil;
  3370. if FOpenViewer = Viewer then
  3371. CloseChildPopups;
  3372. end;
  3373. procedure TTBView.RecreateItemViewer(const I: Integer);
  3374. var
  3375. OldViewer, NewViewer: TTBItemViewer;
  3376. J: Integer;
  3377. begin
  3378. OldViewer := FViewers[I];
  3379. DeletingViewer(OldViewer);
  3380. NewViewer := OldViewer.Item.GetItemViewerClass(Self).Create(Self,
  3381. OldViewer.Item, OldViewer.FGroupLevel);
  3382. FViewers[I] := NewViewer;
  3383. if Assigned(FPriorityList) then begin
  3384. J := FPriorityList.IndexOf(OldViewer);
  3385. if J <> -1 then
  3386. FPriorityList[J] := NewViewer;
  3387. end;
  3388. OldViewer.Free;
  3389. end;
  3390. function TTBView.InsertItemViewers(const NewIndex: Integer;
  3391. const AItem: TTBCustomItem; const AGroupLevel: Integer;
  3392. const AddToPriorityList, TopOfPriorityList: Boolean): Integer;
  3393. var
  3394. NewViewer: TTBItemViewer;
  3395. LinkItem: TTBCustomItem;
  3396. I: Integer;
  3397. begin
  3398. if AGroupLevel > MaxGroupLevel then begin
  3399. Result := 0;
  3400. Exit;
  3401. end;
  3402. NewViewer := AItem.GetItemViewerClass(Self).Create(Self, AItem,
  3403. AGroupLevel);
  3404. InsertIntoViewerArray(FViewers, FViewerCount, NewIndex,
  3405. NewViewer);
  3406. if AddToPriorityList and FUsePriorityList then begin
  3407. if not TopOfPriorityList then
  3408. AddToList(FPriorityList, NewViewer)
  3409. else
  3410. { When new items are inserted programmatically at run-time, place
  3411. them at the top of FPriorityList }
  3412. AddToFrontOfList(FPriorityList, NewViewer);
  3413. end;
  3414. Result := 1;
  3415. { If a new group item is being inserted, insert all its child items too }
  3416. if not FCustomizing and (tbisEmbeddedGroup in AItem.ItemStyle) then begin
  3417. LinkItem := ItemContainingItems(AItem);
  3418. for I := 0 to LinkItem.Count-1 do begin
  3419. Inc(Result, InsertItemViewers(NewIndex + Result, LinkItem.FItems[I].Item,
  3420. AGroupLevel + 1, AddToPriorityList, TopOfPriorityList));
  3421. end;
  3422. end;
  3423. end;
  3424. procedure TTBView.ItemNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
  3425. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  3426. procedure ItemInserted;
  3427. var
  3428. NewLevel, Start, InsertPoint, Last: Integer;
  3429. GroupItem, NextItem: TTBCustomItem;
  3430. Found, SearchAgain: Boolean;
  3431. begin
  3432. InvalidatePositions;
  3433. NewLevel := 0;
  3434. Start := 0;
  3435. if Ancestor = FCurParentItem then
  3436. InsertPoint := FViewerCount
  3437. else begin
  3438. { Ancestor <> FCurParentItem, so apparently an item has been inserted
  3439. inside a group item }
  3440. repeat
  3441. Found := False;
  3442. while Start < FViewerCount do begin
  3443. GroupItem := FViewers[Start].Item;
  3444. if (tbisEmbeddedGroup in GroupItem.ItemStyle) and (GroupItem = Ancestor) then begin
  3445. NewLevel := FViewers[Start].FGroupLevel + 1;
  3446. Inc(Start);
  3447. Found := True;
  3448. Break;
  3449. end;
  3450. Inc(Start);
  3451. end;
  3452. if not Found then
  3453. { Couldn't find Ancestor; it shouldn't get here }
  3454. Exit;
  3455. InsertPoint := Start;
  3456. SearchAgain := False;
  3457. while (InsertPoint < FViewerCount) and
  3458. (FViewers[InsertPoint].FGroupLevel >= NewLevel) do begin
  3459. if (FViewers[InsertPoint].Item = Item) and
  3460. (FViewers[InsertPoint].FGroupLevel = NewLevel) then begin
  3461. { If the item we were going to insert already exists, then there
  3462. must be multiple instances of the same group item. This can
  3463. happen when are two group items on the same toolbar each
  3464. linking to the same submenu item, with the submenu item
  3465. containing a group item of its own, and an item is inserted
  3466. inside that. }
  3467. SearchAgain := True;
  3468. Break;
  3469. end;
  3470. Inc(InsertPoint);
  3471. end;
  3472. until not SearchAgain;
  3473. end;
  3474. if InsertPoint = FViewerCount then begin
  3475. { Don't add items after the chevron or MDI buttons item }
  3476. Dec(InsertPoint, FInternalViewersAtEnd);
  3477. if InsertPoint < 0 then
  3478. InsertPoint := 0; { just in case? }
  3479. end;
  3480. { If the new item wasn't placed at the end, adjust InsertPoint accordingly }
  3481. if Index < Item.Parent.Count-1 then begin
  3482. Last := InsertPoint;
  3483. InsertPoint := Start;
  3484. NextItem := Item.Parent.FItems[Index+1].Item;
  3485. while (InsertPoint < Last) and
  3486. ((FViewers[InsertPoint].Item <> NextItem) or
  3487. (FViewers[InsertPoint].FGroupLevel <> NewLevel)) do
  3488. Inc(InsertPoint);
  3489. end;
  3490. InsertItemViewers(InsertPoint, Item, NewLevel, True,
  3491. not(csLoading in Item.ComponentState) and FNewViewersGetHighestPriority);
  3492. end;
  3493. procedure ItemDeleting;
  3494. procedure DeleteItem(DeleteIndex: Integer);
  3495. var
  3496. Viewer: TTBItemViewer;
  3497. begin
  3498. Viewer := FViewers[DeleteIndex];
  3499. DeletingViewer(Viewer);
  3500. RemoveFromList(FPriorityList, Viewer);
  3501. FreeAndNil(Viewer);
  3502. DeleteFromViewerArray(FViewers, FViewerCount, DeleteIndex);
  3503. end;
  3504. var
  3505. I: Integer;
  3506. DeleteLevel: Integer;
  3507. begin
  3508. InvalidatePositions;
  3509. I := 0;
  3510. DeleteLevel := 0;
  3511. while I < FViewerCount do begin
  3512. if DeleteLevel > 0 then begin
  3513. if FViewers[I].FGroupLevel >= DeleteLevel then begin
  3514. DeleteItem(I);
  3515. Continue;
  3516. end
  3517. else
  3518. DeleteLevel := 0;
  3519. end;
  3520. if FViewers[I].Item = Item then begin
  3521. { Delete the item, and any group item children afterward }
  3522. DeleteLevel := FViewers[I].FGroupLevel + 1;
  3523. DeleteItem(I);
  3524. Continue;
  3525. end;
  3526. Inc(I);
  3527. end;
  3528. end;
  3529. var
  3530. I: Integer;
  3531. begin
  3532. case Action of
  3533. tbicInserted: ItemInserted;
  3534. tbicDeleting: ItemDeleting;
  3535. tbicSubitemsChanged: begin
  3536. { If Relayed=True, LinkSubitems must have changed on a child group
  3537. item. Currently there isn't any optimized way of handling this
  3538. situation; just recreate all viewers. }
  3539. if Relayed then
  3540. RecreateAllViewers;
  3541. end;
  3542. tbicSubitemsBeginUpdate: BeginUpdate;
  3543. tbicSubitemsEndUpdate: EndUpdate;
  3544. tbicInvalidate: begin
  3545. for I := 0 to FViewerCount-1 do
  3546. if FViewers[I].Item = Item then
  3547. Invalidate(FViewers[I]);
  3548. end;
  3549. tbicInvalidateAndResize: InvalidatePositions;
  3550. tbicRecreateItemViewers: begin
  3551. InvalidatePositions;
  3552. for I := 0 to FViewerCount-1 do
  3553. if FViewers[I].Item = Item then
  3554. RecreateItemViewer(I);
  3555. end;
  3556. tbicSubMenuImagesChanged: ImagesChanged;
  3557. else
  3558. { Prevent TryValidatePositions from being called below on Actions other than
  3559. those listed above. Currently there are no other Actions, but for forward
  3560. compatibility, we should ignore unknown Actions completely. }
  3561. Exit;
  3562. end;
  3563. TryValidatePositions;
  3564. end;
  3565. procedure TTBView.LinkNotification(Ancestor: TTBCustomItem; Relayed: Boolean;
  3566. Action: TTBItemChangedAction; Index: Integer; Item: TTBCustomItem);
  3567. { This notification procedure watches for tbicSubitemsChanged notifications
  3568. from FParentItem }
  3569. begin
  3570. case Action of
  3571. tbicSubitemsChanged: begin
  3572. { LinkSubitems may have changed on FParentItem, e.g. on the root item
  3573. of a toolbar, so see if FCurParentItem needs updating }
  3574. UpdateCurParentItem;
  3575. end;
  3576. tbicSubMenuImagesChanged: begin
  3577. { In case the images were inherited from the actual parent instead of
  3578. the linked parent... }
  3579. if FParentItem <> FCurParentItem then
  3580. ImagesChanged;
  3581. end;
  3582. end;
  3583. end;
  3584. procedure TTBView.ImagesChanged;
  3585. begin
  3586. InvalidatePositions;
  3587. TryValidatePositions;
  3588. if Assigned(FOpenViewerView) then
  3589. FOpenViewerView.ImagesChanged;
  3590. end;
  3591. procedure TTBView.GivePriority(AViewer: TTBItemViewer);
  3592. { Move item to top of priority list. Rearranges items if necessary. }
  3593. var
  3594. I: Integer;
  3595. begin
  3596. if Assigned(FChevronParentView) then begin
  3597. I := AViewer.Index + FChevronParentView.FInternalViewersAtFront;
  3598. if I < FChevronParentView.FViewerCount then { range check just in case }
  3599. FChevronParentView.GivePriority(FChevronParentView.FViewers[I]);
  3600. Exit;
  3601. end;
  3602. if Assigned(FPriorityList) then begin
  3603. I := FPriorityList.IndexOf(AViewer);
  3604. if I <> -1 then begin
  3605. FPriorityList.Move(I, 0);
  3606. if not FValidated or AViewer.OffEdge then
  3607. UpdatePositions;
  3608. end;
  3609. end;
  3610. { Call GivePriority on parent view, so that if an item on a submenu is
  3611. clicked, the parent item of the submenu gets priority. }
  3612. if Assigned(FParentView) and Assigned(FParentView.FOpenViewer) then
  3613. FParentView.GivePriority(FParentView.FOpenViewer);
  3614. end;
  3615. function TTBView.HighestPriorityViewer: TTBItemViewer;
  3616. { Returns index of first visible, non-separator item at top of priority list,
  3617. or -1 if there are no items found }
  3618. var
  3619. I: Integer;
  3620. J: TTBItemViewer;
  3621. begin
  3622. ValidatePositions;
  3623. Result := nil;
  3624. if Assigned(FPriorityList) then begin
  3625. for I := 0 to FPriorityList.Count-1 do begin
  3626. J := FPriorityList[I];
  3627. if J.Show and not(tbisSeparator in J.Item.ItemStyle) then begin
  3628. Result := J;
  3629. Break;
  3630. end;
  3631. end;
  3632. end
  3633. else begin
  3634. for I := 0 to FViewerCount-1 do begin
  3635. J := FViewers[I];
  3636. if J.Show and not(tbisSeparator in J.Item.ItemStyle) then begin
  3637. Result := J;
  3638. Break;
  3639. end;
  3640. end;
  3641. end;
  3642. end;
  3643. procedure TTBView.StartTimer(const ATimer: TTBViewTimerID;
  3644. const Interval: Integer);
  3645. { Starts a timer. Stops any previously set timer of the same ID first.
  3646. Note: WM_TIMER messages generated by timers set by the method are handled
  3647. in PopupMessageLoop. }
  3648. begin
  3649. StopTimer(ATimer);
  3650. if (FWindow is TTBPopupWindow) and FWindow.HandleAllocated then begin
  3651. SetTimer(FWindow.Handle, ViewTimerBaseID + Ord(ATimer), Interval, nil);
  3652. Include(FActiveTimers, ATimer);
  3653. end;
  3654. end;
  3655. procedure TTBView.StopAllTimers;
  3656. var
  3657. I: TTBViewTimerID;
  3658. begin
  3659. for I := Low(I) to High(I) do
  3660. StopTimer(I);
  3661. end;
  3662. procedure TTBView.StopTimer(const ATimer: TTBViewTimerID);
  3663. begin
  3664. if ATimer in FActiveTimers then begin
  3665. if (FWindow is TTBPopupWindow) and FWindow.HandleAllocated then
  3666. KillTimer(FWindow.Handle, ViewTimerBaseID + Ord(ATimer));
  3667. Exclude(FActiveTimers, ATimer);
  3668. end;
  3669. end;
  3670. function TTBView.OpenChildPopup(const SelectFirstItem: Boolean): Boolean;
  3671. var
  3672. Item: TTBCustomItem;
  3673. begin
  3674. StopTimer(tiClose);
  3675. StopTimer(tiOpen);
  3676. if FSelected <> FOpenViewer then begin
  3677. CloseChildPopups;
  3678. if Assigned(FSelected) then begin
  3679. Item := FSelected.Item;
  3680. if Item.Enabled and (tbisSubmenu in Item.ItemStyle) then
  3681. Item.CreatePopup(Self, FSelected, not FIsToolbar, SelectFirstItem,
  3682. False, Point(0, 0), tbpaLeft);
  3683. end;
  3684. end;
  3685. Result := Assigned(FOpenViewer);
  3686. end;
  3687. procedure TTBView.CloseChildPopups;
  3688. begin
  3689. if Assigned(FOpenViewerView) then
  3690. FOpenViewerView.CloseChildPopups;
  3691. StopTimer(tiClose);
  3692. FOpenViewerWindow.Free;
  3693. FOpenViewerWindow := nil;
  3694. FOpenViewerView := nil;
  3695. FOpenViewer := nil;
  3696. end;
  3697. procedure TTBView.CancelChildPopups;
  3698. begin
  3699. if FIsToolbar then
  3700. Exclude(FState, vsDropDownMenus);
  3701. CloseChildPopups;
  3702. end;
  3703. function TTBView.ViewerFromPoint(const P: TPoint): TTBItemViewer;
  3704. var
  3705. I: Integer;
  3706. begin
  3707. ValidatePositions;
  3708. for I := 0 to FViewerCount-1 do begin
  3709. if FViewers[I].Show and
  3710. PtInRect(FViewers[I].BoundsRect, P) then begin
  3711. Result := FViewers[I];
  3712. Exit;
  3713. end;
  3714. end;
  3715. Result := nil;
  3716. end;
  3717. procedure TTBView.NotifyFocusEvent;
  3718. { Notifies Active Accessibility of a change in "focus". Has no effect if the
  3719. view or the root view lacks the vsModal state, or if the modal loop is
  3720. ending (EndModal* was called). }
  3721. var
  3722. I, ChildID, J: Integer;
  3723. begin
  3724. { Note: We don't notify about windows not yet shown (e.g. a popup menu that
  3725. is still initializing) because that would probably confuse screen readers.
  3726. Also allocating a window handle at this point *might* not be a good idea. }
  3727. if (vsModal in FState) and (vsModal in GetRootView.FState) and
  3728. not IsModalEnding and
  3729. FWindow.HandleAllocated and IsWindowVisible(FWindow.Handle) then begin
  3730. if Assigned(FSelected) and FSelected.IsAccessible then
  3731. I := IndexOf(FSelected)
  3732. else
  3733. I := -1;
  3734. if (I < 0) and Assigned(FParentView) then begin
  3735. { If we have no selected item, report the the selected item on the parent
  3736. view as having the "focus".
  3737. Note: With standard menus, when you go from having a selection to no
  3738. selection on a submenu, it sends two focus events - first with the
  3739. client window as having the focus, then with the parent item. I
  3740. figure that's probably a bug, so I don't try to emulate that behavior
  3741. here. }
  3742. FParentView.NotifyFocusEvent;
  3743. end
  3744. else begin
  3745. if I >= 0 then begin
  3746. { Convert viewer index into a one-based child index.
  3747. (TTBViewAccObject.get_accChild does the inverse.) }
  3748. ChildID := 1;
  3749. for J := 0 to I-1 do
  3750. if FViewers[J].IsAccessible then
  3751. Inc(ChildID);
  3752. end
  3753. else begin
  3754. { If there is no (accessible) selection and no parent view, report
  3755. the client window itself as being "focused". This is what happens
  3756. when a standard context menu has no selection. }
  3757. ChildID := CHILDID_SELF;
  3758. end;
  3759. CallNotifyWinEvent(EVENT_OBJECT_FOCUS, FWindow.Handle, OBJID_CLIENT, ChildID);
  3760. end;
  3761. end;
  3762. end;
  3763. procedure TTBView.SetSelected(Value: TTBItemViewer);
  3764. begin
  3765. Select(Value, False);
  3766. end;
  3767. procedure TTBView.Select(Value: TTBItemViewer; ViaMouse: Boolean);
  3768. { Sets the current selection.
  3769. When the selection is changing it will also, if necessary, open/close child
  3770. popups. How exactly this works depends on the setting of ViaMouse. If
  3771. ViaMouse is True it will delay the opening/closing of popups using timers. }
  3772. var
  3773. OldSelected: TTBItemViewer;
  3774. NewMouseOverSelected: Boolean;
  3775. P: TPoint;
  3776. begin
  3777. OldSelected := FSelected;
  3778. if Value <> OldSelected then begin
  3779. { If there's a new selection and the parent item on the parent view
  3780. isn't currently selected, select it. Also stop any timer running on
  3781. the parent view. }
  3782. if Assigned(Value) and Assigned(FParentView) and
  3783. Assigned(FParentView.FOpenViewer) and
  3784. (FParentView.FSelected <> FParentView.FOpenViewer) then begin
  3785. FParentView.Selected := FParentView.FOpenViewer;
  3786. FParentView.StopTimer(tiClose);
  3787. FParentView.StopTimer(tiOpen);
  3788. end;
  3789. { Handle automatic closing of child popups }
  3790. if vsModal in FState then begin
  3791. { If the view is a toolbar, or if the new selection didn't come from
  3792. the mouse, close child popups immediately }
  3793. if FIsToolbar or not ViaMouse then begin
  3794. { Always stop any close timer because CloseChildPopups may not be
  3795. called below }
  3796. StopTimer(tiClose);
  3797. if Value <> FOpenViewer then
  3798. { ^ But don't close if selection is returning to the open item.
  3799. Needed for the "FParentView.Selected := FParentView.FOpenViewer"
  3800. line above to work. }
  3801. CloseChildPopups;
  3802. end
  3803. else begin
  3804. { Otherwise, delay-close any child popup }
  3805. if Assigned(FOpenViewerView) and not(tiClose in FActiveTimers) then
  3806. StartTimer(tiClose, GetMenuShowDelay);
  3807. end;
  3808. end;
  3809. CancelCapture;
  3810. if Assigned(OldSelected) then
  3811. OldSelected.Leaving;
  3812. FSelected := Value;
  3813. FSelectedViaMouse := ViaMouse;
  3814. end;
  3815. NewMouseOverSelected := False;
  3816. if Assigned(Value) and Assigned(FWindow) then begin
  3817. P := SmallPointToPoint(TSmallPoint(GetMessagePos()));
  3818. if FindDragTarget(P, True) = FWindow then begin
  3819. P := FWindow.ScreenToClient(P);
  3820. NewMouseOverSelected := (ViewerFromPoint(P) = Value);
  3821. if NewMouseOverSelected and FCapture and
  3822. not Value.IsPtInButtonPart(P.X - Value.BoundsRect.Left,
  3823. P.Y - Value.BoundsRect.Top) then
  3824. NewMouseOverSelected := False;
  3825. end;
  3826. end;
  3827. if Value <> OldSelected then begin
  3828. FMouseOverSelected := NewMouseOverSelected;
  3829. if Assigned(OldSelected) and (tbisRedrawOnSelChange in OldSelected.Item.ItemStyle) then
  3830. Invalidate(OldSelected);
  3831. if Assigned(Value) then begin
  3832. if tbisRedrawOnSelChange in Value.Item.ItemStyle then
  3833. Invalidate(Value);
  3834. Value.Entering(OldSelected);
  3835. end;
  3836. NotifyFocusEvent;
  3837. { Handle automatic opening of a child popup }
  3838. if vsModal in FState then begin
  3839. { If the view is a toolbar, immediately open any child popup }
  3840. if FIsToolbar then begin
  3841. if Assigned(Value) then begin
  3842. if ViaMouse and Assigned(FParentView) then begin
  3843. { On chevron popups, always drop down menus when mouse passes
  3844. over them, like Office 2000 }
  3845. Include(FState, vsDropDownMenus);
  3846. end;
  3847. if (vsDropDownMenus in FState) and
  3848. (ViaMouse or not(tbisNoAutoOpen in Value.Item.ItemStyle)) then
  3849. OpenChildPopup(not ViaMouse);
  3850. end;
  3851. end
  3852. else begin
  3853. { Otherwise, delay-open any child popup if the selection came from
  3854. the mouse }
  3855. StopTimer(tiOpen);
  3856. if ViaMouse and Assigned(Value) and (tbisSubmenu in Value.Item.ItemStyle) then
  3857. StartTimer(tiOpen, GetMenuShowDelay);
  3858. end;
  3859. end;
  3860. end
  3861. else if FMouseOverSelected <> NewMouseOverSelected then begin
  3862. FMouseOverSelected := NewMouseOverSelected;
  3863. if Assigned(Value) and FCapture and (tbisRedrawOnMouseOverChange in Value.Item.ItemStyle) then
  3864. Invalidate(Value);
  3865. end;
  3866. end;
  3867. procedure TTBView.UpdateSelection(const P: PPoint; const AllowNewSelection: Boolean);
  3868. { Called in response to a mouse movement, this method updates the current
  3869. selection, updates the vsMouseInWindow view state, and enables/disables
  3870. scroll timers. }
  3871. function IsPtInScrollArrow(ADownArrow: Boolean): Boolean;
  3872. var
  3873. P2: TPoint;
  3874. R: TRect;
  3875. begin
  3876. Result := False;
  3877. if (vsModal in FState) and (vsMouseInWindow in FState) and
  3878. Assigned(P) then begin
  3879. P2 := FWindow.ScreenToClient(P^);
  3880. R := FWindow.ClientRect;
  3881. if PtInRect(R, P2) then begin
  3882. if ADownArrow then
  3883. Result := FShowDownArrow and (P2.Y >= R.Bottom - tbMenuScrollArrowHeight)
  3884. else
  3885. Result := FShowUpArrow and (P2.Y < tbMenuScrollArrowHeight);
  3886. end;
  3887. end;
  3888. end;
  3889. var
  3890. NewSelected, ViewerAtPoint: TTBItemViewer;
  3891. P2: TPoint;
  3892. MouseWasInWindow: Boolean;
  3893. begin
  3894. ValidatePositions;
  3895. { If modal, default to keeping the existing selection }
  3896. if vsModal in FState then
  3897. NewSelected := FSelected
  3898. else
  3899. NewSelected := nil;
  3900. { Is the mouse inside the window? }
  3901. MouseWasInWindow := vsMouseInWindow in FState;
  3902. if Assigned(P) and Assigned(FWindow) and (FindDragTarget(P^, True) = FWindow) then begin
  3903. { If we're a popup window and the mouse is inside, default to no selection }
  3904. if FIsPopup then
  3905. NewSelected := nil;
  3906. Include(FState, vsMouseInWindow);
  3907. if AllowNewSelection or Assigned(FSelected) then begin
  3908. P2 := FWindow.ScreenToClient(P^);
  3909. ViewerAtPoint := ViewerFromPoint(P2);
  3910. if Assigned(ViewerAtPoint) then
  3911. NewSelected := ViewerAtPoint;
  3912. end;
  3913. end
  3914. else
  3915. Exclude(FState, vsMouseInWindow);
  3916. { If FCapture is True, don't allow the selection to change }
  3917. if FCapture and (NewSelected <> FSelected) then
  3918. NewSelected := FSelected;
  3919. { If we're a popup window and there is a selection... }
  3920. if FIsPopup and Assigned(NewSelected) then begin
  3921. { If the mouse just moved out of the window and no submenu was open,
  3922. remove the highlight }
  3923. if not FCapture and MouseWasInWindow and not(vsMouseInWindow in FState) and
  3924. (not Assigned(FOpenViewerView) or not(tbisSubmenu in NewSelected.Item.ItemStyle)) then
  3925. NewSelected := nil;
  3926. end;
  3927. { Now we set the new Selected value }
  3928. Select(NewSelected, True);
  3929. { Update scroll arrow timers }
  3930. if IsPtInScrollArrow(False) then begin
  3931. StopTimer(tiScrollDown);
  3932. if not(tiScrollUp in FActiveTimers) then
  3933. StartTimer(tiScrollUp, 100);
  3934. end
  3935. else if IsPtInScrollArrow(True) then begin
  3936. StopTimer(tiScrollUp);
  3937. if not(tiScrollDown in FActiveTimers) then
  3938. StartTimer(tiScrollDown, 100);
  3939. end
  3940. else begin
  3941. StopTimer(tiScrollUp);
  3942. StopTimer(tiScrollDown);
  3943. end;
  3944. end;
  3945. procedure TTBView.RecreateAllViewers;
  3946. var
  3947. Item: TTBCustomItem;
  3948. I: Integer;
  3949. begin
  3950. { Since the FViewers list is being rebuilt, FOpenViewer and FSelected
  3951. will no longer be valid, so ensure they're set to nil. }
  3952. CloseChildPopups;
  3953. Selected := nil;
  3954. InvalidatePositions;
  3955. FreeAndNil(FPriorityList);
  3956. FreeViewers;
  3957. FInternalViewersAtFront := 0;
  3958. FInternalViewersAtEnd := 0;
  3959. { MDI system menu item }
  3960. Item := GetMDISystemMenuItem;
  3961. if Assigned(Item) then
  3962. Inc(FInternalViewersAtFront, InsertItemViewers(FViewerCount, Item, 0,
  3963. False, False));
  3964. { Items }
  3965. if Assigned(FCurParentItem) then begin
  3966. for I := 0 to FCurParentItem.Count-1 do
  3967. InsertItemViewers(FViewerCount, FCurParentItem.FItems[I].Item, 0,
  3968. True, False);
  3969. end;
  3970. { MDI buttons item }
  3971. Item := GetMDIButtonsItem;
  3972. if Assigned(Item) then begin
  3973. for I := 0 to Item.Count-1 do
  3974. Inc(FInternalViewersAtEnd, InsertItemViewers(FViewerCount,
  3975. Item.FItems[I].Item, 0, False, False));
  3976. end;
  3977. { Chevron item }
  3978. Item := GetChevronItem;
  3979. if Assigned(Item) then
  3980. Inc(FInternalViewersAtEnd, InsertItemViewers(FViewerCount, Item, 0,
  3981. False, False));
  3982. end;
  3983. function TTBView.CalculatePositions(const CanMoveControls: Boolean;
  3984. const AOrientation: TTBViewOrientation;
  3985. AWrapOffset, AChevronOffset, AChevronSize: Integer;
  3986. var ABaseSize, TotalSize: TPoint;
  3987. var AWrappedLines: Integer): Boolean;
  3988. { Returns True if the positions have changed }
  3989. type
  3990. PTempPosition = ^TTempPosition;
  3991. TTempPosition = record
  3992. BoundsRect: TRect;
  3993. Show, OffEdge, LineSep, Clipped, SameWidth: Boolean;
  3994. end;
  3995. PTempPositionArray = ^TTempPositionArray;
  3996. TTempPositionArray = array[0..$7FFFFFFF div SizeOf(TTempPosition)-1] of TTempPosition;
  3997. var
  3998. DC: HDC;
  3999. LeftX, TopY, CurX, CurY, I: Integer;
  4000. NewPositions: PTempPositionArray;
  4001. GroupSplit, DidWrap: Boolean;
  4002. LineStart, HighestHeightOnLine, HighestWidthOnLine: Integer;
  4003. function GetSizeOfGroup(const StartingIndex: Integer): Integer;
  4004. var
  4005. I: Integer;
  4006. begin
  4007. Result := 0;
  4008. for I := StartingIndex to FViewerCount-1 do begin
  4009. if not NewPositions[I].Show then
  4010. Continue;
  4011. if tbisSeparator in FViewers[I].Item.ItemStyle then
  4012. Break;
  4013. with NewPositions[I] do begin
  4014. if AOrientation <> tbvoVertical then
  4015. Inc(Result, BoundsRect.Right)
  4016. else
  4017. Inc(Result, BoundsRect.Bottom);
  4018. end;
  4019. end;
  4020. end;
  4021. procedure Mirror;
  4022. { Reverses the horizontal ordering (i.e. first item becomes last) }
  4023. var
  4024. I, NewRight: Integer;
  4025. begin
  4026. for I := 0 to FViewerCount-1 do
  4027. with NewPositions[I] do
  4028. if Show then begin
  4029. NewRight := TotalSize.X - BoundsRect.Left;
  4030. BoundsRect.Left := TotalSize.X - BoundsRect.Right;
  4031. BoundsRect.Right := NewRight;
  4032. end;
  4033. end;
  4034. procedure HandleMaxHeight;
  4035. { Decreases, if necessary, the height of the view to FMaxHeight, and adjusts
  4036. the visibility of the scroll arrows }
  4037. var
  4038. MaxOffset, I, MaxTop, MaxBottom: Integer;
  4039. begin
  4040. FShowUpArrow := False;
  4041. FShowDownArrow := False;
  4042. if (FMaxHeight > 0) and (TotalSize.Y > FMaxHeight) then begin
  4043. MaxOffset := TotalSize.Y - FMaxHeight;
  4044. if FScrollOffset > MaxOffset then
  4045. FScrollOffset := MaxOffset;
  4046. if FScrollOffset < 0 then
  4047. FScrollOffset := 0;
  4048. FShowUpArrow := (FScrollOffset > 0);
  4049. FShowDownArrow := (FScrollOffset < MaxOffset);
  4050. MaxTop := 0;
  4051. if FShowUpArrow then
  4052. MaxTop := tbMenuScrollArrowHeight;
  4053. MaxBottom := FMaxHeight;
  4054. if FShowDownArrow then
  4055. Dec(MaxBottom, tbMenuScrollArrowHeight);
  4056. for I := 0 to FViewerCount-1 do begin
  4057. if not IsRectEmpty(NewPositions[I].BoundsRect) then begin
  4058. OffsetRect(NewPositions[I].BoundsRect, 0, -FScrollOffset);
  4059. if NewPositions[I].Show and
  4060. ((NewPositions[I].BoundsRect.Top < MaxTop) or
  4061. (NewPositions[I].BoundsRect.Bottom > MaxBottom)) then begin
  4062. NewPositions[I].Show := False;
  4063. NewPositions[I].Clipped := True;
  4064. end;
  4065. end;
  4066. end;
  4067. TotalSize.Y := FMaxHeight;
  4068. end
  4069. else
  4070. FScrollOffset := 0;
  4071. end;
  4072. procedure FinalizeLine(const LineEnd: Integer; const LastLine: Boolean);
  4073. var
  4074. I, RightAlignStart: Integer;
  4075. Item: TTBCustomItem;
  4076. IsButton: Boolean;
  4077. Pos: PTempPosition;
  4078. Z: Integer;
  4079. begin
  4080. if LineStart <> -1 then begin
  4081. if DidWrap and (FChevronParentView = nil) then begin
  4082. { When wrapping on a docked toolbar, extend TotalSize.X/Y to
  4083. AWrapOffset so that the toolbar always fills the whole row }
  4084. if (AOrientation = tbvoHorizontal) and (TotalSize.X < AWrapOffset) then
  4085. TotalSize.X := AWrapOffset
  4086. else if (AOrientation = tbvoVertical) and (TotalSize.Y < AWrapOffset) then
  4087. TotalSize.Y := AWrapOffset;
  4088. end;
  4089. RightAlignStart := -1;
  4090. for I := LineStart to LineEnd do begin
  4091. Pos := @NewPositions[I];
  4092. if not Pos.Show then
  4093. Continue;
  4094. Item := FViewers[I].Item;
  4095. if (RightAlignStart < 0) and (tbisRightAlign in Item.ItemStyle) then
  4096. RightAlignStart := I;
  4097. IsButton := FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
  4098. if FIsToolbar then begin
  4099. if LastLine and not DidWrap and (AOrientation <> tbvoFloating) then begin
  4100. { In case the toolbar is docked next to a taller/wider toolbar... }
  4101. HighestWidthOnLine := TotalSize.X;
  4102. HighestHeightOnLine := TotalSize.Y;
  4103. end;
  4104. { Make separators on toolbars as tall/wide as the tallest/widest item }
  4105. if [tbisSeparator, tbisStretch] * Item.ItemStyle <> [] then begin
  4106. if AOrientation <> tbvoVertical then
  4107. Pos.BoundsRect.Bottom := Pos.BoundsRect.Top + HighestHeightOnLine
  4108. else
  4109. Pos.BoundsRect.Right := Pos.BoundsRect.Left + HighestWidthOnLine;
  4110. end
  4111. else begin
  4112. { Center the item }
  4113. if AOrientation <> tbvoVertical then begin
  4114. Z := (HighestHeightOnLine - (Pos.BoundsRect.Bottom - Pos.BoundsRect.Top)) div 2;
  4115. Inc(Pos.BoundsRect.Top, Z);
  4116. Inc(Pos.BoundsRect.Bottom, Z);
  4117. end
  4118. else begin
  4119. Z := (HighestWidthOnLine - (Pos.BoundsRect.Right - Pos.BoundsRect.Left)) div 2;
  4120. Inc(Pos.BoundsRect.Left, Z);
  4121. Inc(Pos.BoundsRect.Right, Z);
  4122. end;
  4123. end;
  4124. end
  4125. else begin
  4126. { Make items in a menu as wide as the widest item }
  4127. if not IsButton then begin
  4128. with Pos.BoundsRect do Right := Left + HighestWidthOnLine;
  4129. end;
  4130. end;
  4131. end;
  4132. if RightAlignStart >= 0 then begin
  4133. Z := 0;
  4134. for I := LineEnd downto RightAlignStart do begin
  4135. Pos := @NewPositions[I];
  4136. if not Pos.Show then
  4137. Continue;
  4138. if AOrientation <> tbvoVertical then
  4139. Z := Min(AWrapOffset, TotalSize.X) - Pos.BoundsRect.Right
  4140. else
  4141. Z := Min(AWrapOffset, TotalSize.Y) - Pos.BoundsRect.Bottom;
  4142. Break;
  4143. end;
  4144. if Z > 0 then begin
  4145. for I := RightAlignStart to LineEnd do begin
  4146. Pos := @NewPositions[I];
  4147. if not Pos.Show then
  4148. Continue;
  4149. if AOrientation <> tbvoVertical then begin
  4150. Inc(Pos.BoundsRect.Left, Z);
  4151. Inc(Pos.BoundsRect.Right, Z);
  4152. end
  4153. else begin
  4154. Inc(Pos.BoundsRect.Top, Z);
  4155. Inc(Pos.BoundsRect.Bottom, Z);
  4156. end;
  4157. end;
  4158. end;
  4159. end;
  4160. end;
  4161. LineStart := -1;
  4162. HighestHeightOnLine := 0;
  4163. HighestWidthOnLine := 0;
  4164. end;
  4165. procedure PositionItem(const CurIndex: Integer; var Pos: TTempPosition);
  4166. var
  4167. O, X, Y: Integer;
  4168. IsLineSep, Vert: Boolean;
  4169. begin
  4170. if LineStart = -1 then begin
  4171. LineStart := CurIndex;
  4172. HighestHeightOnLine := 0;
  4173. HighestWidthOnLine := 0;
  4174. end;
  4175. IsLineSep := False;
  4176. Vert := (AOrientation = tbvoVertical);
  4177. if not Vert then
  4178. O := CurX
  4179. else
  4180. O := CurY;
  4181. if (AWrapOffset > 0) and (O > 0) then begin
  4182. if not Vert then
  4183. Inc(O, Pos.BoundsRect.Right)
  4184. else
  4185. Inc(O, Pos.BoundsRect.Bottom);
  4186. if (tbisSeparator in FViewers[CurIndex].Item.ItemStyle) and
  4187. ((GroupSplit and not(tbisNoLineBreak in FViewers[CurIndex].Item.ItemStyle))
  4188. or (O + GetSizeOfGroup(CurIndex+1) > AWrapOffset)) then begin
  4189. DidWrap := True;
  4190. Inc(AWrappedLines);
  4191. if not Vert then begin
  4192. CurX := 0;
  4193. Inc(CurY, HighestHeightOnLine);
  4194. end
  4195. else begin
  4196. CurY := 0;
  4197. Inc(CurX, HighestWidthOnLine);
  4198. end;
  4199. FinalizeLine(CurIndex-1, False);
  4200. LineStart := CurIndex+1;
  4201. if not Vert then begin
  4202. Pos.BoundsRect.Right := 0;
  4203. Pos.BoundsRect.Bottom := tbLineSpacing;
  4204. end
  4205. else begin
  4206. Pos.BoundsRect.Right := tbLineSpacing;
  4207. Pos.BoundsRect.Bottom := 0;
  4208. end;
  4209. Pos.LineSep := True;
  4210. IsLineSep := True;
  4211. end
  4212. else if O > AWrapOffset then begin
  4213. { proceed to next row }
  4214. DidWrap := True;
  4215. Inc(AWrappedLines);
  4216. if not Vert then begin
  4217. CurX := LeftX;
  4218. Inc(CurY, HighestHeightOnLine);
  4219. end
  4220. else begin
  4221. CurY := TopY;
  4222. Inc(CurX, HighestWidthOnLine);
  4223. end;
  4224. GroupSplit := True;
  4225. FinalizeLine(CurIndex-1, False);
  4226. LineStart := CurIndex;
  4227. end;
  4228. end;
  4229. if Pos.BoundsRect.Bottom > HighestHeightOnLine then
  4230. HighestHeightOnLine := Pos.BoundsRect.Bottom;
  4231. if Pos.BoundsRect.Right > HighestWidthOnLine then
  4232. HighestWidthOnLine := Pos.BoundsRect.Right;
  4233. X := CurX;
  4234. Y := CurY;
  4235. if X < 0 then X := 0;
  4236. if Y < 0 then Y := 0;
  4237. OffsetRect(Pos.BoundsRect, X, Y);
  4238. if IsLineSep then begin
  4239. if not Vert then begin
  4240. CurX := LeftX;
  4241. Inc(CurY, tbLineSpacing);
  4242. end
  4243. else begin
  4244. CurY := TopY;
  4245. Inc(CurX, tbLineSpacing);
  4246. end;
  4247. GroupSplit := False;
  4248. end;
  4249. end;
  4250. var
  4251. SaveOrientation: TTBViewOrientation;
  4252. ChevronItem: TTBCustomItem;
  4253. CalcCanvas: TCanvas;
  4254. LastWasSep, LastWasButton, IsButton, IsControl: Boolean;
  4255. Item: TTBCustomItem;
  4256. Ctl: TControl;
  4257. ChangedBold: Boolean;
  4258. HighestSameWidthViewerWidth, Total, J, TotalVisibleItems: Integer;
  4259. IsFirst: Boolean;
  4260. Viewer: TTBItemViewer;
  4261. UseChevron, NonControlsOffEdge, TempViewerCreated: Boolean;
  4262. Margins: TRect;
  4263. label 1;
  4264. begin
  4265. SaveOrientation := FOrientation;
  4266. AWrappedLines := 1;
  4267. ChevronItem := GetChevronItem;
  4268. NewPositions := nil;
  4269. DC := 0;
  4270. CalcCanvas := nil;
  4271. try
  4272. FOrientation := AOrientation;
  4273. CalcCanvas := TCanvas.Create;
  4274. DC := GetDC(0);
  4275. CalcCanvas.Handle := DC;
  4276. CalcCanvas.Font.Assign(GetFont);
  4277. NewPositions := AllocMem(FViewerCount * SizeOf(TTempPosition));
  4278. { Figure out which items should be shown }
  4279. LastWasSep := True; { set to True initially so it won't show leading seps }
  4280. for I := 0 to FViewerCount-1 do begin
  4281. Item := FViewers[I].Item;
  4282. IsControl := Item is TTBControlItem;
  4283. with NewPositions[I] do begin
  4284. { Show is initially False since AllocMem initializes to zero }
  4285. if Item = ChevronItem then
  4286. Continue;
  4287. if Assigned(FChevronParentView) then begin
  4288. if IsControl then
  4289. Continue;
  4290. FChevronParentView.ValidatePositions;
  4291. J := I + FChevronParentView.FInternalViewersAtFront;
  4292. if J < FChevronParentView.FViewerCount then
  4293. { range check just in case }
  4294. Viewer := FChevronParentView.FViewers[J]
  4295. else
  4296. Viewer := nil;
  4297. if (Viewer = nil) or (not Viewer.OffEdge and not(tbisSeparator in Item.ItemStyle)) then
  4298. Continue;
  4299. end;
  4300. if not IsControl then begin
  4301. if not(tbisEmbeddedGroup in Item.ItemStyle) or FCustomizing then begin
  4302. Show := Item.Visible;
  4303. { Don't display two consecutive separators }
  4304. if Show then begin
  4305. if (tbisSeparator in Item.ItemStyle) and LastWasSep then
  4306. Show := False;
  4307. LastWasSep := tbisSeparator in Item.ItemStyle;
  4308. end;
  4309. end;
  4310. end
  4311. else begin
  4312. { Controls can only be rendered on a single Parent, so only
  4313. include the control if its parent is currently equal to
  4314. FWindow }
  4315. Ctl := TTBControlItem(Item).FControl;
  4316. if Assigned(Ctl) and Assigned(FWindow) and (Ctl.Parent = FWindow) and
  4317. (Ctl.Visible or (csDesigning in Ctl.ComponentState)) then begin
  4318. Show := True;
  4319. LastWasSep := False;
  4320. end;
  4321. end;
  4322. end;
  4323. end;
  4324. { Hide any trailing separators, so that they aren't included in the
  4325. base size }
  4326. for I := FViewerCount-1 downto 0 do begin
  4327. with NewPositions[I] do
  4328. if Show then begin
  4329. if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
  4330. Break;
  4331. Show := False;
  4332. end;
  4333. end;
  4334. { Calculate sizes of all the items }
  4335. HighestSameWidthViewerWidth := 0;
  4336. for I := 0 to FViewerCount-1 do begin
  4337. Item := FViewers[I].Item;
  4338. IsControl := Item is TTBControlItem;
  4339. with NewPositions[I] do begin
  4340. { BoundsRect is currently empty since AllocMem initializes to zero }
  4341. if not Show then
  4342. Continue;
  4343. if not IsControl then begin
  4344. ChangedBold := False;
  4345. if tboDefault in Item.EffectiveOptions then
  4346. with CalcCanvas.Font do
  4347. if not(fsBold in Style) then begin
  4348. ChangedBold := True;
  4349. Style := Style + [fsBold];
  4350. end;
  4351. Viewer := FViewers[I];
  4352. TempViewerCreated := False;
  4353. if Item.NeedToRecreateViewer(Viewer) then begin
  4354. if CanMoveControls then begin
  4355. RecreateItemViewer(I);
  4356. Viewer := FViewers[I];
  4357. end
  4358. else begin
  4359. Viewer := Item.GetItemViewerClass(Self).Create(Self, Item, 0);
  4360. TempViewerCreated := True;
  4361. end;
  4362. end;
  4363. try
  4364. Viewer.CalcSize(CalcCanvas, BoundsRect.Right, BoundsRect.Bottom);
  4365. if Viewer.UsesSameWidth then begin
  4366. SameWidth := True;
  4367. if (BoundsRect.Right > HighestSameWidthViewerWidth) then
  4368. HighestSameWidthViewerWidth := BoundsRect.Right;
  4369. end;
  4370. finally
  4371. if TempViewerCreated then
  4372. Viewer.Free;
  4373. end;
  4374. if ChangedBold then
  4375. with CalcCanvas.Font do
  4376. Style := Style - [fsBold];
  4377. end
  4378. else begin
  4379. Ctl := TTBControlItem(Item).FControl;
  4380. BoundsRect.Right := Ctl.Width;
  4381. BoundsRect.Bottom := Ctl.Height;
  4382. end;
  4383. end;
  4384. end;
  4385. { Increase widths of SameWidth items if necessary. Also calculate
  4386. ABaseSize.X (or Y). }
  4387. ABaseSize.X := 0;
  4388. ABaseSize.Y := 0;
  4389. for I := 0 to FViewerCount-1 do begin
  4390. with NewPositions[I] do begin
  4391. if SameWidth and (BoundsRect.Right < HighestSameWidthViewerWidth) then
  4392. BoundsRect.Right := HighestSameWidthViewerWidth;
  4393. if AOrientation <> tbvoVertical then
  4394. Inc(ABaseSize.X, BoundsRect.Right)
  4395. else
  4396. Inc(ABaseSize.Y, BoundsRect.Bottom);
  4397. end;
  4398. end;
  4399. { Hide partially visible items, mark them as 'OffEdge' }
  4400. if AOrientation <> tbvoVertical then
  4401. Total := ABaseSize.X
  4402. else
  4403. Total := ABaseSize.Y;
  4404. NonControlsOffEdge := False;
  4405. UseChevron := Assigned(ChevronItem) and (AChevronOffset > 0) and
  4406. (Total > AChevronOffset);
  4407. if UseChevron then begin
  4408. Dec(AChevronOffset, AChevronSize);
  4409. while Total > AChevronOffset do begin
  4410. { Count number of items. Stop loop if <= 1 }
  4411. TotalVisibleItems := 0;
  4412. for I := FViewerCount-1 downto 0 do begin
  4413. if NewPositions[I].Show and not(tbisSeparator in FViewers[I].Item.ItemStyle) then
  4414. Inc(TotalVisibleItems);
  4415. end;
  4416. if TotalVisibleItems <= 1 then
  4417. Break;
  4418. { Hide any trailing separators }
  4419. for I := FViewerCount-1 downto 0 do begin
  4420. with NewPositions[I] do
  4421. if Show then begin
  4422. if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
  4423. Break;
  4424. Show := False;
  4425. if AOrientation <> tbvoVertical then
  4426. Dec(Total, BoundsRect.Right)
  4427. else
  4428. Dec(Total, BoundsRect.Bottom);
  4429. goto 1;
  4430. end;
  4431. end;
  4432. { Find an item to hide }
  4433. if Assigned(FPriorityList) then
  4434. I := FPriorityList.Count-1
  4435. else
  4436. I := FViewerCount-1;
  4437. while I >= 0 do begin
  4438. if Assigned(FPriorityList) then begin
  4439. Viewer := FPriorityList[I];
  4440. J := Viewer.Index;
  4441. end
  4442. else begin
  4443. Viewer := FViewers[I];
  4444. J := I;
  4445. end;
  4446. if NewPositions[J].Show and not(tbisSeparator in Viewer.Item.ItemStyle) then begin
  4447. NewPositions[J].Show := False;
  4448. NewPositions[J].OffEdge := True;
  4449. if AOrientation <> tbvoVertical then
  4450. Dec(Total, NewPositions[J].BoundsRect.Right)
  4451. else
  4452. Dec(Total, NewPositions[J].BoundsRect.Bottom);
  4453. if not NonControlsOffEdge and not(Viewer.Item is TTBControlItem) then
  4454. NonControlsOffEdge := True;
  4455. goto 1;
  4456. end;
  4457. Dec(I);
  4458. end;
  4459. Break; { prevent endless loop }
  4460. 1:
  4461. { Don't show two consecutive separators }
  4462. LastWasSep := True; { set to True initially so it won't show leading seps }
  4463. for J := 0 to FViewerCount-1 do begin
  4464. Item := FViewers[J].Item;
  4465. with NewPositions[J] do begin
  4466. if Show then begin
  4467. if (tbisSeparator in Item.ItemStyle) and LastWasSep then begin
  4468. Show := False;
  4469. if AOrientation <> tbvoVertical then
  4470. Dec(Total, BoundsRect.Right)
  4471. else
  4472. Dec(Total, BoundsRect.Bottom);
  4473. end;
  4474. LastWasSep := tbisSeparator in Item.ItemStyle;
  4475. end;
  4476. end;
  4477. end;
  4478. end;
  4479. end;
  4480. { Hide any trailing separators after items were hidden }
  4481. for I := FViewerCount-1 downto 0 do begin
  4482. with NewPositions[I] do
  4483. if Show then begin
  4484. if not(tbisSeparator in FViewers[I].Item.ItemStyle) then
  4485. Break;
  4486. Show := False;
  4487. end;
  4488. end;
  4489. { Set the ABaseSize.Y (or X) *after* items were hidden }
  4490. for I := 0 to FViewerCount-1 do begin
  4491. with NewPositions[I] do
  4492. if Show then begin
  4493. if AOrientation <> tbvoVertical then begin
  4494. if BoundsRect.Bottom > ABaseSize.Y then
  4495. ABaseSize.Y := BoundsRect.Bottom;
  4496. end
  4497. else begin
  4498. if BoundsRect.Right > ABaseSize.X then
  4499. ABaseSize.X := BoundsRect.Right;
  4500. end;
  4501. end;
  4502. end;
  4503. { On menus, set all non-separator items to be as tall as the tallest item }
  4504. {if not FIsToolbar then begin
  4505. J := 0;
  4506. for I := 0 to FViewerCount-1 do begin
  4507. Item := FViewers[I].Item;
  4508. with NewPositions[I] do
  4509. if Show and not(tbisSeparator in Item.ItemStyle) and
  4510. not(tboToolbarSize in Item.FEffectiveOptions) and
  4511. (BoundsRect.Bottom - BoundsRect.Top > J) then
  4512. J := BoundsRect.Bottom - BoundsRect.Top;
  4513. end;
  4514. for I := 0 to FViewerCount-1 do begin
  4515. Item := FViewers[I].Item;
  4516. with NewPositions[I] do
  4517. if Show and not(tbisSeparator in Item.ItemStyle) and
  4518. not(tboToolbarSize in Item.FEffectiveOptions) then
  4519. BoundsRect.Bottom := BoundsRect.Top + J;
  4520. end;
  4521. end;}
  4522. { Calculate the position of the items }
  4523. GetMargins(AOrientation, Margins);
  4524. LeftX := Margins.Left;
  4525. TopY := Margins.Top;
  4526. if AWrapOffset > 0 then begin
  4527. Dec(AWrapOffset, Margins.Right);
  4528. if AWrapOffset < 1 then AWrapOffset := 1;
  4529. end;
  4530. CurX := LeftX;
  4531. CurY := TopY;
  4532. GroupSplit := False;
  4533. DidWrap := False;
  4534. LastWasButton := FIsToolbar;
  4535. LineStart := -1;
  4536. for I := 0 to FViewerCount-1 do begin
  4537. Item := FViewers[I].Item;
  4538. with NewPositions[I] do begin
  4539. if not Show then
  4540. Continue;
  4541. IsButton := FIsToolbar or (tboToolbarSize in Item.FEffectiveOptions);
  4542. if LastWasButton and not IsButton then begin
  4543. { On a menu, if last item was a button and the current item isn't,
  4544. proceed to next row }
  4545. CurX := LeftX;
  4546. CurY := TotalSize.Y;
  4547. end;
  4548. LastWasButton := IsButton;
  4549. PositionItem(I, NewPositions[I]);
  4550. if IsButton and (AOrientation <> tbvoVertical) then
  4551. Inc(CurX, BoundsRect.Right - BoundsRect.Left)
  4552. else
  4553. Inc(CurY, BoundsRect.Bottom - BoundsRect.Top);
  4554. if BoundsRect.Right > TotalSize.X then
  4555. TotalSize.X := BoundsRect.Right;
  4556. if BoundsRect.Bottom > TotalSize.Y then
  4557. TotalSize.Y := BoundsRect.Bottom;
  4558. end;
  4559. end;
  4560. if FViewerCount <> 0 then
  4561. FinalizeLine(FViewerCount-1, True);
  4562. Inc(TotalSize.X, Margins.Right);
  4563. Inc(TotalSize.Y, Margins.Bottom);
  4564. if AOrientation = tbvoVertical then
  4565. Mirror;
  4566. HandleMaxHeight;
  4567. if CanMoveControls then begin
  4568. for I := 0 to FViewerCount-1 do begin
  4569. Item := FViewers[I].Item;
  4570. if Item is TTBControlItem then begin
  4571. if NewPositions[I].Show then begin
  4572. Ctl := TTBControlItem(Item).FControl;
  4573. if not EqualRect(NewPositions[I].BoundsRect, Ctl.BoundsRect) then
  4574. Ctl.BoundsRect := NewPositions[I].BoundsRect;
  4575. end
  4576. else if NewPositions[I].OffEdge or NewPositions[I].Clipped then begin
  4577. { Simulate hiding of OddEdge controls by literally moving them
  4578. off the edge. Do the same for Clipped controls. }
  4579. Ctl := TTBControlItem(Item).FControl;
  4580. Ctl.SetBounds(FWindow.ClientWidth, FWindow.ClientHeight,
  4581. Ctl.Width, Ctl.Height);
  4582. end;
  4583. end;
  4584. end;
  4585. end;
  4586. { Set size of line separators }
  4587. if FIsToolbar then
  4588. for I := 0 to FViewerCount-1 do begin
  4589. Item := FViewers[I].Item;
  4590. with NewPositions[I] do
  4591. if Show and (tbisSeparator in Item.ItemStyle) and
  4592. LineSep then begin
  4593. if AOrientation <> tbvoVertical then
  4594. BoundsRect.Right := TotalSize.X
  4595. else
  4596. BoundsRect.Bottom := TotalSize.Y;
  4597. end;
  4598. end;
  4599. { Position the chevron item }
  4600. if UseChevron then begin
  4601. if CanMoveControls then
  4602. ChevronItem.Enabled := NonControlsOffEdge;
  4603. NewPositions[FViewerCount-1].Show := True;
  4604. I := AChevronOffset;
  4605. if AOrientation <> tbvoVertical then begin
  4606. if I < TotalSize.X then
  4607. I := TotalSize.X;
  4608. NewPositions[FViewerCount-1].BoundsRect := Bounds(I, 0,
  4609. AChevronSize, TotalSize.Y);
  4610. end
  4611. else begin
  4612. if I < TotalSize.Y then
  4613. I := TotalSize.Y;
  4614. NewPositions[FViewerCount-1].BoundsRect := Bounds(0, I,
  4615. TotalSize.X, AChevronSize);
  4616. end;
  4617. end;
  4618. { Commit changes }
  4619. Result := False;
  4620. if CanMoveControls then begin
  4621. for I := 0 to FViewerCount-1 do begin
  4622. if not Result and
  4623. (not EqualRect(FViewers[I].BoundsRect, NewPositions[I].BoundsRect) or
  4624. (FViewers[I].Show <> NewPositions[I].Show) or
  4625. (tbisLineSep in FViewers[I].State <> NewPositions[I].LineSep)) then
  4626. Result := True;
  4627. FViewers[I].FBoundsRect := NewPositions[I].BoundsRect;
  4628. FViewers[I].FShow := NewPositions[I].Show;
  4629. FViewers[I].FOffEdge := NewPositions[I].OffEdge;
  4630. FViewers[I].FClipped := NewPositions[I].Clipped;
  4631. if NewPositions[I].LineSep then
  4632. Include(FViewers[I].State, tbisLineSep)
  4633. else
  4634. Exclude(FViewers[I].State, tbisLineSep);
  4635. end;
  4636. end;
  4637. finally
  4638. FOrientation := SaveOrientation;
  4639. if Assigned(CalcCanvas) then
  4640. CalcCanvas.Handle := 0;
  4641. if DC <> 0 then ReleaseDC(0, DC);
  4642. CalcCanvas.Free;
  4643. FreeMem(NewPositions);
  4644. end;
  4645. if (ABaseSize.X = 0) or (ABaseSize.Y = 0) then begin
  4646. { If there are no visible items... }
  4647. {}{scale this?}
  4648. ABaseSize.X := 23;
  4649. ABaseSize.Y := 22;
  4650. if TotalSize.X < 23 then TotalSize.X := 23;
  4651. if TotalSize.Y < 22 then TotalSize.Y := 22;
  4652. end;
  4653. end;
  4654. procedure TTBView.DoUpdatePositions(var ASize: TPoint);
  4655. { This is called by UpdatePositions }
  4656. var
  4657. Bmp: TBitmap;
  4658. CtlCanvas: TControlCanvas;
  4659. WrappedLines: Integer;
  4660. begin
  4661. { Don't call InvalidatePositions before CalculatePositions so that
  4662. endless recursion doesn't happen if an item's CalcSize uses a method that
  4663. calls ValidatePositions }
  4664. if not CalculatePositions(True, FOrientation, FWrapOffset, FChevronOffset,
  4665. FChevronSize, FBaseSize, ASize, WrappedLines) then begin
  4666. { If the new positions are identical to the previous ones, continue using
  4667. the previous ones, and don't redraw }
  4668. FValidated := True;
  4669. { Just because the positions are the same doesn't mean the size hasn't
  4670. changed. (If a shrunken toolbar moves between docks, the positions of
  4671. the non-OffEdge items may be the same on the new dock as on the old
  4672. dock.) }
  4673. AutoSize(ASize.X, ASize.Y);
  4674. end
  4675. else begin
  4676. if not(csDesigning in ComponentState) then begin
  4677. FValidated := True;
  4678. { Need to call ValidateRect before AutoSize, otherwise Windows will
  4679. erase the client area during a resize }
  4680. if FWindow.HandleAllocated then
  4681. ValidateRect(FWindow.Handle, nil);
  4682. AutoSize(ASize.X, ASize.Y);
  4683. if Assigned(FWindow) and FWindow.HandleAllocated and
  4684. IsWindowVisible(FWindow.Handle) and
  4685. (FWindow.ClientWidth > 0) and (FWindow.ClientHeight > 0) then begin
  4686. CtlCanvas := nil;
  4687. Bmp := TBitmap.Create;
  4688. try
  4689. CtlCanvas := TControlCanvas.Create;
  4690. CtlCanvas.Control := FWindow;
  4691. Bmp.Width := FWindow.ClientWidth;
  4692. Bmp.Height := FWindow.ClientHeight;
  4693. SendMessage(FWindow.Handle, WM_ERASEBKGND, WPARAM(Bmp.Canvas.Handle), 0);
  4694. SendMessage(FWindow.Handle, WM_PAINT, WPARAM(Bmp.Canvas.Handle), 0);
  4695. BitBlt(CtlCanvas.Handle, 0, 0, Bmp.Width, Bmp.Height,
  4696. Bmp.Canvas.Handle, 0, 0, SRCCOPY);
  4697. ValidateRect(FWindow.Handle, nil);
  4698. finally
  4699. CtlCanvas.Free;
  4700. Bmp.Free;
  4701. end;
  4702. end;
  4703. end
  4704. else begin
  4705. { Delphi's handling of canvases is different at design time -- child
  4706. controls aren't clipped from a parent control's canvas, so the above
  4707. offscreen rendering code doesn't work right at design-time }
  4708. InvalidatePositions;
  4709. FValidated := True;
  4710. AutoSize(ASize.X, ASize.Y);
  4711. end;
  4712. end;
  4713. end;
  4714. function TTBView.UpdatePositions: TPoint;
  4715. { Called whenever the size or orientation of a view changes. When items are
  4716. added or removed from the view, InvalidatePositions must be called instead,
  4717. otherwise the view may not be redrawn properly. }
  4718. begin
  4719. Result.X := 0;
  4720. Result.Y := 0;
  4721. DoUpdatePositions(Result);
  4722. end;
  4723. procedure TTBView.AutoSize(AWidth, AHeight: Integer);
  4724. begin
  4725. end;
  4726. function TTBView.GetChevronItem: TTBCustomItem;
  4727. begin
  4728. Result := nil;
  4729. end;
  4730. procedure TTBView.GetMargins(AOrientation: TTBViewOrientation;
  4731. var Margins: TRect);
  4732. begin
  4733. if AOrientation = tbvoFloating then begin
  4734. Margins.Left := 4;
  4735. Margins.Top := 2;
  4736. Margins.Right := 4;
  4737. Margins.Bottom := 1;
  4738. end
  4739. else begin
  4740. Margins.Left := 0;
  4741. Margins.Top := 0;
  4742. Margins.Right := 0;
  4743. Margins.Bottom := 0;
  4744. end;
  4745. end;
  4746. function TTBView.GetMDIButtonsItem: TTBCustomItem;
  4747. begin
  4748. Result := nil;
  4749. end;
  4750. function TTBView.GetMDISystemMenuItem: TTBCustomItem;
  4751. begin
  4752. Result := nil;
  4753. end;
  4754. function TTBView.GetFont: TFont;
  4755. begin
  4756. if Assigned(ToolbarFont) then
  4757. Result := ToolbarFont
  4758. else begin
  4759. { ToolbarFont is destroyed during unit finalization, but in rare cases
  4760. this method may end up being called from ValidatePositions *after*
  4761. unit finalization if Application.Run is never called; see the
  4762. "EConvertError" newsgroup thread. We can't return nil because that would
  4763. cause an exception in the calling function, so just return the window
  4764. font. It's not the *right* font, but it shouldn't matter since the app
  4765. is exiting anyway. }
  4766. Result := TControlAccess(FWindow).Font;
  4767. end;
  4768. end;
  4769. procedure TTBView.DrawItem(Viewer: TTBItemViewer; DrawTo: TCanvas;
  4770. Offscreen: Boolean);
  4771. const
  4772. COLOR_MENUHILIGHT = 29;
  4773. clMenuHighlight = TColor(COLOR_MENUHILIGHT or $80000000);
  4774. var
  4775. Bmp: TBitmap;
  4776. DrawToDC, BmpDC: HDC;
  4777. DrawCanvas: TCanvas;
  4778. R1, R2, R3: TRect;
  4779. IsOpen, IsSelected, IsPushed: Boolean;
  4780. ToolbarStyle: Boolean;
  4781. UseDisabledShadow: Boolean;
  4782. SaveIndex, SaveIndex2: Integer;
  4783. BkColor: TColor;
  4784. begin
  4785. ValidatePositions;
  4786. if tbisInvalidated in Viewer.State then begin
  4787. Offscreen := True;
  4788. Exclude(Viewer.State, tbisInvalidated);
  4789. end;
  4790. R1 := Viewer.BoundsRect;
  4791. if not Viewer.Show or IsRectEmpty(R1) or (Viewer.Item is TTBControlItem) then
  4792. Exit;
  4793. R2 := R1;
  4794. OffsetRect(R2, -R2.Left, -R2.Top);
  4795. IsOpen := FOpenViewer = Viewer;
  4796. IsSelected := (FSelected = Viewer);
  4797. IsPushed := IsSelected and (IsOpen or (FMouseOverSelected and FCapture));
  4798. ToolbarStyle := Viewer.IsToolbarStyle;
  4799. DrawToDC := DrawTo.Handle;
  4800. Bmp := nil;
  4801. { Must deselect any currently selected handles before calling SaveDC, because
  4802. if they are left selected and DeleteObject gets called on them after the
  4803. SaveDC call, it will fail on Win9x/Me, and thus leak GDI resources. }
  4804. DrawTo.Refresh;
  4805. SaveIndex := SaveDC(DrawToDC);
  4806. try
  4807. IntersectClipRect(DrawToDC, R1.Left, R1.Top, R1.Right, R1.Bottom);
  4808. GetClipBox(DrawToDC, R3);
  4809. if IsRectEmpty(R3) then
  4810. Exit;
  4811. if not Offscreen then begin
  4812. MoveWindowOrg(DrawToDC, R1.Left, R1.Top);
  4813. { Tweak the brush origin so that the checked background drawn behind
  4814. checked items always looks the same regardless of whether the item
  4815. is positioned on an even or odd Left or Top coordinate. }
  4816. SetBrushOrgEx(DrawToDC, R1.Left and 1, R1.Top and 1, nil);
  4817. DrawCanvas := DrawTo;
  4818. end
  4819. else begin
  4820. Bmp := TBitmap.Create;
  4821. Bmp.Width := R2.Right;
  4822. Bmp.Height := R2.Bottom;
  4823. DrawCanvas := Bmp.Canvas;
  4824. BmpDC := DrawCanvas.Handle;
  4825. SaveIndex2 := SaveDC(BmpDC);
  4826. SetWindowOrgEx(BmpDC, R1.Left, R1.Top, nil);
  4827. FWindow.Perform(WM_ERASEBKGND, WPARAM(BmpDC), 0);
  4828. RestoreDC(BmpDC, SaveIndex2);
  4829. end;
  4830. { Initialize brush }
  4831. if not ToolbarStyle and IsSelected then begin
  4832. {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
  4833. if AreFlatMenusEnabled then
  4834. { Windows XP uses a different fill color for selected menu items when
  4835. flat menus are enabled }
  4836. DrawCanvas.Brush.Color := clMenuHighlight
  4837. else
  4838. {$ENDIF}
  4839. DrawCanvas.Brush.Color := clHighlight;
  4840. end
  4841. else
  4842. DrawCanvas.Brush.Style := bsClear;
  4843. { Initialize font }
  4844. DrawCanvas.Font.Assign(GetFont);
  4845. if Viewer.Item.Enabled then begin
  4846. if not ToolbarStyle and IsSelected then
  4847. DrawCanvas.Font.Color := clHighlightText
  4848. else begin
  4849. if ToolbarStyle then
  4850. DrawCanvas.Font.Color := clBtnText
  4851. else
  4852. DrawCanvas.Font.Color := tbMenuTextColor;
  4853. end;
  4854. UseDisabledShadow := False;
  4855. end
  4856. else begin
  4857. DrawCanvas.Font.Color := clGrayText;
  4858. { Use the disabled shadow if either:
  4859. 1. The item is a toolbar-style item.
  4860. 2. The item is not selected, and the background color equals the
  4861. button-face color.
  4862. 3. The gray-text color is the same as the background color.
  4863. Note: Windows actually uses dithered text in this case. }
  4864. BkColor := ColorToRGB(TControlAccess(FWindow).Color);
  4865. UseDisabledShadow := ToolbarStyle or
  4866. (not IsSelected and (BkColor = ColorToRGB(clBtnFace))) or
  4867. (ColorToRGB(clGrayText) = BkColor);
  4868. end;
  4869. Viewer.Paint(DrawCanvas, R2, IsSelected, IsPushed, UseDisabledShadow);
  4870. if Offscreen then
  4871. BitBlt(DrawToDC, R1.Left, R1.Top, Bmp.Width, Bmp.Height, DrawCanvas.Handle,
  4872. 0, 0, SRCCOPY);
  4873. finally
  4874. DrawTo.Refresh; { must do this before a RestoreDC }
  4875. RestoreDC(DrawToDC, SaveIndex);
  4876. Bmp.Free;
  4877. end;
  4878. end;
  4879. procedure TTBView.DrawSubitems(ACanvas: TCanvas);
  4880. var
  4881. I: Integer;
  4882. begin
  4883. for I := 0 to FViewerCount-1 do begin
  4884. if (vsDrawInOrder in FState) or (FViewers[I] <> FSelected) then
  4885. DrawItem(FViewers[I], ACanvas, False);
  4886. end;
  4887. if not(vsDrawInOrder in FState) and Assigned(FSelected) then
  4888. DrawItem(FSelected, ACanvas, False);
  4889. Exclude(FState, vsDrawInOrder);
  4890. end;
  4891. procedure TTBView.Invalidate(AViewer: TTBItemViewer);
  4892. begin
  4893. if not FValidated or not Assigned(FWindow) or not FWindow.HandleAllocated then
  4894. Exit;
  4895. if AViewer.Show and not IsRectEmpty(AViewer.BoundsRect) and
  4896. not(AViewer.Item is TTBControlItem) then begin
  4897. Include(AViewer.State, tbisInvalidated);
  4898. InvalidateRect(FWindow.Handle, @AViewer.BoundsRect, False);
  4899. end;
  4900. end;
  4901. procedure TTBView.SetAccelsVisibility(AShowAccels: Boolean);
  4902. var
  4903. I: Integer;
  4904. Viewer: TTBItemViewer;
  4905. begin
  4906. { Always show accels when keyboard cues are enabled }
  4907. AShowAccels := AShowAccels or not(vsUseHiddenAccels in FStyle) or
  4908. AreKeyboardCuesEnabled;
  4909. if AShowAccels <> (vsShowAccels in FState) then begin
  4910. if AShowAccels then
  4911. Include(FState, vsShowAccels)
  4912. else
  4913. Exclude(FState, vsShowAccels);
  4914. if Assigned(FWindow) and FWindow.HandleAllocated and
  4915. IsWindowVisible(FWindow.Handle) then
  4916. { ^ the visibility check is just an optimization }
  4917. for I := 0 to FViewerCount-1 do begin
  4918. Viewer := FViewers[I];
  4919. if Viewer.CaptionShown and
  4920. (FindAccelChar(Viewer.GetCaptionText) <> #0) then
  4921. Invalidate(Viewer);
  4922. end;
  4923. end;
  4924. end;
  4925. function TTBView.FirstSelectable: TTBItemViewer;
  4926. var
  4927. FirstViewer: TTBItemViewer;
  4928. begin
  4929. Result := NextSelectable(nil, True);
  4930. if Assigned(Result) then begin
  4931. FirstViewer := Result;
  4932. while tbisDontSelectFirst in Result.Item.ItemStyle do begin
  4933. Result := NextSelectable(Result, True);
  4934. if Result = FirstViewer then
  4935. { don't loop endlessly if all items have the tbisDontSelectFirst style }
  4936. Break;
  4937. end;
  4938. end;
  4939. end;
  4940. function TTBView.NextSelectable(CurViewer: TTBItemViewer;
  4941. GoForward: Boolean): TTBItemViewer;
  4942. var
  4943. I, J: Integer;
  4944. begin
  4945. ValidatePositions;
  4946. Result := nil;
  4947. if FViewerCount = 0 then Exit;
  4948. J := -1;
  4949. I := IndexOf(CurViewer);
  4950. while True do begin
  4951. if GoForward then begin
  4952. Inc(I);
  4953. if I >= FViewerCount then I := 0;
  4954. end
  4955. else begin
  4956. Dec(I);
  4957. if I < 0 then I := FViewerCount-1;
  4958. end;
  4959. if J = -1 then
  4960. J := I
  4961. else
  4962. if I = J then
  4963. Exit;
  4964. if (FViewers[I].Show or FViewers[I].Clipped) and FViewers[I].Item.Visible and
  4965. (tbisSelectable in FViewers[I].Item.ItemStyle) then
  4966. Break;
  4967. end;
  4968. Result := FViewers[I];
  4969. end;
  4970. function TTBView.NextSelectableWithAccel(CurViewer: TTBItemViewer;
  4971. Key: Char; RequirePrimaryAccel: Boolean; var IsOnlyItemWithAccel: Boolean): TTBItemViewer;
  4972. function IsAccelItem(const Index: Integer;
  4973. const Primary, EnabledItems: Boolean): Boolean;
  4974. var
  4975. S: String;
  4976. LastAccel: Char;
  4977. Viewer: TTBItemViewer;
  4978. Item: TTBCustomItem;
  4979. begin
  4980. Result := False;
  4981. Viewer := FViewers[Index];
  4982. Item := Viewer.Item;
  4983. if (Viewer.Show or Viewer.Clipped) and (tbisSelectable in Item.ItemStyle) and
  4984. (Item.Enabled = EnabledItems) and
  4985. Item.Visible and Viewer.CaptionShown then begin
  4986. S := Viewer.GetCaptionText;
  4987. if S <> '' then begin
  4988. LastAccel := FindAccelChar(S);
  4989. if Primary then begin
  4990. if LastAccel <> #0 then
  4991. Result := AnsiCompareText(LastAccel, Key) = 0;
  4992. end
  4993. else
  4994. if (LastAccel = #0) and (Key <> ' ') then
  4995. Result := AnsiCompareText(S[1], Key) = 0;
  4996. end;
  4997. end;
  4998. end;
  4999. function FindAccel(I: Integer;
  5000. const Primary, EnabledItems: Boolean): Integer;
  5001. var
  5002. J: Integer;
  5003. begin
  5004. Result := -1;
  5005. J := -1;
  5006. while True do begin
  5007. Inc(I);
  5008. if I >= FViewerCount then I := 0;
  5009. if J = -1 then
  5010. J := I
  5011. else
  5012. if I = J then
  5013. Break;
  5014. if IsAccelItem(I, Primary, EnabledItems) then begin
  5015. Result := I;
  5016. Break;
  5017. end;
  5018. end;
  5019. end;
  5020. var
  5021. Start, I: Integer;
  5022. Primary, EnabledItems: Boolean;
  5023. begin
  5024. ValidatePositions;
  5025. Result := nil;
  5026. IsOnlyItemWithAccel := False;
  5027. if FViewerCount = 0 then Exit;
  5028. Start := IndexOf(CurViewer);
  5029. for Primary := True downto False do
  5030. if not RequirePrimaryAccel or Primary then
  5031. for EnabledItems := True downto False do begin
  5032. I := FindAccel(Start, Primary, EnabledItems);
  5033. if I <> -1 then begin
  5034. Result := FViewers[I];
  5035. IsOnlyItemWithAccel := not EnabledItems or
  5036. (FindAccel(I, Primary, EnabledItems) = I);
  5037. Exit;
  5038. end;
  5039. end;
  5040. end;
  5041. procedure TTBView.EnterToolbarLoop(Options: TTBEnterToolbarLoopOptions);
  5042. var
  5043. ModalHandler: TTBModalHandler;
  5044. P: TPoint;
  5045. begin
  5046. if vsModal in FState then Exit;
  5047. ModalHandler := TTBModalHandler.Create(FWindow.Handle);
  5048. try
  5049. { remove all states except... }
  5050. FState := FState * [vsShowAccels];
  5051. try
  5052. Include(FState, vsModal);
  5053. { Must ensure that DoneAction is reset to tbdaNone *before* calling
  5054. NotifyFocusEvent so that the IsModalEnding call it makes won't return
  5055. True }
  5056. FDoneActionData.DoneAction := tbdaNone;
  5057. { Now that the vsModal state has been added, send an MSAA focus event }
  5058. if Assigned(Selected) then
  5059. NotifyFocusEvent;
  5060. ModalHandler.Loop(Self, tbetMouseDown in Options,
  5061. tbetExecuteSelected in Options, tbetFromMSAA in Options, False);
  5062. finally
  5063. { Remove vsModal state from the root view before any TTBView.Destroy
  5064. methods get called (as a result of the CloseChildPopups call below),
  5065. so that NotifyFocusEvent becomes a no-op }
  5066. Exclude(FState, vsModal);
  5067. StopAllTimers;
  5068. CloseChildPopups;
  5069. GetCursorPos(P);
  5070. UpdateSelection(@P, True);
  5071. end;
  5072. finally
  5073. ModalHandler.Free;
  5074. end;
  5075. SetAccelsVisibility(False);
  5076. Selected := nil;
  5077. // caused flicker: FWindow.Update;
  5078. ProcessDoneAction(FDoneActionData, False);
  5079. end;
  5080. procedure TTBView.SetCustomizing(Value: Boolean);
  5081. begin
  5082. if FCustomizing <> Value then begin
  5083. FCustomizing := Value;
  5084. RecreateAllViewers;
  5085. end;
  5086. end;
  5087. procedure TTBView.BeginUpdate;
  5088. begin
  5089. Inc(FUpdating);
  5090. end;
  5091. procedure TTBView.EndUpdate;
  5092. begin
  5093. Dec(FUpdating);
  5094. if FUpdating = 0 then
  5095. TryValidatePositions;
  5096. end;
  5097. procedure TTBView.GetOffEdgeControlList(const List: TList);
  5098. var
  5099. I: Integer;
  5100. Item: TTBCustomItem;
  5101. begin
  5102. for I := 0 to FViewerCount-1 do begin
  5103. Item := FViewers[I].Item;
  5104. if (Item is TTBControlItem) and FViewers[I].OffEdge and
  5105. (TTBControlItem(Item).FControl is TWinControl) then
  5106. List.Add(TTBControlItem(Item).FControl);
  5107. end;
  5108. end;
  5109. procedure TTBView.SetCapture;
  5110. begin
  5111. FCapture := True;
  5112. end;
  5113. procedure TTBView.CancelCapture;
  5114. begin
  5115. if FCapture then begin
  5116. FCapture := False;
  5117. LastPos.X := Low(LastPos.X);
  5118. if Assigned(FSelected) then
  5119. FSelected.LosingCapture;
  5120. end;
  5121. end;
  5122. procedure TTBView.KeyDown(var Key: Word; Shift: TShiftState);
  5123. procedure SelNextItem(const ParentView: TTBView; const GoForward: Boolean);
  5124. begin
  5125. ParentView.Selected := ParentView.NextSelectable(ParentView.FSelected,
  5126. GoForward);
  5127. ParentView.ScrollSelectedIntoView;
  5128. end;
  5129. procedure HelpKey;
  5130. var
  5131. V: TTBView;
  5132. ContextID: Integer;
  5133. begin
  5134. ContextID := 0;
  5135. V := Self;
  5136. while Assigned(V) do begin
  5137. if Assigned(V.FSelected) then begin
  5138. ContextID := V.FSelected.Item.HelpContext;
  5139. if ContextID <> 0 then Break;
  5140. end;
  5141. V := V.FParentView;
  5142. end;
  5143. if ContextID <> 0 then
  5144. EndModalWithHelp(ContextID);
  5145. end;
  5146. var
  5147. ParentTBView: TTBView;
  5148. begin
  5149. ParentTBView := GetParentToolbarView;
  5150. case Key of
  5151. VK_TAB: begin
  5152. SelNextItem(Self, GetKeyState(VK_SHIFT) >= 0);
  5153. end;
  5154. VK_RETURN: begin
  5155. ExecuteSelected(True);
  5156. end;
  5157. VK_MENU, VK_F10: begin
  5158. EndModal;
  5159. end;
  5160. VK_ESCAPE: begin
  5161. Key := 0;
  5162. if FParentView = nil then
  5163. EndModal
  5164. else
  5165. FParentView.CancelChildPopups;
  5166. end;
  5167. VK_LEFT, VK_RIGHT: begin
  5168. if (Self = ParentTBView) and (Orientation = tbvoVertical) then
  5169. OpenChildPopup(True)
  5170. else if Key = VK_LEFT then begin
  5171. if Assigned(ParentTBView) and (ParentTBView.Orientation <> tbvoVertical) then begin
  5172. if (Self = ParentTBView) or
  5173. (FParentView = ParentTBView) then
  5174. SelNextItem(ParentTBView, False)
  5175. else
  5176. FParentView.CloseChildPopups;
  5177. end
  5178. else begin
  5179. if Assigned(FParentView) then
  5180. FParentView.CancelChildPopups;
  5181. end;
  5182. end
  5183. else begin
  5184. if ((Self = ParentTBView) or not OpenChildPopup(True)) and
  5185. (Assigned(ParentTBView) and (ParentTBView.Orientation <> tbvoVertical)) then begin
  5186. { If we're on ParentTBView, or if the selected item can't display
  5187. a submenu, proceed to next item on ParentTBView }
  5188. SelNextItem(ParentTBView, True);
  5189. end;
  5190. end;
  5191. end;
  5192. VK_UP, VK_DOWN: begin
  5193. if (Self = ParentTBView) and (Orientation <> tbvoVertical) then
  5194. OpenChildPopup(True)
  5195. else
  5196. SelNextItem(Self, Key = VK_DOWN);
  5197. end;
  5198. VK_HOME, VK_END: begin
  5199. Selected := NextSelectable(nil, Key = VK_HOME);
  5200. ScrollSelectedIntoView;
  5201. end;
  5202. VK_F1: HelpKey;
  5203. else
  5204. Exit; { don't set Key to 0 for unprocessed keys }
  5205. end;
  5206. Key := 0;
  5207. end;
  5208. function TTBView.IsModalEnding: Boolean;
  5209. begin
  5210. Result := (GetRootView.FDoneActionData.DoneAction <> tbdaNone);
  5211. end;
  5212. procedure TTBView.EndModal;
  5213. var
  5214. RootView: TTBView;
  5215. begin
  5216. RootView := GetRootView;
  5217. RootView.FDoneActionData.DoneAction := tbdaCancel;
  5218. end;
  5219. procedure TTBView.EndModalWithClick(AViewer: TTBItemViewer);
  5220. var
  5221. RootView: TTBView;
  5222. begin
  5223. RootView := GetRootView;
  5224. RootView.FDoneActionData.ClickItem := AViewer.Item;
  5225. RootView.FDoneActionData.Sound := AViewer.FView.FIsPopup;
  5226. RootView.FDoneActionData.DoneAction := tbdaClickItem;
  5227. end;
  5228. procedure TTBView.EndModalWithHelp(AContextID: Integer);
  5229. var
  5230. RootView: TTBView;
  5231. begin
  5232. RootView := GetRootView;
  5233. RootView.FDoneActionData.ContextID := AContextID;
  5234. RootView.FDoneActionData.DoneAction := tbdaHelpContext;
  5235. end;
  5236. procedure TTBView.EndModalWithSystemMenu(AWnd: HWND; AKey: Cardinal);
  5237. var
  5238. RootView: TTBView;
  5239. begin
  5240. RootView := GetRootView;
  5241. RootView.FDoneActionData.Wnd := AWnd;
  5242. RootView.FDoneActionData.Key := AKey;
  5243. RootView.FDoneActionData.DoneAction := tbdaOpenSystemMenu;
  5244. end;
  5245. procedure TTBView.ExecuteSelected(AGivePriority: Boolean);
  5246. { Normally called after an Enter or accelerator key press on the view, this
  5247. method 'executes' or opens the selected item. It ends the modal loop, except
  5248. when a submenu is opened. }
  5249. var
  5250. Item: TTBCustomItem;
  5251. begin
  5252. if Assigned(FSelected) and FSelected.Item.Enabled then begin
  5253. Item := FSelected.Item;
  5254. if (tbisCombo in Item.ItemStyle) or not OpenChildPopup(True) then begin
  5255. if tbisSelectable in Item.ItemStyle then
  5256. FSelected.Execute(AGivePriority)
  5257. else
  5258. EndModal;
  5259. end
  5260. end
  5261. else
  5262. EndModal;
  5263. Exit; asm db 0,'Toolbar2000 (C) 1998-2005 Jordan Russell',0 end;
  5264. end;
  5265. procedure TTBView.Scroll(ADown: Boolean);
  5266. var
  5267. CurPos, NewPos, I: Integer;
  5268. begin
  5269. ValidatePositions;
  5270. if ADown then begin
  5271. NewPos := High(NewPos);
  5272. CurPos := FMaxHeight - tbMenuScrollArrowHeight;
  5273. for I := 0 to FViewerCount-1 do begin
  5274. with FViewers[I] do
  5275. if Clipped and not(tbisSeparator in Item.ItemStyle) and
  5276. (BoundsRect.Bottom < NewPos) and (BoundsRect.Bottom > CurPos) then
  5277. NewPos := BoundsRect.Bottom;
  5278. end;
  5279. if NewPos = High(NewPos) then
  5280. Exit;
  5281. Dec(NewPos, FMaxHeight - tbMenuScrollArrowHeight);
  5282. end
  5283. else begin
  5284. NewPos := Low(NewPos);
  5285. CurPos := tbMenuScrollArrowHeight;
  5286. for I := 0 to FViewerCount-1 do begin
  5287. with FViewers[I] do
  5288. if Clipped and not(tbisSeparator in Item.ItemStyle) and
  5289. (BoundsRect.Top > NewPos) and (BoundsRect.Top < CurPos) then
  5290. NewPos := BoundsRect.Top;
  5291. end;
  5292. if NewPos = Low(NewPos) then
  5293. Exit;
  5294. Dec(NewPos, tbMenuScrollArrowHeight);
  5295. end;
  5296. Inc(FScrollOffset, NewPos);
  5297. UpdatePositions;
  5298. end;
  5299. procedure TTBView.ScrollSelectedIntoView;
  5300. begin
  5301. ValidatePositions;
  5302. if (FSelected = nil) or not FSelected.Clipped then
  5303. Exit;
  5304. if FSelected.BoundsRect.Top < tbMenuScrollArrowHeight then begin
  5305. Dec(FScrollOffset, tbMenuScrollArrowHeight - FSelected.BoundsRect.Top);
  5306. UpdatePositions;
  5307. end
  5308. else if FSelected.BoundsRect.Bottom > FMaxHeight - tbMenuScrollArrowHeight then begin
  5309. Dec(FScrollOffset, (FMaxHeight - tbMenuScrollArrowHeight) -
  5310. FSelected.BoundsRect.Bottom);
  5311. UpdatePositions;
  5312. end;
  5313. end;
  5314. procedure TTBView.SetUsePriorityList(Value: Boolean);
  5315. begin
  5316. if FUsePriorityList <> Value then begin
  5317. FUsePriorityList := Value;
  5318. RecreateAllViewers;
  5319. end;
  5320. end;
  5321. function TTBView.GetCaptureWnd: HWND;
  5322. begin
  5323. Result := GetRootView.FCaptureWnd;
  5324. end;
  5325. procedure TTBView.CancelMode;
  5326. var
  5327. View: TTBView;
  5328. begin
  5329. EndModal;
  5330. { Hide all parent/child popup windows. Can't actually destroy them using
  5331. CloseChildPopups because this method may be called while inside
  5332. TTBEditItemViewer's message loop, and it could result in the active
  5333. TTBEditItemViewer instance being destroyed (leading to an AV). }
  5334. View := Self;
  5335. while Assigned(View.FOpenViewerView) do
  5336. View := View.FOpenViewerView;
  5337. repeat
  5338. View.StopAllTimers;
  5339. if View.FWindow is TTBPopupWindow then
  5340. View.FWindow.Visible := False;
  5341. View := View.FParentView;
  5342. until View = nil;
  5343. { Note: This doesn't remove the selection from a top-level toolbar item.
  5344. Unfortunately, we can't do 'Selected := nil' because it would destroy
  5345. child popups and that must'nt happen for the reason stated above. }
  5346. end;
  5347. procedure TTBView.SetState(AState: TTBViewState);
  5348. begin
  5349. FState := AState;
  5350. end;
  5351. { TTBModalHandler }
  5352. const
  5353. LSFW_LOCK = 1;
  5354. LSFW_UNLOCK = 2;
  5355. var
  5356. LockSetForegroundWindowInited: BOOL;
  5357. LockSetForegroundWindow: function(uLockCode: UINT): BOOL; stdcall;
  5358. constructor TTBModalHandler.Create(AExistingWnd: HWND);
  5359. begin
  5360. inherited Create;
  5361. if not LockSetForegroundWindowInited then begin
  5362. LockSetForegroundWindow := GetProcAddress(GetModuleHandle(user32),
  5363. 'LockSetForegroundWindow');
  5364. InterlockedExchange(Integer(LockSetForegroundWindowInited), Ord(True));
  5365. end;
  5366. LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
  5367. if AExistingWnd <> 0 then
  5368. FWnd := AExistingWnd
  5369. else begin
  5370. FWnd := {$IFDEF JR_D6}Classes.{$ENDIF} AllocateHWnd(WndProc);
  5371. FCreatedWnd := True;
  5372. end;
  5373. if Assigned(LockSetForegroundWindow) then begin
  5374. { Like standard menus, don't allow other apps to steal the focus during
  5375. our modal loop. This also prevents us from losing activation when
  5376. "active window tracking" is enabled and the user moves the mouse over
  5377. another application's window. }
  5378. LockSetForegroundWindow(LSFW_LOCK);
  5379. end;
  5380. SetCapture(FWnd);
  5381. SetCursor(LoadCursor(0, IDC_ARROW));
  5382. CallNotifyWinEvent(EVENT_SYSTEM_MENUSTART, FWnd, OBJID_CLIENT, CHILDID_SELF);
  5383. FInited := True;
  5384. end;
  5385. destructor TTBModalHandler.Destroy;
  5386. begin
  5387. if Assigned(LockSetForegroundWindow) then
  5388. LockSetForegroundWindow(LSFW_UNLOCK);
  5389. if FWnd <> 0 then begin
  5390. if GetCapture = FWnd then
  5391. ReleaseCapture;
  5392. if FInited then
  5393. CallNotifyWinEvent(EVENT_SYSTEM_MENUEND, FWnd, OBJID_CLIENT, CHILDID_SELF);
  5394. if FCreatedWnd then
  5395. {$IFDEF JR_D6}Classes.{$ENDIF} DeallocateHWnd(FWnd);
  5396. end;
  5397. inherited;
  5398. end;
  5399. procedure TTBModalHandler.WndProc(var Msg: TMessage);
  5400. begin
  5401. Msg.Result := DefWindowProc(FWnd, Msg.Msg, Msg.WParam, Msg.LParam);
  5402. if (Msg.Msg = WM_CANCELMODE) and Assigned(FRootPopup) then begin
  5403. try
  5404. { We can receive a WM_CANCELMODE message during a modal loop if a dialog
  5405. pops up. Respond by hiding menus to make it look like the modal loop
  5406. has returned, even though it really hasn't yet.
  5407. Note: Similar code in TTBCustomToolbar.WMCancelMode. }
  5408. FRootPopup.View.CancelMode;
  5409. except
  5410. Application.HandleException(Self);
  5411. end;
  5412. end;
  5413. end;
  5414. procedure TTBModalHandler.Loop(const RootView: TTBView;
  5415. const AMouseDown, AExecuteSelected, AFromMSAA, TrackRightButton: Boolean);
  5416. var
  5417. OriginalActiveWindow: HWND;
  5418. function GetActiveView: TTBView;
  5419. begin
  5420. Result := RootView;
  5421. while Assigned(Result.FOpenViewerView) do
  5422. Result := Result.FOpenViewerView;
  5423. end;
  5424. procedure UpdateAllSelections(const P: TPoint; const AllowNewSelection: Boolean);
  5425. var
  5426. View, CapView: TTBView;
  5427. begin
  5428. View := GetActiveView;
  5429. CapView := View;
  5430. while Assigned(CapView) and not CapView.FCapture do
  5431. CapView := CapView.FParentView;
  5432. while Assigned(View) do begin
  5433. if (CapView = nil) or (View = CapView) then
  5434. View.UpdateSelection(@P, AllowNewSelection);
  5435. View := View.FParentView;
  5436. end;
  5437. end;
  5438. function GetSelectedViewer(var AView: TTBView; var AViewer: TTBItemViewer): Boolean;
  5439. { Returns True if AViewer <> nil. }
  5440. var
  5441. View: TTBView;
  5442. begin
  5443. AView := nil;
  5444. AViewer := nil;
  5445. { Look for a capture item first }
  5446. View := RootView;
  5447. repeat
  5448. if View.FCapture then begin
  5449. AView := View;
  5450. AViewer := View.FSelected;
  5451. Break;
  5452. end;
  5453. View := View.FOpenViewerView;
  5454. until View = nil;
  5455. if View = nil then begin
  5456. View := RootView;
  5457. repeat
  5458. if Assigned(View.FSelected) and View.FMouseOverSelected then begin
  5459. AView := View;
  5460. AViewer := View.FSelected;
  5461. Break;
  5462. end;
  5463. if vsMouseInWindow in View.FState then begin
  5464. { ...there is no current selection, but the mouse is still in the
  5465. window. This can happen if the mouse is over the non-client area
  5466. of the toolbar or popup window, or in an area not containing an
  5467. item. }
  5468. AView := View;
  5469. Break;
  5470. end;
  5471. View := View.FOpenViewerView;
  5472. until View = nil;
  5473. end;
  5474. Result := Assigned(AViewer);
  5475. end;
  5476. function ContinueLoop: Boolean;
  5477. begin
  5478. { Don't continue if the mouse capture is lost, if a (modeless) top-level
  5479. window is shown causing the active window to change, or if EndModal* was
  5480. called. }
  5481. Result := (GetCapture = FWnd) and (GetActiveWindow = OriginalActiveWindow)
  5482. and not RootView.IsModalEnding;
  5483. end;
  5484. function SendKeyEvent(const View: TTBView; var Key: Word;
  5485. const Shift: TShiftState): Boolean;
  5486. begin
  5487. Result := True;
  5488. if Assigned(View.FSelected) then begin
  5489. View.FSelected.KeyDown(Key, Shift);
  5490. if RootView.IsModalEnding then
  5491. Exit;
  5492. end;
  5493. if Key <> 0 then begin
  5494. View.KeyDown(Key, Shift);
  5495. if RootView.IsModalEnding then
  5496. Exit;
  5497. end;
  5498. Result := False;
  5499. end;
  5500. procedure DoHintMouseMessage(const Ctl: TControl; const P: TPoint);
  5501. var
  5502. M: TWMMouseMove;
  5503. begin
  5504. M.Msg := WM_MOUSEMOVE;
  5505. M.Keys := 0;
  5506. M.Pos := PointToSmallPoint(P);
  5507. Application.HintMouseMessage(Ctl, TMessage(M));
  5508. end;
  5509. procedure MouseMoved;
  5510. var
  5511. View: TTBView;
  5512. Cursor: HCURSOR;
  5513. Item: TTBCustomItem;
  5514. P: TPoint;
  5515. R: TRect;
  5516. begin
  5517. UpdateAllSelections(LastPos, True);
  5518. View := GetActiveView;
  5519. Cursor := 0;
  5520. if Assigned(View.FSelected) and Assigned(View.FWindow) then begin
  5521. Item := View.FSelected.Item;
  5522. P := View.FWindow.ScreenToClient(LastPos);
  5523. if ((vsAlwaysShowHints in View.FStyle) or
  5524. (tboShowHint in Item.FEffectiveOptions)) and not View.FCapture then begin
  5525. { Display popup hint for the item. Update is called
  5526. first to minimize flicker caused by the hiding &
  5527. showing of the hint window. }
  5528. View.FWindow.Update;
  5529. DoHintMouseMessage(View.FWindow, P);
  5530. end
  5531. else
  5532. Application.CancelHint;
  5533. R := View.FSelected.BoundsRect;
  5534. Dec(P.X, R.Left);
  5535. Dec(P.Y, R.Top);
  5536. View.FSelected.GetCursor(P, Cursor);
  5537. end
  5538. else
  5539. Application.CancelHint;
  5540. if Cursor = 0 then
  5541. Cursor := LoadCursor(0, IDC_ARROW);
  5542. SetCursor(Cursor);
  5543. end;
  5544. procedure UpdateAppHint;
  5545. var
  5546. View: TTBView;
  5547. begin
  5548. View := RootView;
  5549. while Assigned(View.FOpenViewerView) and Assigned(View.FOpenViewerView.FSelected) do
  5550. View := View.FOpenViewerView;
  5551. if Assigned(View.FSelected) then
  5552. Application.Hint := GetLongHint(View.FSelected.Item.Hint)
  5553. else
  5554. Application.Hint := '';
  5555. end;
  5556. procedure HandleTimer(const View: TTBView; const ID: TTBViewTimerID);
  5557. begin
  5558. case ID of
  5559. tiOpen: begin
  5560. { Similar to standard menus, always close child popups, even if
  5561. Selected = OpenViewer.
  5562. Note: CloseChildPopups and OpenChildPopup will stop the tiClose
  5563. and tiOpen timers respectively. }
  5564. View.CloseChildPopups;
  5565. View.OpenChildPopup(False);
  5566. end;
  5567. tiClose: begin
  5568. { Note: CloseChildPopups stops the tiClose timer. }
  5569. View.CloseChildPopups;
  5570. end;
  5571. tiScrollUp: begin
  5572. if View.FShowUpArrow then
  5573. View.Scroll(False)
  5574. else
  5575. View.StopTimer(tiScrollUp);
  5576. end;
  5577. tiScrollDown: begin
  5578. if View.FShowDownArrow then
  5579. View.Scroll(True)
  5580. else
  5581. View.StopTimer(tiScrollDown);
  5582. end;
  5583. end;
  5584. end;
  5585. var
  5586. MouseDownOnMenu: Boolean;
  5587. Msg: TMsg;
  5588. P: TPoint;
  5589. Ctl: TControl;
  5590. View: TTBView;
  5591. IsOnlyItemWithAccel: Boolean;
  5592. MouseIsDown: Boolean;
  5593. Key: Word;
  5594. Shift: TShiftState;
  5595. Viewer: TTBItemViewer;
  5596. begin
  5597. FillChar(RootView.FDoneActionData, SizeOf(RootView.FDoneActionData), 0);
  5598. RootView.ValidatePositions;
  5599. try
  5600. try
  5601. RootView.FCaptureWnd := FWnd;
  5602. MouseDownOnMenu := False;
  5603. if AMouseDown then begin
  5604. P := RootView.FSelected.ScreenToClient(SmallPointToPoint(TSmallPoint(GetMessagePos())));
  5605. RootView.FSelected.MouseDown([], P.X, P.Y, MouseDownOnMenu);
  5606. if RootView.IsModalEnding then
  5607. Exit;
  5608. MouseDownOnMenu := False; { never set MouseDownOnMenu to True on first click }
  5609. end
  5610. else if AExecuteSelected then begin
  5611. RootView.ExecuteSelected(not AFromMSAA);
  5612. if RootView.IsModalEnding then
  5613. Exit;
  5614. end;
  5615. OriginalActiveWindow := GetActiveWindow;
  5616. while ContinueLoop do begin
  5617. { Examine the next message before popping it out of the queue }
  5618. if not PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then begin
  5619. WaitMessage;
  5620. Continue;
  5621. end;
  5622. case Msg.message of
  5623. WM_LBUTTONDOWN, WM_RBUTTONDOWN: begin
  5624. P := SmallPointToPoint(TSmallPoint(Msg.lParam));
  5625. Windows.ClientToScreen(Msg.hwnd, P);
  5626. Ctl := FindDragTarget(P, True);
  5627. { Was the mouse not clicked on a popup, or was it clicked on a
  5628. popup that is not a child of RootView?
  5629. (The latter can happen when in customization mode, for example,
  5630. if the user right-clicks a popup menu being customized and
  5631. the context menu is displayed.) }
  5632. if not(Ctl is TTBPopupWindow) or
  5633. not RootView.ContainsView(TTBPopupWindow(Ctl).View) then begin
  5634. { If the root view is a popup, or if the root view is a toolbar
  5635. and the user clicked outside the toolbar or in its non-client
  5636. area (e.g. on its drag handle), exit }
  5637. if RootView.FIsPopup or (Ctl <> RootView.FWindow) or
  5638. not PtInRect(RootView.FWindow.ClientRect, RootView.FWindow.ScreenToClient(P)) then
  5639. Exit
  5640. else
  5641. if Msg.message = WM_LBUTTONDOWN then begin
  5642. { If the user clicked inside a toolbar on anything but an
  5643. item, exit }
  5644. UpdateAllSelections(P, True);
  5645. if (RootView.FSelected = nil) or not RootView.FMouseOverSelected or
  5646. (tbisClicksTransparent in RootView.FSelected.Item.ItemStyle) then
  5647. Exit;
  5648. end;
  5649. end;
  5650. end;
  5651. end;
  5652. { Now pop the message out of the queue }
  5653. if not PeekMessage(Msg, 0, Msg.message, Msg.message, PM_REMOVE or PM_NOYIELD) then
  5654. Continue;
  5655. case Msg.message of
  5656. $4D:
  5657. { This undocumented message is sent to the focused window when
  5658. F1 is pressed. Windows handles it by sending a WM_HELP message
  5659. to the same window. We don't want this to happen while a menu
  5660. is up, so swallow the message. }
  5661. ;
  5662. WM_CONTEXTMENU:
  5663. { Windows still sends WM_CONTEXTMENU messages for "context menu"
  5664. keystrokes even if WM_KEYUP messages are never dispatched,
  5665. so it must specifically ignore this message }
  5666. ;
  5667. WM_KEYFIRST..WM_KEYLAST: begin
  5668. Application.CancelHint;
  5669. MouseIsDown := (GetKeyState(VK_LBUTTON) < 0) or
  5670. (TrackRightButton and (GetKeyState(VK_RBUTTON) < 0));
  5671. case Msg.message of
  5672. WM_KEYDOWN, WM_SYSKEYDOWN:
  5673. begin
  5674. if Msg.wParam = VK_PROCESSKEY then
  5675. { Don't let IME process the key }
  5676. Msg.wParam := ImmGetVirtualKey(Msg.hwnd);
  5677. if not MouseIsDown or (Msg.wParam = VK_F1) then begin
  5678. Key := Word(Msg.wParam);
  5679. if SendKeyEvent(GetActiveView, Key,
  5680. KeyDataToShiftState(Msg.lParam)) then
  5681. Exit;
  5682. { If it's not handled by a KeyDown method, translate
  5683. it into a WM_*CHAR message }
  5684. if Key <> 0 then
  5685. TranslateMessage(Msg);
  5686. end;
  5687. end;
  5688. WM_CHAR, WM_SYSCHAR:
  5689. if not MouseIsDown then begin
  5690. View := GetActiveView;
  5691. Viewer := View.NextSelectableWithAccel(View.FSelected,
  5692. Chr(Msg.WParam), False, IsOnlyItemWithAccel);
  5693. if Viewer = nil then begin
  5694. if (Msg.WParam in [VK_SPACE, Ord('-')]) and
  5695. not RootView.FIsPopup and (View = RootView) and
  5696. (GetActiveWindow <> 0) then begin
  5697. RootView.EndModalWithSystemMenu(GetActiveWindow,
  5698. Msg.WParam);
  5699. Exit;
  5700. end
  5701. else
  5702. MessageBeep(0);
  5703. end
  5704. else begin
  5705. View.Selected := Viewer;
  5706. View.ScrollSelectedIntoView;
  5707. if IsOnlyItemWithAccel then
  5708. View.ExecuteSelected(True);
  5709. end;
  5710. end;
  5711. end;
  5712. end;
  5713. WM_TIMER:
  5714. begin
  5715. Ctl := FindControl(Msg.hwnd);
  5716. if Assigned(Ctl) and (Ctl is TTBPopupWindow) and
  5717. (Msg.wParam >= ViewTimerBaseID + Ord(Low(TTBViewTimerID))) and
  5718. (Msg.wParam <= ViewTimerBaseID + Ord(High(TTBViewTimerID))) then begin
  5719. if Assigned(TTBPopupWindow(Ctl).FView) then
  5720. HandleTimer(TTBPopupWindow(Ctl).FView,
  5721. TTBViewTimerID(WPARAM(Msg.wParam - ViewTimerBaseID)));
  5722. end
  5723. else
  5724. DispatchMessage(Msg);
  5725. end;
  5726. $118: ;
  5727. { ^ Like standard menus, don't dispatch WM_SYSTIMER messages
  5728. (the internal Windows message used for things like caret
  5729. blink and list box scrolling). }
  5730. WM_MOUSEFIRST..WM_MOUSELAST:
  5731. case Msg.message of
  5732. WM_MOUSEMOVE: begin
  5733. if (Msg.pt.X <> LastPos.X) or (Msg.pt.Y <> LastPos.Y) then begin
  5734. LastPos := Msg.pt;
  5735. MouseMoved;
  5736. end;
  5737. if GetSelectedViewer(View, Viewer) then begin
  5738. P := Viewer.ScreenToClient(Msg.pt);
  5739. Viewer.MouseMove(P.X, P.Y);
  5740. end;
  5741. end;
  5742. WM_MOUSEWHEEL:
  5743. if GetSelectedViewer(View, Viewer) then begin
  5744. P := Viewer.ScreenToClient(Msg.pt);
  5745. Viewer.MouseWheel(Smallint(LongRec(Msg.wParam).Hi), P.X, P.Y);
  5746. end;
  5747. WM_LBUTTONDOWN, WM_LBUTTONDBLCLK, WM_RBUTTONDOWN:
  5748. if (Msg.message <> WM_RBUTTONDOWN) or TrackRightButton then begin
  5749. Application.CancelHint;
  5750. MouseDownOnMenu := False;
  5751. Exclude(RootView.FState, vsIgnoreFirstMouseUp);
  5752. UpdateAllSelections(Msg.pt, True);
  5753. if GetSelectedViewer(View, Viewer) then begin
  5754. if Msg.message <> WM_LBUTTONDBLCLK then
  5755. Shift := []
  5756. else
  5757. Shift := [ssDouble];
  5758. P := Viewer.ScreenToClient(Msg.pt);
  5759. Viewer.MouseDown(Shift, P.X, P.Y, MouseDownOnMenu);
  5760. LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
  5761. end;
  5762. end;
  5763. WM_LBUTTONUP, WM_RBUTTONUP:
  5764. if (Msg.message = WM_LBUTTONUP) or TrackRightButton then begin
  5765. UpdateAllSelections(Msg.pt, False);
  5766. { ^ False is used so that when a popup menu is
  5767. displayed with the cursor currently inside it, the item
  5768. under the cursor won't be accidentally selected when the
  5769. user releases the button. The user must move the mouse at
  5770. at least one pixel (generating a WM_MOUSEMOVE message),
  5771. and then release the button. }
  5772. if not GetSelectedViewer(View, Viewer) then begin
  5773. { Mouse was not released over any item. Cancel out of the
  5774. loop if it's outside all views, or is inside unused
  5775. space on a topmost toolbar }
  5776. if not Assigned(View) or
  5777. ((View = RootView) and RootView.FIsToolbar) then begin
  5778. if not(vsIgnoreFirstMouseUp in RootView.FState) then
  5779. Exit
  5780. else
  5781. Exclude(RootView.FState, vsIgnoreFirstMouseUp);
  5782. end;
  5783. end
  5784. else begin
  5785. P := Viewer.ScreenToClient(Msg.pt);
  5786. Viewer.MouseUp(P.X, P.Y, MouseDownOnMenu);
  5787. end;
  5788. end;
  5789. end;
  5790. else
  5791. DispatchMessage(Msg);
  5792. end;
  5793. if not ContinueLoop then
  5794. Exit;
  5795. if LastPos.X = Low(LastPos.X) then begin
  5796. LastPos := SmallPointToPoint(TSmallPoint(GetMessagePos()));
  5797. MouseMoved;
  5798. end;
  5799. UpdateAppHint;
  5800. end;
  5801. finally
  5802. RootView.CancelCapture;
  5803. end;
  5804. finally
  5805. RootView.FCaptureWnd := 0;
  5806. Application.Hint := '';
  5807. { Make sure there are no outstanding WM_*CHAR messages }
  5808. RemoveMessages(WM_CHAR, WM_DEADCHAR);
  5809. RemoveMessages(WM_SYSCHAR, WM_SYSDEADCHAR);
  5810. { Nor any outstanding 'send WM_HELP' messages caused by an earlier press
  5811. of the F1 key }
  5812. RemoveMessages($4D, $4D);
  5813. end;
  5814. end;
  5815. { TTBPopupView }
  5816. procedure TTBPopupView.AutoSize(AWidth, AHeight: Integer);
  5817. begin
  5818. with TTBPopupWindow(FWindow) do
  5819. with GetNCSize do
  5820. SetBounds(Left, Top, AWidth + (X * 2),
  5821. AHeight + (Y * 2));
  5822. end;
  5823. function TTBPopupView.GetFont: TFont;
  5824. begin
  5825. Result := (Owner as TTBPopupWindow).Font;
  5826. end;
  5827. { TTBPopupWindow }
  5828. constructor TTBPopupWindow.CreatePopupWindow(AOwner: TComponent;
  5829. const AParentView: TTBView; const AItem: TTBCustomItem;
  5830. const ACustomizing: Boolean);
  5831. begin
  5832. inherited Create(AOwner);
  5833. Visible := False;
  5834. SetBounds(0, 0, 320, 240);
  5835. ControlStyle := ControlStyle - [csCaptureMouse];
  5836. ShowHint := True;
  5837. Color := tbMenuBkColor;
  5838. FView := GetViewClass.CreateView(Self, AParentView, AItem, Self, False,
  5839. ACustomizing, False);
  5840. Include(FView.FState, vsModal);
  5841. { Inherit the font from the parent view, or use the system menu font if
  5842. there is no parent view }
  5843. if Assigned(AParentView) then
  5844. Font.Assign(AParentView.GetFont)
  5845. else
  5846. Font.Assign(ToolbarFont);
  5847. { Inherit the accelerator visibility state from the parent view. If there
  5848. is no parent view (i.e. it's a standalone popup menu), then default to
  5849. hiding accelerator keys, but change this in CreateWnd if the last input
  5850. came from the keyboard. }
  5851. if Assigned(AParentView) then begin
  5852. if vsUseHiddenAccels in AParentView.FStyle then
  5853. Include(FView.FStyle, vsUseHiddenAccels);
  5854. if vsShowAccels in AParentView.FState then
  5855. Include(FView.FState, vsShowAccels);
  5856. end
  5857. else
  5858. Include(FView.FStyle, vsUseHiddenAccels);
  5859. if Application.Handle <> 0 then
  5860. { Use Application.Handle if possible so that the taskbar button for the app
  5861. doesn't pop up when a TTBEditItem on a popup menu is focused }
  5862. ParentWindow := Application.Handle
  5863. else
  5864. { When Application.Handle is zero, use GetDesktopWindow() as the parent
  5865. window, not zero, otherwise UpdateControlState won't show the window }
  5866. ParentWindow := GetDesktopWindow;
  5867. end;
  5868. destructor TTBPopupWindow.Destroy;
  5869. begin
  5870. Destroying;
  5871. { Ensure window handle is destroyed *before* FView is freed, since
  5872. DestroyWindowHandle calls CallNotifyWinEvent which may result in
  5873. FView.HandleWMObject being called }
  5874. if HandleAllocated then
  5875. DestroyWindowHandle;
  5876. FreeAndNil(FView);
  5877. inherited;
  5878. end;
  5879. procedure TTBPopupWindow.BeforeDestruction;
  5880. begin
  5881. { The inherited BeforeDestruction method hides the form. We need to close
  5882. any child popups first, so that pixels behind the popups are properly
  5883. restored without generating a WM_PAINT message. }
  5884. if Assigned(FView) then
  5885. FView.CloseChildPopups;
  5886. inherited;
  5887. end;
  5888. function TTBPopupWindow.GetNCSize: TPoint;
  5889. begin
  5890. Result.X := PopupMenuWindowNCSize;
  5891. Result.Y := PopupMenuWindowNCSize;
  5892. end;
  5893. function TTBPopupWindow.GetViewClass: TTBViewClass;
  5894. begin
  5895. Result := TTBPopupView;
  5896. end;
  5897. procedure TTBPopupWindow.CreateParams(var Params: TCreateParams);
  5898. const
  5899. CS_DROPSHADOW = $00020000;
  5900. begin
  5901. inherited;
  5902. with Params do begin
  5903. Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP;
  5904. ExStyle := ExStyle or WS_EX_TOPMOST or WS_EX_TOOLWINDOW;
  5905. WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  5906. { Enable drop shadow effect on Windows XP and later }
  5907. if IsWindowsXP then
  5908. WindowClass.Style := WindowClass.Style or CS_DROPSHADOW;
  5909. end;
  5910. end;
  5911. procedure TTBPopupWindow.CreateWnd;
  5912. const
  5913. WM_CHANGEUISTATE = $0127;
  5914. WM_QUERYUISTATE = $0129;
  5915. UIS_INITIALIZE = 3;
  5916. UISF_HIDEACCEL = $2;
  5917. var
  5918. B: Boolean;
  5919. begin
  5920. inherited;
  5921. { On a top-level popup window, send WM_CHANGEUISTATE & WM_QUERYUISTATE
  5922. messages to the window to see if the last input came from the keyboard
  5923. and if the accelerator keys should be shown }
  5924. if (FView.ParentView = nil) and not FAccelsVisibilitySet then begin
  5925. FAccelsVisibilitySet := True;
  5926. SendMessage(Handle, WM_CHANGEUISTATE, UIS_INITIALIZE, 0);
  5927. B := (SendMessage(Handle, WM_QUERYUISTATE, 0, 0) and UISF_HIDEACCEL = 0);
  5928. FView.SetAccelsVisibility(B);
  5929. end;
  5930. end;
  5931. procedure TTBPopupWindow.DestroyWindowHandle;
  5932. begin
  5933. { Before destroying the window handle, we must stop any animation, otherwise
  5934. the animation thread will use an invalid handle }
  5935. TBEndAnimation(WindowHandle);
  5936. { Cleanly destroy any timers before the window handle is destroyed }
  5937. if Assigned(FView) then
  5938. FView.StopAllTimers;
  5939. CallNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, WindowHandle, OBJID_CLIENT,
  5940. CHILDID_SELF);
  5941. inherited;
  5942. end;
  5943. procedure TTBPopupWindow.WMGetObject(var Message: TMessage);
  5944. begin
  5945. if not FView.HandleWMGetObject(Message) then
  5946. inherited;
  5947. end;
  5948. procedure TTBPopupWindow.CMShowingChanged(var Message: TMessage);
  5949. const
  5950. ShowFlags: array[Boolean] of UINT = (
  5951. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW,
  5952. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  5953. SPI_GETMENUFADE = $1012;
  5954. var
  5955. Animate: BOOL;
  5956. Blend: Boolean;
  5957. begin
  5958. { Must override TCustomForm/TForm's CM_SHOWINGCHANGED handler so that the
  5959. form doesn't get activated when Visible is set to True. }
  5960. { Handle animation. NOTE: I do not recommend trying to enable animation on
  5961. Windows 95 and NT 4.0 because there's a difference in the way the
  5962. SetWindowPos works on those versions. See the comment in the
  5963. TBStartAnimation function of TB2Anim.pas. }
  5964. {$IFNDEF TB2K_NO_ANIMATION}
  5965. if ((FView.ParentView = nil) or not(vsNoAnimation in FView.FParentView.FState)) and
  5966. Showing and (FView.Selected = nil) and not IsWindowVisible(WindowHandle) and
  5967. SystemParametersInfo(SPI_GETMENUANIMATION, 0, @Animate, 0) and Animate then begin
  5968. Blend := SystemParametersInfo(SPI_GETMENUFADE, 0, @Animate, 0) and Animate;
  5969. if Blend or (FAnimationDirection <> []) then begin
  5970. if SendMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_ANIMSTART, 0) = 0 then
  5971. begin
  5972. { Start animation only if WM_TB2K_POPUPSHOWING returns zero (or not handled) }
  5973. TBStartAnimation(WindowHandle, Blend, FAnimationDirection);
  5974. Exit;
  5975. end;
  5976. end;
  5977. end;
  5978. {$ENDIF}
  5979. { No animation... }
  5980. if not Showing then begin
  5981. { Call TBEndAnimation to ensure WS_EX_LAYERED style is removed before
  5982. hiding, otherwise windows under the popup window aren't repainted
  5983. properly. }
  5984. TBEndAnimation(WindowHandle);
  5985. end;
  5986. SetWindowPos(WindowHandle, 0, 0, 0, 0, 0, ShowFlags[Showing]);
  5987. if Showing then SendNotifyMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_NOANIM, 0);
  5988. end;
  5989. procedure TTBPopupWindow.WMTB2kAnimationEnded(var Message: TMessage);
  5990. begin
  5991. SendNotifyMessage(WindowHandle, WM_TB2K_POPUPSHOWING, TPS_ANIMFINISHED, 0);
  5992. end;
  5993. procedure TTBPopupWindow.WMTB2kStepAnimation(var Message: TMessage);
  5994. begin
  5995. TBStepAnimation(Message);
  5996. end;
  5997. procedure TTBPopupWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  5998. begin
  5999. { May be necessary in some cases... }
  6000. TBEndAnimation(WindowHandle);
  6001. inherited;
  6002. end;
  6003. procedure TTBPopupWindow.WMPaint(var Message: TWMPaint);
  6004. begin
  6005. { Must abort animation when a WM_PAINT message is received }
  6006. TBEndAnimation(WindowHandle);
  6007. inherited;
  6008. end;
  6009. procedure TTBPopupWindow.Paint;
  6010. begin
  6011. FView.DrawSubitems(Canvas);
  6012. PaintScrollArrows;
  6013. end;
  6014. procedure TTBPopupWindow.PaintScrollArrows;
  6015. procedure DrawArrow(const R: TRect; ADown: Boolean);
  6016. var
  6017. X, Y: Integer;
  6018. P: array[0..2] of TPoint;
  6019. begin
  6020. X := (R.Left + R.Right) div 2;
  6021. Y := (R.Top + R.Bottom) div 2;
  6022. Dec(Y);
  6023. P[0].X := X-3;
  6024. P[0].Y := Y;
  6025. P[1].X := X+3;
  6026. P[1].Y := Y;
  6027. P[2].X := X;
  6028. P[2].Y := Y;
  6029. if ADown then
  6030. Inc(P[2].Y, 3)
  6031. else begin
  6032. Inc(P[0].Y, 3);
  6033. Inc(P[1].Y, 3);
  6034. end;
  6035. Canvas.Pen.Color := tbMenuTextColor;
  6036. Canvas.Brush.Color := tbMenuTextColor;
  6037. Canvas.Polygon(P);
  6038. end;
  6039. begin
  6040. if FView.FShowUpArrow then
  6041. DrawArrow(Rect(0, 0, ClientWidth, tbMenuScrollArrowHeight), False);
  6042. if FView.FShowDownArrow then
  6043. DrawArrow(Bounds(0, ClientHeight - tbMenuScrollArrowHeight,
  6044. ClientWidth, tbMenuScrollArrowHeight), True);
  6045. end;
  6046. procedure TTBPopupWindow.WMClose(var Message: TWMClose);
  6047. begin
  6048. { do nothing -- ignore Alt+F4 keypresses }
  6049. end;
  6050. procedure TTBPopupWindow.WMNCCalcSize(var Message: TWMNCCalcSize);
  6051. begin
  6052. with GetNCSize do
  6053. InflateRect(Message.CalcSize_Params^.rgrc[0], -X, -Y);
  6054. inherited;
  6055. end;
  6056. procedure PopupWindowNCPaintProc(Wnd: HWND; DC: HDC; AppData: Longint);
  6057. var
  6058. R: TRect;
  6059. {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
  6060. Brush: HBRUSH;
  6061. {$ENDIF}
  6062. begin
  6063. GetWindowRect(Wnd, R); OffsetRect(R, -R.Left, -R.Top);
  6064. {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
  6065. if not AreFlatMenusEnabled then begin
  6066. {$ENDIF}
  6067. DrawEdge(DC, R, EDGE_RAISED, BF_RECT or BF_ADJUST);
  6068. FrameRect(DC, R, GetSysColorBrush(COLOR_BTNFACE));
  6069. {$IFNDEF TB2K_USE_STRICT_O2K_MENU_STYLE}
  6070. end
  6071. else begin
  6072. FrameRect(DC, R, GetSysColorBrush(COLOR_BTNSHADOW));
  6073. Brush := CreateSolidBrush(ColorToRGB(TTBPopupWindow(AppData).Color));
  6074. InflateRect(R, -1, -1);
  6075. FrameRect(DC, R, Brush);
  6076. InflateRect(R, -1, -1);
  6077. FrameRect(DC, R, Brush);
  6078. DeleteObject(Brush);
  6079. end;
  6080. {$ENDIF}
  6081. end;
  6082. procedure TTBPopupWindow.WMNCPaint(var Message: TMessage);
  6083. var
  6084. DC: HDC;
  6085. begin
  6086. DC := GetWindowDC(Handle);
  6087. try
  6088. SelectNCUpdateRgn(Handle, DC, HRGN(Message.WParam));
  6089. PopupWindowNCPaintProc(Handle, DC, Longint(Self));
  6090. finally
  6091. ReleaseDC(Handle, DC);
  6092. end;
  6093. end;
  6094. procedure TTBPopupWindow.WMPrint(var Message: TMessage);
  6095. begin
  6096. HandleWMPrint(Handle, Message, PopupWindowNCPaintProc, Longint(Self));
  6097. end;
  6098. procedure TTBPopupWindow.WMPrintClient(var Message: TMessage);
  6099. begin
  6100. HandleWMPrintClient(Self, Message);
  6101. end;
  6102. procedure TTBPopupWindow.CMHintShow(var Message: TCMHintShow);
  6103. begin
  6104. with Message.HintInfo^ do begin
  6105. HintStr := '';
  6106. if Assigned(FView.Selected) then begin
  6107. CursorRect := FView.Selected.BoundsRect;
  6108. HintStr := FView.FSelected.GetHintText;
  6109. end;
  6110. end;
  6111. end;
  6112. { TTBItemContainer }
  6113. constructor TTBItemContainer.Create(AOwner: TComponent);
  6114. begin
  6115. inherited;
  6116. FItem := TTBRootItem.Create(Self);
  6117. FItem.ParentComponent := Self;
  6118. end;
  6119. destructor TTBItemContainer.Destroy;
  6120. begin
  6121. FItem.Free;
  6122. inherited;
  6123. end;
  6124. function TTBItemContainer.GetItems: TTBCustomItem;
  6125. begin
  6126. Result := FItem;
  6127. end;
  6128. procedure TTBItemContainer.GetChildren(Proc: TGetChildProc; Root: TComponent);
  6129. begin
  6130. FItem.GetChildren(Proc, Root);
  6131. end;
  6132. function TTBItemContainer.GetImages: TCustomImageList;
  6133. begin
  6134. Result := FItem.SubMenuImages;
  6135. end;
  6136. procedure TTBItemContainer.SetImages(Value: TCustomImageList);
  6137. begin
  6138. FItem.SubMenuImages := Value;
  6139. end;
  6140. { TTBPopupMenu }
  6141. constructor TTBPopupMenu.Create(AOwner: TComponent);
  6142. begin
  6143. inherited;
  6144. FItem := GetRootItemClass.Create(Self);
  6145. FItem.ParentComponent := Self;
  6146. FItem.OnClick := RootItemClick;
  6147. end;
  6148. destructor TTBPopupMenu.Destroy;
  6149. begin
  6150. FItem.Free;
  6151. inherited;
  6152. end;
  6153. function TTBPopupMenu.GetItems: TTBCustomItem;
  6154. begin
  6155. Result := FItem;
  6156. end;
  6157. procedure TTBPopupMenu.GetChildren(Proc: TGetChildProc; Root: TComponent);
  6158. begin
  6159. FItem.GetChildren(Proc, Root);
  6160. end;
  6161. procedure TTBPopupMenu.SetChildOrder(Child: TComponent; Order: Integer);
  6162. begin
  6163. FItem.SetChildOrder(Child, Order);
  6164. end;
  6165. function TTBPopupMenu.GetRootItemClass: TTBRootItemClass;
  6166. begin
  6167. Result := TTBRootItem;
  6168. end;
  6169. function TTBPopupMenu.GetImages: TCustomImageList;
  6170. begin
  6171. Result := FItem.SubMenuImages;
  6172. end;
  6173. function TTBPopupMenu.GetLinkSubitems: TTBCustomItem;
  6174. begin
  6175. Result := FItem.LinkSubitems;
  6176. end;
  6177. function TTBPopupMenu.GetOptions: TTBItemOptions;
  6178. begin
  6179. Result := FItem.Options;
  6180. end;
  6181. procedure TTBPopupMenu.SetImages(Value: TCustomImageList);
  6182. begin
  6183. FItem.SubMenuImages := Value;
  6184. end;
  6185. procedure TTBPopupMenu.SetLinkSubitems(Value: TTBCustomItem);
  6186. begin
  6187. FItem.LinkSubitems := Value;
  6188. end;
  6189. procedure TTBPopupMenu.SetOptions(Value: TTBItemOptions);
  6190. begin
  6191. FItem.Options := Value;
  6192. end;
  6193. procedure TTBPopupMenu.RootItemClick(Sender: TObject);
  6194. begin
  6195. if Sender = FItem then
  6196. Sender := Self;
  6197. DoPopup(Sender);
  6198. end;
  6199. {$IFNDEF JR_D5}
  6200. procedure TTBPopupMenu.DoPopup(Sender: TObject);
  6201. begin
  6202. if Assigned(OnPopup) then OnPopup(Sender);
  6203. end;
  6204. {$ENDIF}
  6205. procedure TTBPopupMenu.Popup(X, Y: Integer);
  6206. begin
  6207. PopupEx(X, Y, False);
  6208. end;
  6209. function TTBPopupMenu.PopupEx(X, Y: Integer;
  6210. ReturnClickedItemOnly: Boolean = False): TTBCustomItem;
  6211. begin
  6212. {$IFDEF JR_D5}
  6213. {$IFDEF JR_D9}
  6214. SetPopupPoint(Point(X, Y));
  6215. {$ELSE}
  6216. PPoint(@PopupPoint)^ := Point(X, Y);
  6217. {$ENDIF}
  6218. {$ENDIF}
  6219. Result := FItem.Popup(X, Y, TrackButton = tbRightButton,
  6220. TTBPopupAlignment(Alignment), ReturnClickedItemOnly);
  6221. end;
  6222. function TTBPopupMenu.IsShortCut(var Message: TWMKey): Boolean;
  6223. begin
  6224. Result := FItem.IsShortCut(Message);
  6225. end;
  6226. { TTBImageList }
  6227. constructor TTBCustomImageList.Create(AOwner: TComponent);
  6228. begin
  6229. inherited;
  6230. FCheckedImagesChangeLink := TChangeLink.Create;
  6231. FCheckedImagesChangeLink.OnChange := ImageListChanged;
  6232. FDisabledImagesChangeLink := TChangeLink.Create;
  6233. FDisabledImagesChangeLink.OnChange := ImageListChanged;
  6234. FHotImagesChangeLink := TChangeLink.Create;
  6235. FHotImagesChangeLink.OnChange := ImageListChanged;
  6236. FImagesBitmap := TBitmap.Create;
  6237. FImagesBitmap.OnChange := ImagesBitmapChanged;
  6238. FImagesBitmapMaskColor := clFuchsia;
  6239. end;
  6240. destructor TTBCustomImageList.Destroy;
  6241. begin
  6242. FreeAndNil(FImagesBitmap);
  6243. FreeAndNil(FHotImagesChangeLink);
  6244. FreeAndNil(FDisabledImagesChangeLink);
  6245. FreeAndNil(FCheckedImagesChangeLink);
  6246. inherited;
  6247. end;
  6248. procedure TTBCustomImageList.ImagesBitmapChanged(Sender: TObject);
  6249. begin
  6250. if not ImagesBitmap.Empty then begin
  6251. Clear;
  6252. AddMasked(ImagesBitmap, FImagesBitmapMaskColor);
  6253. end;
  6254. end;
  6255. procedure TTBCustomImageList.ImageListChanged(Sender: TObject);
  6256. begin
  6257. Change;
  6258. end;
  6259. procedure TTBCustomImageList.DefineProperties(Filer: TFiler);
  6260. type
  6261. TProc = procedure(ASelf: TObject; Filer: TFiler);
  6262. begin
  6263. if (Filer is TReader) or FImagesBitmap.Empty then
  6264. inherited
  6265. else
  6266. { Bypass TCustomImageList.DefineProperties when we've got an ImageBitmap }
  6267. TProc(@TComponentAccess.DefineProperties)(Self, Filer);
  6268. end;
  6269. procedure TTBCustomImageList.DrawState(Canvas: TCanvas; X, Y, Index: Integer;
  6270. Enabled, Selected, Checked: Boolean);
  6271. begin
  6272. if not Enabled and Assigned(DisabledImages) then
  6273. DisabledImages.Draw(Canvas, X, Y, Index)
  6274. else if Checked and Assigned(CheckedImages) then
  6275. CheckedImages.Draw(Canvas, X, Y, Index, Enabled)
  6276. else if Selected and Assigned(HotImages) then
  6277. HotImages.Draw(Canvas, X, Y, Index, Enabled)
  6278. else
  6279. Draw(Canvas, X, Y, Index, Enabled);
  6280. end;
  6281. procedure TTBCustomImageList.Notification(AComponent: TComponent; Operation: TOperation);
  6282. begin
  6283. inherited;
  6284. if Operation = opRemove then begin
  6285. if AComponent = CheckedImages then CheckedImages := nil;
  6286. if AComponent = DisabledImages then DisabledImages := nil;
  6287. if AComponent = HotImages then HotImages := nil;
  6288. end;
  6289. end;
  6290. procedure TTBCustomImageList.ChangeImages(var AImageList: TCustomImageList;
  6291. Value: TCustomImageList; AChangeLink: TChangeLink);
  6292. begin
  6293. if Value = Self then
  6294. Value := nil;
  6295. if AImageList <> Value then begin
  6296. if Assigned(AImageList) then
  6297. AImageList.UnregisterChanges(AChangeLink);
  6298. AImageList := Value;
  6299. if Assigned(Value) then begin
  6300. Value.RegisterChanges(AChangeLink);
  6301. Value.FreeNotification(Self);
  6302. end;
  6303. { Don't call Change while loading because it causes the Delphi IDE to
  6304. think the form has been modified (?). Also, don't call Change while
  6305. destroying since there's no reason to. }
  6306. if not(csLoading in ComponentState) and
  6307. not(csDestroying in ComponentState) then
  6308. Change;
  6309. end;
  6310. end;
  6311. procedure TTBCustomImageList.SetCheckedImages(Value: TCustomImageList);
  6312. begin
  6313. ChangeImages(FCheckedImages, Value, FCheckedImagesChangeLink);
  6314. end;
  6315. procedure TTBCustomImageList.SetDisabledImages(Value: TCustomImageList);
  6316. begin
  6317. ChangeImages(FDisabledImages, Value, FDisabledImagesChangeLink);
  6318. end;
  6319. procedure TTBCustomImageList.SetHotImages(Value: TCustomImageList);
  6320. begin
  6321. ChangeImages(FHotImages, Value, FHotImagesChangeLink);
  6322. end;
  6323. procedure TTBCustomImageList.SetImagesBitmap(Value: TBitmap);
  6324. begin
  6325. FImagesBitmap.Assign(Value);
  6326. end;
  6327. procedure TTBCustomImageList.SetImagesBitmapMaskColor(Value: TColor);
  6328. begin
  6329. if FImagesBitmapMaskColor <> Value then begin
  6330. FImagesBitmapMaskColor := Value;
  6331. ImagesBitmapChanged(nil);
  6332. end;
  6333. end;
  6334. { TTBBaseAccObject }
  6335. { According to the MSAA docs:
  6336. "With Active Accessibility 2.0, servers can return E_NOTIMPL from IDispatch
  6337. methods and Active Accessibility will implement the IAccessible interface
  6338. for them."
  6339. And there was much rejoicing. }
  6340. function TTBBaseAccObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  6341. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  6342. begin
  6343. Result := E_NOTIMPL;
  6344. end;
  6345. function TTBBaseAccObject.GetTypeInfo(Index, LocaleID: Integer;
  6346. out TypeInfo): HResult;
  6347. begin
  6348. Result := E_NOTIMPL;
  6349. end;
  6350. function TTBBaseAccObject.GetTypeInfoCount(out Count: Integer): HResult;
  6351. begin
  6352. Result := E_NOTIMPL;
  6353. end;
  6354. function TTBBaseAccObject.Invoke(DispID: Integer; const IID: TGUID;
  6355. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  6356. ArgErr: Pointer): HResult;
  6357. begin
  6358. Result := E_NOTIMPL;
  6359. end;
  6360. { Initialization & finalization }
  6361. procedure TBInitToolbarSystemFont;
  6362. var
  6363. NonClientMetrics: TNonClientMetrics;
  6364. begin
  6365. NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
  6366. if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
  6367. ToolbarFont.Handle := CreateFontIndirect(NonClientMetrics.lfMenuFont);
  6368. end;
  6369. initialization
  6370. ToolbarFont := TFont.Create;
  6371. TBInitToolbarSystemFont;
  6372. finalization
  6373. DestroyClickWnd;
  6374. FreeAndNil(ToolbarFont);
  6375. end.