TB2Item.pas 225 KB

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