TB2Item.pas 224 KB

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