TB2Dock.pas 186 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593
  1. unit TB2Dock;
  2. {
  3. Toolbar2000
  4. Copyright (C) 1998-2005 by Jordan Russell
  5. All rights reserved.
  6. The contents of this file are subject to the "Toolbar2000 License"; you may
  7. not use or distribute this file except in compliance with the
  8. "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
  9. TB2k-LICENSE.txt or at:
  10. http://www.jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
  11. Alternatively, the contents of this file may be used under the terms of the
  12. GNU General Public License (the "GPL"), in which case the provisions of the
  13. GPL are applicable instead of those in the "Toolbar2000 License". A copy of
  14. the GPL may be found in GPL-LICENSE.txt or at:
  15. http://www.jrsoftware.org/files/tb2k/GPL-LICENSE.txt
  16. If you wish to allow use of your version of this file only under the terms of
  17. the GPL and not to allow others to use your version of this file under the
  18. "Toolbar2000 License", indicate your decision by deleting the provisions
  19. above and replace them with the notice and other provisions required by the
  20. GPL. If you do not delete the provisions above, a recipient may use your
  21. version of this file under either the "Toolbar2000 License" or the GPL.
  22. $jrsoftware: tb2k/Source/TB2Dock.pas,v 1.99 2005/07/15 19:35:03 jr Exp $
  23. }
  24. interface
  25. {x$DEFINE TB2Dock_DisableLock}
  26. { Remove the 'x' to enable the define. It will disable calls to
  27. LockWindowUpdate, which it calls to disable screen updates while dragging.
  28. You may want to temporarily enable the define while debugging so you are able
  29. to see your code window while stepping through the dragging routines. }
  30. {$I TB2Ver.inc}
  31. uses
  32. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
  33. type
  34. TTBCustomForm = {$IFDEF JR_D3} TCustomForm {$ELSE} TForm {$ENDIF};
  35. { TTBDock }
  36. TTBDockBoundLinesValues = (blTop, blBottom, blLeft, blRight);
  37. TTBDockBoundLines = set of TTBDockBoundLinesValues;
  38. TTBDockPosition = (dpTop, dpBottom, dpLeft, dpRight);
  39. TTBDockType = (dtNotDocked, dtFloating, dtTopBottom, dtLeftRight);
  40. TTBDockableTo = set of TTBDockPosition;
  41. TTBCustomDockableWindow = class;
  42. {$IFNDEF MPEXCLUDE}
  43. TTBBasicBackground = class;
  44. {$ENDIF}
  45. TTBInsertRemoveEvent = procedure(Sender: TObject; Inserting: Boolean;
  46. Bar: TTBCustomDockableWindow) of object;
  47. TTBRequestDockEvent = procedure(Sender: TObject; Bar: TTBCustomDockableWindow;
  48. var Accept: Boolean) of object;
  49. TTBDock = class(TCustomControl)
  50. private
  51. { Property values }
  52. FPosition: TTBDockPosition;
  53. FAllowDrag: Boolean;
  54. FBoundLines: TTBDockBoundLines;
  55. {$IFNDEF MPEXCLUDE}
  56. FBackground: TTBBasicBackground;
  57. {$ENDIF}
  58. FBkgOnToolbars: Boolean;
  59. FFixAlign: Boolean;
  60. FCommitNewPositions: Boolean;
  61. FLimitToOneRow: Boolean;
  62. FOnInsertRemoveBar: TTBInsertRemoveEvent;
  63. FOnRequestDock: TTBRequestDockEvent;
  64. {$IFNDEF JR_D4}
  65. FOnResize: TNotifyEvent;
  66. {$ENDIF}
  67. { Internal }
  68. FDisableArrangeToolbars: Integer; { Increment to disable ArrangeToolbars }
  69. FArrangeToolbarsNeeded: Boolean;
  70. FNonClientWidth, FNonClientHeight: Integer;
  71. { Property access methods }
  72. //function GetVersion: TToolbar97Version;
  73. procedure SetAllowDrag(Value: Boolean);
  74. {$IFNDEF MPEXCLUDE}
  75. procedure SetBackground(Value: TTBBasicBackground);
  76. procedure SetBackgroundOnToolbars(Value: Boolean);
  77. {$ENDIF}
  78. procedure SetBoundLines(Value: TTBDockBoundLines);
  79. procedure SetFixAlign(Value: Boolean);
  80. procedure SetPosition(Value: TTBDockPosition);
  81. //procedure SetVersion(const Value: TToolbar97Version);
  82. function GetToolbarCount: Integer;
  83. function GetToolbars(Index: Integer): TTBCustomDockableWindow;
  84. { Internal }
  85. {$IFNDEF MPEXCLUDE}
  86. procedure BackgroundChanged(Sender: TObject);
  87. {$ENDIF}
  88. procedure ChangeDockList(const Insert: Boolean; const Bar: TTBCustomDockableWindow);
  89. procedure CommitPositions;
  90. procedure DrawNCArea(const DrawToDC: Boolean; const ADC: HDC;
  91. const Clip: HRGN);
  92. function GetDesignModeRowOf(const XY: Integer): Integer;
  93. procedure RelayMsgToFloatingBars(var Message: TMessage);
  94. procedure ToolbarVisibilityChanged(const Bar: TTBCustomDockableWindow;
  95. const ForceRemove: Boolean);
  96. { Messages }
  97. procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  98. procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
  99. {$IFNDEF MPEXCLUDE}
  100. procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
  101. {$ENDIF}
  102. procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  103. procedure WMMove(var Message: TWMMove); message WM_MOVE;
  104. {$IFNDEF JR_D4}
  105. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  106. {$ENDIF}
  107. procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  108. procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  109. procedure WMPrint(var Message: TMessage); message WM_PRINT;
  110. procedure WMPrintClient(var Message: TMessage); message WM_PRINTCLIENT;
  111. procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
  112. protected
  113. DockList: TList; { List of the toolbars docked, and those floating and have LastDock
  114. pointing to the dock. Items are casted in TTBCustomDockableWindow's. }
  115. DockVisibleList: TList; { Similar to DockList, but lists only docked and visible toolbars }
  116. function Accepts(ADockableWindow: TTBCustomDockableWindow): Boolean; virtual;
  117. procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  118. procedure ChangeWidthHeight(const NewWidth, NewHeight: Integer);
  119. procedure DrawBackground(DC: HDC; const DrawRect: TRect); virtual;
  120. {$IFNDEF MPEXCLUDE}
  121. function GetPalette: HPALETTE; override;
  122. {$ENDIF}
  123. function HasVisibleToolbars: Boolean;
  124. procedure InvalidateBackgrounds;
  125. procedure Loaded; override;
  126. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  127. procedure SetParent(AParent: TWinControl); override;
  128. function ToolbarVisibleOnDock(const AToolbar: TTBCustomDockableWindow): Boolean;
  129. procedure Paint; override;
  130. function UsingBackground: Boolean; virtual;
  131. property ArrangeToolbarsNeeded: Boolean read FArrangeToolbarsNeeded write FArrangeToolbarsNeeded;
  132. property DisableArrangeToolbars: Integer read FDisableArrangeToolbars write FDisableArrangeToolbars;
  133. public
  134. constructor Create(AOwner: TComponent); override;
  135. procedure CreateParams(var Params: TCreateParams); override;
  136. destructor Destroy; override;
  137. procedure ArrangeToolbars; virtual;
  138. procedure BeginUpdate;
  139. procedure EndUpdate;
  140. function GetCurrentRowSize(const Row: Integer; var AFullSize: Boolean): Integer;
  141. function GetHighestRow(const HighestEffective: Boolean): Integer;
  142. function GetMinRowSize(const Row: Integer;
  143. const ExcludeControl: TTBCustomDockableWindow): Integer;
  144. property CommitNewPositions: Boolean read FCommitNewPositions write FCommitNewPositions;
  145. property NonClientWidth: Integer read FNonClientWidth;
  146. property NonClientHeight: Integer read FNonClientHeight;
  147. property ToolbarCount: Integer read GetToolbarCount;
  148. property Toolbars[Index: Integer]: TTBCustomDockableWindow read GetToolbars;
  149. published
  150. property AllowDrag: Boolean read FAllowDrag write SetAllowDrag default True;
  151. {$IFNDEF MPEXCLUDE}
  152. property Background: TTBBasicBackground read FBackground write SetBackground;
  153. property BackgroundOnToolbars: Boolean read FBkgOnToolbars write SetBackgroundOnToolbars default True;
  154. {$ENDIF}
  155. property BoundLines: TTBDockBoundLines read FBoundLines write SetBoundLines default [];
  156. property Color default clBtnFace;
  157. property FixAlign: Boolean read FFixAlign write SetFixAlign default False;
  158. property LimitToOneRow: Boolean read FLimitToOneRow write FLimitToOneRow default False;
  159. property PopupMenu;
  160. property Position: TTBDockPosition read FPosition write SetPosition default dpTop;
  161. //property Version: TToolbar97Version read GetVersion write SetVersion stored False;
  162. property Visible;
  163. {$IFDEF JR_D5}
  164. property OnContextPopup;
  165. {$ENDIF}
  166. property OnInsertRemoveBar: TTBInsertRemoveEvent read FOnInsertRemoveBar write FOnInsertRemoveBar;
  167. property OnMouseDown;
  168. property OnMouseMove;
  169. property OnMouseUp;
  170. property OnRequestDock: TTBRequestDockEvent read FOnRequestDock write FOnRequestDock;
  171. {$IFDEF JR_D4}
  172. property OnResize;
  173. {$ELSE}
  174. property OnResize: TNotifyEvent read FOnResize write FOnResize;
  175. {$ENDIF}
  176. end;
  177. { TTBFloatingWindowParent - internal }
  178. TTBToolWindowNCRedrawWhatElement = (twrdBorder, twrdCaption, twrdCloseButton);
  179. TTBToolWindowNCRedrawWhat = set of TTBToolWindowNCRedrawWhatElement;
  180. TTBFloatingWindowParentClass = class of TTBFloatingWindowParent;
  181. TTBFloatingWindowParent = class(TCustomForm)
  182. private
  183. FCloseButtonDown: Boolean; { True if Close button is currently depressed }
  184. FDockableWindow: TTBCustomDockableWindow;
  185. FParentForm: TTBCustomForm;
  186. FShouldShow: Boolean;
  187. procedure SetCloseButtonState(Pushed: Boolean);
  188. procedure RedrawNCArea(const RedrawWhat: TTBToolWindowNCRedrawWhat);
  189. procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  190. procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
  191. procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  192. procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
  193. procedure WMClose(var Message: TWMClose); message WM_CLOSE;
  194. procedure WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
  195. procedure WMMouseActivate(var Message: TWMMouseActivate); message WM_MOUSEACTIVATE;
  196. procedure WMMove(var Message: TWMMove); message WM_MOVE;
  197. procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  198. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  199. procedure WMNCLButtonDblClk(var Message: TWMNCLButtonDblClk); message WM_NCLBUTTONDBLCLK;
  200. procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
  201. procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  202. procedure WMNCRButtonUp(var Message: TWMNCRButtonUp); message WM_NCRBUTTONUP;
  203. procedure WMPrint(var Message: TMessage); message WM_PRINT;
  204. procedure WMPrintClient(var Message: TMessage); message WM_PRINTCLIENT;
  205. protected
  206. procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  207. procedure CreateParams(var Params: TCreateParams); override;
  208. procedure DrawNCArea(const DrawToDC: Boolean; const ADC: HDC;
  209. const Clip: HRGN; RedrawWhat: TTBToolWindowNCRedrawWhat); dynamic;
  210. property DockableWindow: TTBCustomDockableWindow read FDockableWindow;
  211. property CloseButtonDown: Boolean read FCloseButtonDown;
  212. public
  213. property ParentForm: TTBCustomForm read FParentForm;
  214. constructor Create(AOwner: TComponent); override;
  215. destructor Destroy; override;
  216. end;
  217. { TTBCustomDockableWindow }
  218. TTBDockChangingEvent = procedure(Sender: TObject; Floating: Boolean;
  219. DockingTo: TTBDock) of object;
  220. TTBDragHandleStyle = (dhDouble, dhNone, dhSingle);
  221. TTBDockMode = (dmCanFloat, dmCannotFloat, dmCannotFloatOrChangeDocks);
  222. TTBFloatingMode = (fmOnTopOfParentForm, fmOnTopOfAllForms);
  223. TTBSizeHandle = (twshLeft, twshRight, twshTop, twshTopLeft,
  224. twshTopRight, twshBottom, twshBottomLeft, twshBottomRight);
  225. { ^ must be in same order as HTLEFT..HTBOTTOMRIGHT }
  226. TTBPositionReadIntProc = function(const ToolbarName, Value: String; const Default: Longint;
  227. const ExtraData: Pointer): Longint;
  228. TTBPositionReadStringProc = function(const ToolbarName, Value, Default: String;
  229. const ExtraData: Pointer): String;
  230. TTBPositionWriteIntProc = procedure(const ToolbarName, Value: String; const Data: Longint;
  231. const ExtraData: Pointer);
  232. TTBPositionWriteStringProc = procedure(const ToolbarName, Value, Data: String;
  233. const ExtraData: Pointer);
  234. TTBReadPositionData = record
  235. ReadIntProc: TTBPositionReadIntProc;
  236. ReadStringProc: TTBPositionReadStringProc;
  237. ExtraData: Pointer;
  238. end;
  239. TTBWritePositionData = record
  240. WriteIntProc: TTBPositionWriteIntProc;
  241. WriteStringProc: TTBPositionWriteStringProc;
  242. ExtraData: Pointer;
  243. end;
  244. TTBDockableWindowStyles = set of (tbdsResizeEightCorner, tbdsResizeClipCursor);
  245. TTBShrinkMode = (tbsmNone, tbsmWrap, tbsmChevron);
  246. TTBCustomDockableWindow = class(TCustomControl)
  247. private
  248. { Property variables }
  249. FAutoResize: Boolean;
  250. FDblClickUndock: Boolean;
  251. FDockPos, FDockRow, FEffectiveDockPos, FEffectiveDockRow: Integer;
  252. FDocked: Boolean;
  253. FCurrentDock, FDefaultDock, FLastDock: TTBDock;
  254. FCurrentSize: Integer;
  255. FFloating: Boolean;
  256. FOnClose, FOnDockChanged, FOnMove, FOnRecreated,
  257. FOnRecreating, {$IFNDEF JR_D4} FOnResize, {$ENDIF}
  258. FOnVisibleChanged: TNotifyEvent;
  259. FOnCloseQuery: TCloseQueryEvent;
  260. FOnDockChanging, FOnDockChangingHidden: TTBDockChangingEvent;
  261. FActivateParent, FHideWhenInactive, FCloseButton, FCloseButtonWhenDocked,
  262. FFullSize, FResizable, FShowCaption, FStretch, FUseLastDock: Boolean;
  263. FBorderStyle: TBorderStyle;
  264. FDockMode: TTBDockMode;
  265. FDragHandleStyle: TTBDragHandleStyle;
  266. FDockableTo: TTBDockableTo;
  267. FFloatingMode: TTBFloatingMode;
  268. FSmoothDrag: Boolean;
  269. FDockableWindowStyles: TTBDockableWindowStyles;
  270. FLastRowSize: Integer;
  271. FInsertRowBefore: Boolean;
  272. { Misc. }
  273. FUpdatingBounds, { Incremented while internally changing the bounds. This allows
  274. it to move the toolbar freely in design mode and prevents the
  275. SizeChanging protected method from begin called }
  276. FDisableArrange, { Incremented to disable Arrange }
  277. FDisableOnMove, { Incremented to prevent WM_MOVE handler from calling the OnMoved handler }
  278. FHidden: Integer; { Incremented while the toolbar is temporarily hidden }
  279. FArrangeNeeded, FMoved: Boolean;
  280. FInactiveCaption: Boolean; { True when the caption of the toolbar is currently the inactive color }
  281. FFloatingPosition: TPoint;
  282. FDockForms: TList;
  283. FSavedAtRunTime: Boolean;
  284. //FNonClientWidth, FNonClientHeight: Integer;
  285. FDragMode, FDragSplitting, FDragCanSplit: Boolean;
  286. FSmoothDragging: Boolean;
  287. { When floating. These are not used in design mode }
  288. FCloseButtonDown: Boolean; { True if Close button is currently depressed }
  289. FCloseButtonHover: Boolean;
  290. FFloatParent: TTBFloatingWindowParent; { Run-time only: The actual Parent of the toolbar when it is floating }
  291. { Property access methods }
  292. //function GetVersion: TToolbar97Version;
  293. function GetNonClientWidth: Integer;
  294. function GetNonClientHeight: Integer;
  295. function IsLastDockStored: Boolean;
  296. function IsWidthAndHeightStored: Boolean;
  297. procedure SetAutoResize(Value: Boolean);
  298. procedure SetBorderStyle(Value: TBorderStyle);
  299. procedure SetCloseButton(Value: Boolean);
  300. procedure SetCloseButtonWhenDocked(Value: Boolean);
  301. procedure SetCurrentDock(Value: TTBDock);
  302. procedure SetDefaultDock(Value: TTBDock);
  303. procedure SetDockPos(Value: Integer);
  304. procedure SetDockRow(Value: Integer);
  305. procedure SetDragHandleStyle(Value: TTBDragHandleStyle);
  306. procedure SetFloating(Value: Boolean);
  307. procedure SetFloatingMode(Value: TTBFloatingMode);
  308. procedure SetFloatingPosition(Value: TPoint);
  309. procedure SetFullSize(Value: Boolean);
  310. procedure SetLastDock(Value: TTBDock);
  311. procedure SetResizable(Value: Boolean);
  312. procedure SetShowCaption(Value: Boolean);
  313. procedure SetStretch(Value: Boolean);
  314. procedure SetUseLastDock(Value: Boolean);
  315. //procedure SetVersion(const Value: TToolbar97Version);
  316. { Internal }
  317. procedure CancelNCHover;
  318. procedure DrawDraggingOutline(const DC: HDC; const NewRect, OldRect: PRect;
  319. const NewDocking, OldDocking: Boolean);
  320. procedure RedrawNCArea;
  321. procedure SetCloseButtonState(Pushed: Boolean);
  322. procedure ShowNCContextMenu(const Pos: TSmallPoint);
  323. procedure Moved;
  324. function GetShowingState: Boolean;
  325. procedure UpdateCaptionState;
  326. procedure UpdateTopmostFlag;
  327. procedure UpdateVisibility;
  328. procedure ReadSavedAtRunTime(Reader: TReader);
  329. procedure WriteSavedAtRunTime(Writer: TWriter);
  330. { Messages }
  331. procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
  332. procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  333. procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  334. procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  335. procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
  336. {$IFDEF JR_D5}
  337. procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU;
  338. {$ENDIF}
  339. procedure WMEnable(var Message: TWMEnable); message WM_ENABLE;
  340. procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  341. procedure WMMove(var Message: TWMMove); message WM_MOVE;
  342. procedure WMMouseMove(var Message: TMessage); message WM_MOUSEMOVE;
  343. procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  344. procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  345. procedure WMNCMouseLeave(var Message: TMessage); message $2A2 {WM_NCMOUSELEAVE};
  346. procedure WMNCMouseMove(var Message: TWMNCMouseMove); message WM_NCMOUSEMOVE;
  347. procedure WMNCLButtonDblClk(var Message: TWMNCLButtonDblClk); message WM_NCLBUTTONDBLCLK;
  348. procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
  349. procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  350. procedure WMNCRButtonUp(var Message: TWMNCRButtonUp); message WM_NCRBUTTONUP;
  351. procedure WMPrint(var Message: TMessage); message WM_PRINT;
  352. procedure WMPrintClient(var Message: TMessage); message WM_PRINTCLIENT;
  353. procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
  354. {$IFNDEF JR_D4}
  355. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  356. {$ENDIF}
  357. protected
  358. property ActivateParent: Boolean read FActivateParent write FActivateParent default True;
  359. property AutoResize: Boolean read FAutoResize write SetAutoResize default True;
  360. property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
  361. property Color default clBtnFace;
  362. property CloseButton: Boolean read FCloseButton write SetCloseButton default True;
  363. property CloseButtonDown: Boolean read FCloseButtonDown;
  364. property CloseButtonHover: Boolean read FCloseButtonHover;
  365. property CloseButtonWhenDocked: Boolean read FCloseButtonWhenDocked write SetCloseButtonWhenDocked default False;
  366. property DefaultDock: TTBDock read FDefaultDock write SetDefaultDock;
  367. property DockableTo: TTBDockableTo read FDockableTo write FDockableTo default [dpTop, dpBottom, dpLeft, dpRight];
  368. property DockableWindowStyles: TTBDockableWindowStyles read FDockableWindowStyles write FDockableWindowStyles;
  369. property DockMode: TTBDockMode read FDockMode write FDockMode default dmCanFloat;
  370. property DragHandleStyle: TTBDragHandleStyle read FDragHandleStyle write SetDragHandleStyle default dhSingle;
  371. property FloatingMode: TTBFloatingMode read FFloatingMode write SetFloatingMode default fmOnTopOfParentForm;
  372. property FullSize: Boolean read FFullSize write SetFullSize default False;
  373. property InactiveCaption: Boolean read FInactiveCaption;
  374. property HideWhenInactive: Boolean read FHideWhenInactive write FHideWhenInactive default True;
  375. property Resizable: Boolean read FResizable write SetResizable default True;
  376. property ShowCaption: Boolean read FShowCaption write SetShowCaption default True;
  377. property SmoothDrag: Boolean read FSmoothDrag write FSmoothDrag default True;
  378. property Stretch: Boolean read FStretch write SetStretch default False;
  379. property UseLastDock: Boolean read FUseLastDock write SetUseLastDock default True;
  380. //property Version: TToolbar97Version read GetVersion write SetVersion stored False;
  381. property OnClose: TNotifyEvent read FOnClose write FOnClose;
  382. property OnCloseQuery: TCloseQueryEvent read FOnCloseQuery write FOnCloseQuery;
  383. property OnDockChanged: TNotifyEvent read FOnDockChanged write FOnDockChanged;
  384. property OnDockChanging: TTBDockChangingEvent read FOnDockChanging write FOnDockChanging;
  385. property OnDockChangingHidden: TTBDockChangingEvent read FOnDockChangingHidden write FOnDockChangingHidden;
  386. property OnMove: TNotifyEvent read FOnMove write FOnMove;
  387. property OnRecreated: TNotifyEvent read FOnRecreated write FOnRecreated;
  388. property OnRecreating: TNotifyEvent read FOnRecreating write FOnRecreating;
  389. {$IFNDEF JR_D4}
  390. property OnResize: TNotifyEvent read FOnResize write FOnResize;
  391. {$ENDIF}
  392. property OnVisibleChanged: TNotifyEvent read FOnVisibleChanged write FOnVisibleChanged;
  393. { Overridden methods }
  394. procedure CreateParams(var Params: TCreateParams); override;
  395. procedure DefineProperties(Filer: TFiler); override;
  396. function GetPalette: HPALETTE; override;
  397. procedure Loaded; override;
  398. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  399. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  400. function PaletteChanged(Foreground: Boolean): Boolean; override;
  401. procedure SetParent(AParent: TWinControl); override;
  402. { Methods accessible to descendants }
  403. procedure Arrange;
  404. function CalcNCSizes: TPoint; virtual;
  405. function CanDockTo(ADock: TTBDock): Boolean; virtual;
  406. procedure ChangeSize(AWidth, AHeight: Integer);
  407. function ChildControlTransparent(Ctl: TControl): Boolean; dynamic;
  408. procedure Close;
  409. procedure ControlExistsAtPos(const P: TPoint; var ControlExists: Boolean); virtual;
  410. function DoArrange(CanMoveControls: Boolean; PreviousDockType: TTBDockType;
  411. NewFloating: Boolean; NewDock: TTBDock): TPoint; virtual; abstract;
  412. procedure DoDockChangingHidden(NewFloating: Boolean; DockingTo: TTBDock); dynamic;
  413. procedure DoubleClick;
  414. procedure DrawNCArea(const DrawToDC: Boolean; const ADC: HDC;
  415. const Clip: HRGN); virtual;
  416. procedure GetBaseSize(var ASize: TPoint); virtual; abstract;
  417. function GetDockedCloseButtonRect(LeftRight: Boolean): TRect; virtual;
  418. function GetFloatingWindowParentClass: TTBFloatingWindowParentClass; dynamic;
  419. procedure GetMinShrinkSize(var AMinimumSize: Integer); virtual;
  420. procedure GetMinMaxSize(var AMinClientWidth, AMinClientHeight,
  421. AMaxClientWidth, AMaxClientHeight: Integer); virtual;
  422. function GetShrinkMode: TTBShrinkMode; virtual;
  423. procedure InitializeOrdering; dynamic;
  424. function IsAutoResized: Boolean;
  425. procedure ResizeBegin(SizeHandle: TTBSizeHandle); dynamic;
  426. procedure ResizeEnd; dynamic;
  427. procedure ResizeTrack(var Rect: TRect; const OrigRect: TRect); dynamic;
  428. procedure ResizeTrackAccept; dynamic;
  429. procedure SizeChanging(const AWidth, AHeight: Integer); virtual;
  430. property EffectiveDockPosAccess: Integer read FEffectiveDockPos write FEffectiveDockPos;
  431. property EffectiveDockRowAccess: Integer read FEffectiveDockRow write FEffectiveDockRow;
  432. public
  433. property DblClickUndock: Boolean read FDblClickUndock write FDblClickUndock default True;
  434. property Docked: Boolean read FDocked;
  435. property Canvas;
  436. property CurrentDock: TTBDock read FCurrentDock write SetCurrentDock stored False;
  437. property CurrentSize: Integer read FCurrentSize write FCurrentSize;
  438. property DockPos: Integer read FDockPos write SetDockPos default -1;
  439. property DockRow: Integer read FDockRow write SetDockRow default 0;
  440. property DragMode: Boolean read FDragMode;
  441. property DragSplitting: Boolean read FDragSplitting;
  442. property EffectiveDockPos: Integer read FEffectiveDockPos;
  443. property EffectiveDockRow: Integer read FEffectiveDockRow;
  444. property Floating: Boolean read FFloating write SetFloating default False;
  445. property FloatingPosition: TPoint read FFloatingPosition write SetFloatingPosition;
  446. property LastDock: TTBDock read FLastDock write SetLastDock stored IsLastDockStored;
  447. property NonClientWidth: Integer read GetNonClientWidth;
  448. property NonClientHeight: Integer read GetNonClientHeight;
  449. constructor Create(AOwner: TComponent); override;
  450. destructor Destroy; override;
  451. function GetParentComponent: TComponent; override;
  452. function HasParent: Boolean; override;
  453. procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  454. procedure AddDockForm(const Form: TTBCustomForm);
  455. procedure AddDockedNCAreaToSize(var S: TPoint; const LeftRight: Boolean);
  456. procedure AddFloatingNCAreaToSize(var S: TPoint);
  457. procedure BeginMoving(const InitX, InitY: Integer);
  458. procedure BeginSizing(const ASizeHandle: TTBSizeHandle);
  459. procedure BeginUpdate;
  460. procedure DoneReadingPositionData(const Data: TTBReadPositionData); dynamic;
  461. procedure EndUpdate;
  462. procedure GetDockedNCArea(var TopLeft, BottomRight: TPoint;
  463. const LeftRight: Boolean);
  464. function GetFloatingBorderSize: TPoint; virtual;
  465. procedure GetFloatingNCArea(var TopLeft, BottomRight: TPoint);
  466. function IsMovable: Boolean;
  467. procedure MoveOnScreen(const OnlyIfFullyOffscreen: Boolean);
  468. procedure ReadPositionData(const Data: TTBReadPositionData); dynamic;
  469. procedure RemoveDockForm(const Form: TTBCustomForm);
  470. procedure WritePositionData(const Data: TTBWritePositionData); dynamic;
  471. published
  472. property Height stored IsWidthAndHeightStored;
  473. property Width stored IsWidthAndHeightStored;
  474. end;
  475. {$IFNDEF MPEXCLUDE}
  476. TTBBasicBackground = class(TComponent)
  477. protected
  478. procedure Draw(DC: HDC; const DrawRect: TRect); virtual; abstract;
  479. function GetPalette: HPALETTE; virtual; abstract;
  480. procedure RegisterChanges(Proc: TNotifyEvent); virtual; abstract;
  481. procedure SysColorChanged; virtual; abstract;
  482. procedure UnregisterChanges(Proc: TNotifyEvent); virtual; abstract;
  483. function UsingBackground: Boolean; virtual; abstract;
  484. end;
  485. TTBBackground = class(TTBBasicBackground)
  486. private
  487. FBitmap, FBitmapCache: TBitmap;
  488. FBkColor: TColor;
  489. FNotifyList: TList;
  490. FTransparent: Boolean;
  491. procedure BitmapChanged(Sender: TObject);
  492. procedure SetBitmap(Value: TBitmap);
  493. procedure SetBkColor(Value: TColor);
  494. procedure SetTransparent(Value: Boolean);
  495. protected
  496. procedure Draw(DC: HDC; const DrawRect: TRect); override;
  497. function GetPalette: HPALETTE; override;
  498. procedure RegisterChanges(Proc: TNotifyEvent); override;
  499. procedure SysColorChanged; override;
  500. procedure UnregisterChanges(Proc: TNotifyEvent); override;
  501. function UsingBackground: Boolean; override;
  502. public
  503. constructor Create(AOwner: TComponent); override;
  504. destructor Destroy; override;
  505. published
  506. property Bitmap: TBitmap read FBitmap write SetBitmap;
  507. property BkColor: TColor read FBkColor write SetBkColor default clBtnFace;
  508. property Transparent: Boolean read FTransparent write SetTransparent default False;
  509. end;
  510. {$ENDIF}
  511. procedure TBRegLoadPositions(const OwnerComponent: TComponent;
  512. const RootKey: DWORD; const BaseRegistryKey: String);
  513. procedure TBRegSavePositions(const OwnerComponent: TComponent;
  514. const RootKey: DWORD; const BaseRegistryKey: String);
  515. procedure TBIniLoadPositions(const OwnerComponent: TComponent;
  516. const Filename, SectionNamePrefix: String);
  517. procedure TBIniSavePositions(const OwnerComponent: TComponent;
  518. const Filename, SectionNamePrefix: String);
  519. procedure TBCustomLoadPositions(const OwnerComponent: TComponent;
  520. const ReadIntProc: TTBPositionReadIntProc;
  521. const ReadStringProc: TTBPositionReadStringProc; const ExtraData: Pointer);
  522. procedure TBCustomSavePositions(const OwnerComponent: TComponent;
  523. const WriteIntProc: TTBPositionWriteIntProc;
  524. const WriteStringProc: TTBPositionWriteStringProc; const ExtraData: Pointer);
  525. function TBGetDockTypeOf(const Control: TTBDock; const Floating: Boolean): TTBDockType;
  526. function TBGetToolWindowParentForm(const ToolWindow: TTBCustomDockableWindow):
  527. TTBCustomForm;
  528. function TBValidToolWindowParentForm(const ToolWindow: TTBCustomDockableWindow):
  529. TTBCustomForm;
  530. implementation
  531. uses
  532. Registry, IniFiles, Consts, Menus,
  533. TB2Common, TB2Hook, TB2Consts, Types;
  534. type
  535. TControlAccess = class(TControl);
  536. const
  537. DockedBorderSize = 2;
  538. DockedBorderSize2 = DockedBorderSize*2;
  539. DragHandleSizes: array[Boolean, TTBDragHandleStyle] of Integer =
  540. ((9, 0, 6), (14, 14, 14));
  541. DragHandleXOffsets: array[Boolean, TTBDragHandleStyle] of Integer =
  542. ((2, 0, 1), (3, 0, 5));
  543. HT_TB2k_Border = 2000;
  544. HT_TB2k_Close = 2001;
  545. HT_TB2k_Caption = 2002;
  546. DefaultBarWidthHeight = 8;
  547. ForceDockAtTopRow = 0;
  548. ForceDockAtLeftPos = -8;
  549. PositionLeftOrRight = [dpLeft, dpRight];
  550. twrdAll = [Low(TTBToolWindowNCRedrawWhatElement)..High(TTBToolWindowNCRedrawWhatElement)];
  551. { Constants for TTBCustomDockableWindow registry values/data.
  552. Don't localize any of these names! }
  553. rvRev = 'Rev';
  554. rdCurrentRev = 2000;
  555. rvVisible = 'Visible';
  556. rvDockedTo = 'DockedTo';
  557. rdDockedToFloating = '+';
  558. rvLastDock = 'LastDock';
  559. rvDockRow = 'DockRow';
  560. rvDockPos = 'DockPos';
  561. rvFloatLeft = 'FloatLeft';
  562. rvFloatTop = 'FloatTop';
  563. threadvar
  564. FloatingToolWindows: TList;
  565. { Misc. functions }
  566. function GetSmallCaptionHeight: Integer;
  567. { Returns height of the caption of a small window }
  568. begin
  569. Result := GetSystemMetrics(SM_CYSMCAPTION);
  570. end;
  571. function GetMDIParent(const Form: TTBCustomForm): TTBCustomForm;
  572. { Returns the parent of the specified MDI child form. But, if Form isn't a
  573. MDI child, it simply returns Form. }
  574. var
  575. I, J: Integer;
  576. begin
  577. Result := Form;
  578. if Form = nil then Exit;
  579. if {$IFDEF JR_D3} (Form is TForm) and {$ENDIF}
  580. (TForm(Form).FormStyle = fsMDIChild) then
  581. for I := 0 to Screen.FormCount-1 do
  582. with Screen.Forms[I] do begin
  583. if FormStyle <> fsMDIForm then Continue;
  584. for J := 0 to MDIChildCount-1 do
  585. if MDIChildren[J] = Form then begin
  586. Result := Screen.Forms[I];
  587. Exit;
  588. end;
  589. end;
  590. end;
  591. function TBGetDockTypeOf(const Control: TTBDock; const Floating: Boolean): TTBDockType;
  592. begin
  593. if Floating then
  594. Result := dtFloating
  595. else
  596. if Control = nil then
  597. Result := dtNotDocked
  598. else begin
  599. if not(Control.Position in PositionLeftOrRight) then
  600. Result := dtTopBottom
  601. else
  602. Result := dtLeftRight;
  603. end;
  604. end;
  605. function TBGetToolWindowParentForm(const ToolWindow: TTBCustomDockableWindow): TTBCustomForm;
  606. var
  607. Ctl: TWinControl;
  608. begin
  609. Result := nil;
  610. Ctl := ToolWindow;
  611. while Assigned(Ctl.Parent) do begin
  612. if Ctl.Parent is TTBCustomForm then
  613. Result := TTBCustomForm(Ctl.Parent);
  614. Ctl := Ctl.Parent;
  615. end;
  616. { ^ for compatibility with ActiveX controls, that code is used instead of
  617. GetParentForm because it returns nil unless the form is the *topmost*
  618. parent }
  619. if Result is TTBFloatingWindowParent then
  620. Result := TTBFloatingWindowParent(Result).ParentForm;
  621. end;
  622. function TBValidToolWindowParentForm(const ToolWindow: TTBCustomDockableWindow): TTBCustomForm;
  623. begin
  624. Result := TBGetToolWindowParentForm(ToolWindow);
  625. if Result = nil then
  626. raise EInvalidOperation.{$IFDEF JR_D3}CreateFmt{$ELSE}CreateResFmt{$ENDIF}
  627. (SParentRequired, [ToolWindow.Name]);
  628. end;
  629. procedure ToolbarHookProc(Code: THookProcCode; Wnd: HWND; WParam: WPARAM; LParam: LPARAM);
  630. var
  631. I: Integer;
  632. ToolWindow: TTBCustomDockableWindow;
  633. Form: TTBCustomForm;
  634. begin
  635. case Code of
  636. hpSendActivate,
  637. hpSendActivateApp: begin
  638. if Assigned(FloatingToolWindows) then
  639. for I := 0 to FloatingToolWindows.Count-1 do
  640. with TTBCustomDockableWindow(FloatingToolWindows.List[I]) do
  641. { Hide or restore toolbars when a form or the application is
  642. deactivated or activated, and/or update their caption state
  643. (active/inactive) }
  644. UpdateVisibility;
  645. end;
  646. hpSendWindowPosChanged: begin
  647. if Assigned(FloatingToolWindows) then
  648. for I := 0 to FloatingToolWindows.Count-1 do begin
  649. ToolWindow := TTBCustomDockableWindow(FloatingToolWindows.List[I]);
  650. with ToolWindow do begin
  651. if (FFloatingMode = fmOnTopOfParentForm) and HandleAllocated then begin
  652. with PWindowPos(LParam)^ do
  653. { Call UpdateVisibility if parent form's visibility has
  654. changed, or if it has been minimized or restored }
  655. if ((flags and (SWP_SHOWWINDOW or SWP_HIDEWINDOW) <> 0) or
  656. (flags and SWP_FRAMECHANGED <> 0)) then begin
  657. Form := TBGetToolWindowParentForm(ToolWindow);
  658. if Assigned(Form) and Form.HandleAllocated and ((Wnd = Form.Handle) or IsChild(Wnd, Form.Handle)) then
  659. UpdateVisibility;
  660. end;
  661. end;
  662. end;
  663. end;
  664. end;
  665. hpPreDestroy: begin
  666. if Assigned(FloatingToolWindows) then
  667. for I := 0 to FloatingToolWindows.Count-1 do begin
  668. with TTBCustomDockableWindow(FloatingToolWindows.List[I]) do
  669. { It must remove the form window's ownership of the tool window
  670. *before* the form gets destroyed, otherwise Windows will destroy
  671. the tool window's handle. }
  672. if Assigned(Parent) and Parent.HandleAllocated and
  673. (HWND(GetWindowLong(Parent.Handle, GWL_HWNDPARENT)) = Wnd) then
  674. SetWindowLong(Parent.Handle, GWL_HWNDPARENT, Longint(Application.Handle));
  675. { ^ Restore GWL_HWNDPARENT back to Application.Handle }
  676. end;
  677. end;
  678. end;
  679. end;
  680. type
  681. PFindWindowData = ^TFindWindowData;
  682. TFindWindowData = record
  683. TaskActiveWindow, TaskFirstWindow, TaskFirstTopMost: HWND;
  684. end;
  685. function DoFindWindow(Wnd: HWND; Param: Longint): Bool; stdcall;
  686. begin
  687. with PFindWindowData(Param)^ do
  688. if (Wnd <> TaskActiveWindow) and (Wnd <> Application.Handle) and
  689. IsWindowVisible(Wnd) and IsWindowEnabled(Wnd) then begin
  690. if GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOPMOST = 0 then begin
  691. if TaskFirstWindow = 0 then TaskFirstWindow := Wnd;
  692. end
  693. else begin
  694. if TaskFirstTopMost = 0 then TaskFirstTopMost := Wnd;
  695. end;
  696. end;
  697. Result := True;
  698. end;
  699. function FindTopLevelWindow(ActiveWindow: HWND): HWND;
  700. var
  701. FindData: TFindWindowData;
  702. begin
  703. with FindData do begin
  704. TaskActiveWindow := ActiveWindow;
  705. TaskFirstWindow := 0;
  706. TaskFirstTopMost := 0;
  707. EnumThreadWindows(GetCurrentThreadID, @DoFindWindow, Longint(@FindData));
  708. if TaskFirstWindow <> 0 then
  709. Result := TaskFirstWindow
  710. else
  711. Result := TaskFirstTopMost;
  712. end;
  713. end;
  714. function IsAncestorOfWindow(const ParentWnd: HWND; Wnd: HWND): Boolean;
  715. { Returns True if Wnd is a child of, is owned by, or is the same window as
  716. ParentWnd }
  717. begin
  718. while Wnd <> 0 do begin
  719. if Wnd = ParentWnd then begin
  720. Result := True;
  721. Exit;
  722. end;
  723. Wnd := GetParent(Wnd);
  724. end;
  725. Result := False;
  726. end;
  727. procedure RecalcNCArea(const Ctl: TWinControl);
  728. begin
  729. if Ctl.HandleAllocated then
  730. SetWindowPos(Ctl.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or
  731. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
  732. end;
  733. procedure InvalidateAll(const Ctl: TWinControl);
  734. { Invalidate both non-client and client area, and erase. }
  735. begin
  736. if Ctl.HandleAllocated then
  737. RedrawWindow(Ctl.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or
  738. RDW_ERASE or RDW_NOCHILDREN);
  739. end;
  740. type
  741. TSetCloseButtonStateProc = procedure(Pushed: Boolean) of object;
  742. function CloseButtonLoop(const Wnd: HWND; const ButtonRect: TRect;
  743. const SetCloseButtonStateProc: TSetCloseButtonStateProc): Boolean;
  744. function MouseInButton: Boolean;
  745. var
  746. P: TPoint;
  747. begin
  748. GetCursorPos(P);
  749. Result := PtInRect(ButtonRect, P);
  750. end;
  751. var
  752. Msg: TMsg;
  753. begin
  754. Result := False;
  755. SetCloseButtonStateProc(MouseInButton);
  756. SetCapture(Wnd);
  757. try
  758. while GetCapture = Wnd do begin
  759. case Integer(GetMessage(Msg, 0, 0, 0)) of
  760. -1: Break; { if GetMessage failed }
  761. 0: begin
  762. { Repost WM_QUIT messages }
  763. PostQuitMessage(Msg.WParam);
  764. Break;
  765. end;
  766. end;
  767. case Msg.Message of
  768. WM_KEYDOWN, WM_KEYUP:
  769. { Ignore all keystrokes while in a close button loop }
  770. ;
  771. WM_MOUSEMOVE: begin
  772. { Note to self: WM_MOUSEMOVE messages should never be dispatched
  773. here to ensure no hints get shown }
  774. SetCloseButtonStateProc(MouseInButton);
  775. end;
  776. WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
  777. { Make sure it doesn't begin another loop }
  778. Break;
  779. WM_LBUTTONUP: begin
  780. if MouseInButton then
  781. Result := True;
  782. Break;
  783. end;
  784. WM_RBUTTONDOWN..WM_MBUTTONDBLCLK:
  785. { Ignore all other mouse up/down messages }
  786. ;
  787. else
  788. TranslateMessage(Msg);
  789. DispatchMessage(Msg);
  790. end;
  791. end;
  792. finally
  793. if GetCapture = Wnd then
  794. ReleaseCapture;
  795. SetCloseButtonStateProc(False);
  796. end;
  797. end;
  798. { TTBDock - internal }
  799. constructor TTBDock.Create(AOwner: TComponent);
  800. begin
  801. inherited;
  802. ControlStyle := ControlStyle + [csAcceptsControls, csMenuEvents] -
  803. [csClickEvents, csCaptureMouse, csOpaque];
  804. FAllowDrag := True;
  805. FBkgOnToolbars := True;
  806. DockList := TList.Create;
  807. DockVisibleList := TList.Create;
  808. Color := clBtnFace;
  809. Position := dpTop;
  810. end;
  811. procedure TTBDock.CreateParams(var Params: TCreateParams);
  812. begin
  813. inherited;
  814. { Disable complete redraws when size changes. CS_H/VREDRAW cause flicker
  815. and are not necessary for this control at run time }
  816. if not(csDesigning in ComponentState) then
  817. with Params.WindowClass do
  818. Style := Style and not(CS_HREDRAW or CS_VREDRAW);
  819. end;
  820. destructor TTBDock.Destroy;
  821. begin
  822. {$IFNDEF MPEXCLUDE}
  823. if Assigned(FBackground) then
  824. FBackground.UnregisterChanges(BackgroundChanged);
  825. {$ENDIF}
  826. inherited;
  827. DockVisibleList.Free;
  828. DockList.Free;
  829. end;
  830. procedure TTBDock.SetParent(AParent: TWinControl);
  831. begin
  832. if (AParent is TTBCustomDockableWindow) or (AParent is TTBDock) then
  833. raise EInvalidOperation.Create(STBDockParentNotAllowed);
  834. inherited;
  835. end;
  836. procedure TTBDock.BeginUpdate;
  837. begin
  838. Inc(FDisableArrangeToolbars);
  839. end;
  840. procedure TTBDock.EndUpdate;
  841. begin
  842. Dec(FDisableArrangeToolbars);
  843. if FArrangeToolbarsNeeded and (FDisableArrangeToolbars = 0) then
  844. ArrangeToolbars;
  845. end;
  846. function TTBDock.HasVisibleToolbars: Boolean;
  847. var
  848. I: Integer;
  849. begin
  850. Result := False;
  851. for I := 0 to DockList.Count-1 do
  852. if ToolbarVisibleOnDock(TTBCustomDockableWindow(DockList[I])) then begin
  853. Result := True;
  854. Break;
  855. end;
  856. end;
  857. function TTBDock.ToolbarVisibleOnDock(const AToolbar: TTBCustomDockableWindow): Boolean;
  858. begin
  859. Result := (AToolbar.Parent = Self) and
  860. (AToolbar.Visible or (csDesigning in AToolbar.ComponentState));
  861. end;
  862. function TTBDock.GetCurrentRowSize(const Row: Integer;
  863. var AFullSize: Boolean): Integer;
  864. var
  865. I, J: Integer;
  866. T: TTBCustomDockableWindow;
  867. begin
  868. Result := 0;
  869. AFullSize := False;
  870. if Row < 0 then Exit;
  871. for I := 0 to DockList.Count-1 do begin
  872. T := DockList[I];
  873. if (T.FEffectiveDockRow = Row) and ToolbarVisibleOnDock(T) then begin
  874. AFullSize := T.FullSize;
  875. if not(Position in PositionLeftOrRight) then
  876. J := T.Height
  877. else
  878. J := T.Width;
  879. if J > Result then
  880. Result := J;
  881. end;
  882. end;
  883. end;
  884. function TTBDock.GetMinRowSize(const Row: Integer;
  885. const ExcludeControl: TTBCustomDockableWindow): Integer;
  886. var
  887. I, J: Integer;
  888. T: TTBCustomDockableWindow;
  889. begin
  890. Result := 0;
  891. if Row < 0 then Exit;
  892. for I := 0 to DockList.Count-1 do begin
  893. T := DockList[I];
  894. if (T <> ExcludeControl) and (T.FEffectiveDockRow = Row) and
  895. ToolbarVisibleOnDock(T) then begin
  896. J := T.FLastRowSize;
  897. if J > Result then
  898. Result := J;
  899. end;
  900. end;
  901. end;
  902. function TTBDock.GetDesignModeRowOf(const XY: Integer): Integer;
  903. { Similar to GetRowOf, but is a little different to accomidate design mode
  904. better }
  905. var
  906. HighestRowPlus1, R, CurY, CurRowSize: Integer;
  907. FullSize: Boolean;
  908. begin
  909. Result := 0;
  910. HighestRowPlus1 := GetHighestRow(True)+1;
  911. CurY := 0;
  912. for R := 0 to HighestRowPlus1 do begin
  913. Result := R;
  914. if R = HighestRowPlus1 then Break;
  915. CurRowSize := GetCurrentRowSize(R, FullSize);
  916. if CurRowSize = 0 then Continue;
  917. Inc(CurY, CurRowSize);
  918. if XY < CurY then
  919. Break;
  920. end;
  921. end;
  922. function TTBDock.GetHighestRow(const HighestEffective: Boolean): Integer;
  923. { Returns highest used row number, or -1 if no rows are used }
  924. var
  925. I, J: Integer;
  926. begin
  927. Result := -1;
  928. for I := 0 to DockList.Count-1 do
  929. with TTBCustomDockableWindow(DockList[I]) do begin
  930. if HighestEffective then
  931. J := FEffectiveDockRow
  932. else
  933. J := FDockRow;
  934. if J > Result then
  935. Result := J;
  936. end;
  937. end;
  938. procedure TTBDock.ChangeWidthHeight(const NewWidth, NewHeight: Integer);
  939. { Same as setting Width/Height directly, but does not lose Align position. }
  940. begin
  941. case Align of
  942. alNone, alTop, alLeft:
  943. SetBounds(Left, Top, NewWidth, NewHeight);
  944. alBottom:
  945. SetBounds(Left, Top-NewHeight+Height, NewWidth, NewHeight);
  946. alRight:
  947. SetBounds(Left-NewWidth+Width, Top, NewWidth, NewHeight);
  948. end;
  949. end;
  950. function TTBDock.Accepts(ADockableWindow: TTBCustomDockableWindow): Boolean;
  951. begin
  952. Result := AllowDrag;
  953. end;
  954. procedure TTBDock.AlignControls(AControl: TControl; var Rect: TRect);
  955. begin
  956. ArrangeToolbars;
  957. end;
  958. function CompareDockRowPos(const Item1, Item2, ExtraData: Pointer): Integer; far;
  959. begin
  960. if TTBCustomDockableWindow(Item1).FDockRow <> TTBCustomDockableWindow(Item2).FDockRow then
  961. Result := TTBCustomDockableWindow(Item1).FDockRow - TTBCustomDockableWindow(Item2).FDockRow
  962. else
  963. Result := TTBCustomDockableWindow(Item1).FDockPos - TTBCustomDockableWindow(Item2).FDockPos;
  964. end;
  965. procedure TTBDock.ArrangeToolbars;
  966. { The main procedure to arrange all the toolbars docked to it }
  967. type
  968. PPosDataRec = ^TPosDataRec;
  969. TPosDataRec = record
  970. Row, ActualRow, PrecSpace, FullSize, MinimumSize, Size, Overlap, Pos: Integer;
  971. ShrinkMode: TTBShrinkMode;
  972. NeedArrange: Boolean;
  973. end;
  974. PPosDataArray = ^TPosDataArray;
  975. TPosDataArray = array[0..$7FFFFFFF div SizeOf(TPosDataRec)-1] of TPosDataRec;
  976. var
  977. NewDockList: TList;
  978. PosData: PPosDataArray;
  979. function IndexOfDraggingToolbar(const List: TList): Integer;
  980. { Returns index of toolbar in List that's currently being dragged, or -1 }
  981. var
  982. I: Integer;
  983. begin
  984. for I := 0 to List.Count-1 do
  985. if TTBCustomDockableWindow(List[I]).FDragMode then begin
  986. Result := I;
  987. Exit;
  988. end;
  989. Result := -1;
  990. end;
  991. function ShiftLeft(const Row, StartIndex, MaxSize: Integer): Integer;
  992. { Removes PrecSpace pixels from toolbars at or before StartIndex until the
  993. right edge of the toolbar at StartIndex is <= MaxSize.
  994. Returns the total number of PrecSpace pixels removed from toolbars. }
  995. var
  996. PixelsOffEdge, I, J: Integer;
  997. P: PPosDataRec;
  998. begin
  999. Result := 0;
  1000. PixelsOffEdge := -MaxSize;
  1001. for I := 0 to StartIndex do begin
  1002. P := @PosData[I];
  1003. if P.Row = Row then begin
  1004. Inc(PixelsOffEdge, P.PrecSpace);
  1005. Inc(PixelsOffEdge, P.Size);
  1006. end;
  1007. end;
  1008. if PixelsOffEdge > 0 then
  1009. for I := StartIndex downto 0 do begin
  1010. P := @PosData[I];
  1011. if P.Row = Row then begin
  1012. J := PixelsOffEdge;
  1013. if P.PrecSpace < J then
  1014. J := P.PrecSpace;
  1015. Dec(P.PrecSpace, J);
  1016. Dec(PixelsOffEdge, J);
  1017. Inc(Result, J);
  1018. if PixelsOffEdge = 0 then
  1019. Break;
  1020. end;
  1021. end;
  1022. end;
  1023. function GetNextToolbar(const GoForward: Boolean; const Row: Integer;
  1024. const StartIndex: Integer): Integer;
  1025. var
  1026. I: Integer;
  1027. begin
  1028. Result := -1;
  1029. I := StartIndex;
  1030. while True do begin
  1031. if GoForward then begin
  1032. Inc(I);
  1033. if I >= NewDockList.Count then
  1034. Break;
  1035. end
  1036. else begin
  1037. Dec(I);
  1038. if I < 0 then
  1039. Break;
  1040. end;
  1041. if PosData[I].Row = Row then begin
  1042. Result := I;
  1043. Break;
  1044. end;
  1045. end;
  1046. end;
  1047. var
  1048. LeftRight: Boolean;
  1049. EmptySize, HighestRow, R, CurPos, CurRowPixel, I, J, K, L, ClientW,
  1050. ClientH, MaxSize, TotalSize, PixelsPastMaxSize, Offset, CurRealPos, DragIndex,
  1051. MinRealPos, DragIndexPos, ToolbarsOnRow, CurRowSize: Integer;
  1052. P: PPosDataRec;
  1053. T: TTBCustomDockableWindow;
  1054. S: TPoint;
  1055. RowIsEmpty: Boolean;
  1056. label FoundNextToolbar;
  1057. begin
  1058. if (FDisableArrangeToolbars > 0) or (csLoading in ComponentState) then begin
  1059. FArrangeToolbarsNeeded := True;
  1060. Exit;
  1061. end;
  1062. NewDockList := nil;
  1063. PosData := nil;
  1064. Inc(FDisableArrangeToolbars);
  1065. try
  1066. { Work around VCL alignment bug when docking toolbars taller or wider than
  1067. the client height or width of the form. }
  1068. {if not(csDesigning in ComponentState) and HandleAllocated then
  1069. SetWindowPos(Handle, HWND_TOP, 0, 0, 0, 0,
  1070. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);}
  1071. LeftRight := Position in PositionLeftOrRight;
  1072. if not HasVisibleToolbars then begin
  1073. EmptySize := Ord(FFixAlign);
  1074. if csDesigning in ComponentState then
  1075. EmptySize := 9;
  1076. if not LeftRight then
  1077. ChangeWidthHeight(Width, EmptySize)
  1078. else
  1079. ChangeWidthHeight(EmptySize, Height);
  1080. Exit;
  1081. end;
  1082. { It can't read the ClientWidth and ClientHeight properties because they
  1083. attempt to create a handle, which requires Parent to be set. "ClientW"
  1084. and "ClientH" are calculated instead. }
  1085. ClientW := Width - FNonClientWidth;
  1086. if ClientW < 0 then ClientW := 0;
  1087. ClientH := Height - FNonClientHeight;
  1088. if ClientH < 0 then ClientH := 0;
  1089. { Remove toolbars from DockList & DockVisibleList that are destroying, so
  1090. that no methods on these toolbars will be called.
  1091. This is needed because in certain rare cases ArrangeToolbars can be
  1092. indirectly called while a docked toolbar is being destroyed. }
  1093. for I := DockList.Count-1 downto 0 do begin
  1094. T := DockList[I];
  1095. if csDestroying in T.ComponentState then begin
  1096. DockList.Delete(I);
  1097. DockVisibleList.Remove(T);
  1098. end;
  1099. end;
  1100. { If LimitToOneRow is True, only use the first row }
  1101. if FLimitToOneRow then
  1102. for I := 0 to DockList.Count-1 do
  1103. with TTBCustomDockableWindow(DockList[I]) do
  1104. FDockRow := 0;
  1105. { Copy DockList to NewDockList, and ensure it is in correct ordering
  1106. according to DockRow/DockPos }
  1107. NewDockList := TList.Create;
  1108. NewDockList.Count := DockList.Count;
  1109. for I := 0 to NewDockList.Count-1 do
  1110. NewDockList[I] := DockList[I];
  1111. I := IndexOfDraggingToolbar(NewDockList);
  1112. ListSortEx(NewDockList, CompareDockRowPos, nil);
  1113. DragIndex := IndexOfDraggingToolbar(NewDockList);
  1114. if (I <> -1) and TTBCustomDockableWindow(NewDockList[DragIndex]).FDragSplitting then begin
  1115. { When splitting, don't allow the toolbar being dragged to change
  1116. positions in the dock list }
  1117. NewDockList.Move(DragIndex, I);
  1118. DragIndex := I;
  1119. end;
  1120. ListSortEx(DockVisibleList, CompareDockRowPos, nil);
  1121. { Find highest row number }
  1122. HighestRow := GetHighestRow(False);
  1123. { Create a temporary array that holds new position data for the toolbars }
  1124. PosData := AllocMem(NewDockList.Count * SizeOf(TPosDataRec));
  1125. for I := 0 to NewDockList.Count-1 do begin
  1126. P := @PosData[I];
  1127. T := NewDockList[I];
  1128. P.ActualRow := T.FDockRow;
  1129. if ToolbarVisibleOnDock(T) then
  1130. P.Row := T.FDockRow
  1131. else
  1132. P.Row := -1;
  1133. P.Pos := T.FDockPos;
  1134. end;
  1135. { Find FInsertRowBefore=True and FullSize=True toolbars and make sure there
  1136. aren't any other toolbars on the same row. If there are, shift them down
  1137. a row. }
  1138. for L := 0 to 1 do begin
  1139. R := 0;
  1140. while R <= HighestRow do begin
  1141. for I := 0 to NewDockList.Count-1 do begin
  1142. T := NewDockList[I];
  1143. if (PosData[I].ActualRow = R) and
  1144. (((L = 0) and T.FInsertRowBefore and not LimitToOneRow) or
  1145. ((L = 1) and T.FullSize)) then
  1146. for J := 0 to NewDockList.Count-1 do
  1147. if (J <> I) and (PosData[J].ActualRow = R) then begin
  1148. for K := 0 to NewDockList.Count-1 do begin
  1149. if K <> I then begin
  1150. P := @PosData[K];
  1151. if P.ActualRow >= R then
  1152. Inc(P.ActualRow);
  1153. if P.Row >= R then
  1154. Inc(P.Row);
  1155. end;
  1156. end;
  1157. Inc(HighestRow);
  1158. Break;
  1159. end;
  1160. end;
  1161. Inc(R);
  1162. end;
  1163. end;
  1164. { Remove blank rows.
  1165. Note that rows that contain only invisible or currently floating toolbars
  1166. are intentionally not removed, so that when the toolbars are shown again,
  1167. they stay on their own row. }
  1168. R := 0;
  1169. while R <= HighestRow do begin
  1170. RowIsEmpty := True;
  1171. for I := 0 to NewDockList.Count-1 do
  1172. if PosData[I].ActualRow = R then begin
  1173. RowIsEmpty := False;
  1174. Break;
  1175. end;
  1176. if RowIsEmpty then begin
  1177. { Shift all ones higher than R back one }
  1178. for I := 0 to NewDockList.Count-1 do begin
  1179. if PosData[I].ActualRow > R then
  1180. Dec(PosData[I].ActualRow);
  1181. if PosData[I].Row > R then
  1182. Dec(PosData[I].Row);
  1183. end;
  1184. Dec(HighestRow);
  1185. end
  1186. else
  1187. Inc(R);
  1188. end;
  1189. { Calculate positions and sizes of each row }
  1190. R := 0;
  1191. while R <= HighestRow do begin
  1192. if not LeftRight then
  1193. MaxSize := ClientW
  1194. else
  1195. MaxSize := ClientH;
  1196. { Set initial sizes }
  1197. TotalSize := 0;
  1198. ToolbarsOnRow := 0;
  1199. MinRealPos := 0;
  1200. for I := 0 to NewDockList.Count-1 do begin
  1201. P := @PosData[I];
  1202. if P.Row = R then begin
  1203. T := NewDockList[I];
  1204. T.GetBaseSize(S);
  1205. if not LeftRight then
  1206. J := S.X + T.NonClientWidth
  1207. else
  1208. J := S.Y + T.NonClientHeight;
  1209. P.FullSize := J;
  1210. P.Size := J;
  1211. P.ShrinkMode := T.GetShrinkMode;
  1212. P.MinimumSize := 0;
  1213. T.GetMinShrinkSize(P.MinimumSize);
  1214. if P.MinimumSize > P.FullSize then
  1215. { don't allow minimum shrink size to be less than full size }
  1216. P.MinimumSize := P.FullSize;
  1217. if P.ShrinkMode = tbsmChevron then
  1218. Inc(MinRealPos, P.MinimumSize)
  1219. else
  1220. Inc(MinRealPos, P.FullSize);
  1221. { If the toolbar isn't the first toolbar on the row, and the toolbar
  1222. would go off the edge even after it's shrunk, then move it onto a
  1223. row of its own }
  1224. if (ToolbarsOnRow > 0) and (MinRealPos > MaxSize) and
  1225. not LimitToOneRow then begin
  1226. for K := I to NewDockList.Count-1 do begin
  1227. P := @PosData[K];
  1228. if P.ActualRow >= R then
  1229. Inc(P.ActualRow);
  1230. if P.Row >= R then
  1231. Inc(P.Row);
  1232. end;
  1233. Inc(HighestRow);
  1234. Break;
  1235. end;
  1236. Inc(TotalSize, J);
  1237. Inc(ToolbarsOnRow);
  1238. end;
  1239. end;
  1240. PixelsPastMaxSize := TotalSize - MaxSize;
  1241. { Set initial arrangement; don't shrink toolbars yet }
  1242. DragIndexPos := 0;
  1243. CurPos := 0;
  1244. CurRealPos := 0;
  1245. MinRealPos := 0;
  1246. for I := 0 to NewDockList.Count-1 do begin
  1247. P := @PosData[I];
  1248. T := NewDockList[I];
  1249. if P.Row = R then begin
  1250. if (CurPos = 0) and (T.FullSize or T.Stretch) then
  1251. { Force to left }
  1252. J := 0
  1253. else
  1254. J := T.FDockPos;
  1255. if I = DragIndex then
  1256. DragIndexPos := J;
  1257. { Don't let this toolbar overlap preceding toolbars by more than
  1258. the sum of their minimum sizes }
  1259. if J < MinRealPos then
  1260. J := MinRealPos;
  1261. if J > CurPos then begin
  1262. { There's a gap between the left edge or previous toolbar and
  1263. this toolbar }
  1264. if PixelsPastMaxSize <= 0 then begin
  1265. P.PrecSpace := J - CurPos;
  1266. CurPos := J;
  1267. end
  1268. else
  1269. { Don't allow a gap if exceeding MaxSize }
  1270. J := CurPos;
  1271. end
  1272. else begin
  1273. if J < CurRealPos then
  1274. P.Overlap := CurRealPos - J;
  1275. end;
  1276. Inc(CurPos, P.Size);
  1277. CurRealPos := J + P.Size;
  1278. Inc(MinRealPos, P.MinimumSize);
  1279. end;
  1280. end;
  1281. { If we aren't exceeding MaxSize, allow the toolbar being dragged
  1282. to push other toolbars to the left }
  1283. if (PixelsPastMaxSize < 0) and (DragIndex <> -1) and
  1284. (PosData[DragIndex].Row = R) then begin
  1285. I := GetNextToolbar(False, R, DragIndex);
  1286. if I <> -1 then begin
  1287. J := ShiftLeft(R, I, DragIndexPos);
  1288. if J > 0 then begin
  1289. { Ensure that toolbars that follow the toolbar being dragged stay
  1290. at the same place by increasing PrecSpace on the next toolbar }
  1291. I := GetNextToolbar(True, R, DragIndex);
  1292. if I <> -1 then
  1293. Inc(PosData[I].PrecSpace, J);
  1294. end;
  1295. end;
  1296. end;
  1297. { If any toolbars are going off the edge of the dock, try to make them
  1298. at least partially visible by shifting preceding toolbars left }
  1299. I := GetNextToolbar(False, R, NewDockList.Count);
  1300. if I <> -1 then
  1301. ShiftLeft(R, I, MaxSize);
  1302. { Shrink toolbars that overlap other toolbars (Overlaps[x] > 0) }
  1303. if PixelsPastMaxSize > 0 then begin
  1304. Offset := 0;
  1305. for I := 0 to NewDockList.Count-1 do begin
  1306. if PosData[I].Row <> R then
  1307. Continue;
  1308. T := NewDockList[I];
  1309. if (ToolbarsOnRow > 1) and T.FDragMode then
  1310. T.FDragCanSplit := True;
  1311. Inc(Offset, PosData[I].Overlap);
  1312. if Offset > PixelsPastMaxSize then
  1313. Offset := PixelsPastMaxSize;
  1314. if Offset > 0 then
  1315. for J := I-1 downto 0 do begin
  1316. P := @PosData[J];
  1317. if P.Row <> R then
  1318. Continue;
  1319. { How much can we shrink this toolbar J to get toolbar I to
  1320. its preferred position? }
  1321. if P.ShrinkMode = tbsmChevron then
  1322. L := Offset
  1323. else
  1324. L := 0;
  1325. K := -(P.Size - L - P.MinimumSize); { the number of pixels that exceed the minimum size }
  1326. if K > 0 then
  1327. { Don't shrink a toolbar below its minimum allowed size }
  1328. Dec(L, K);
  1329. Dec(P.Size, L);
  1330. Dec(PixelsPastMaxSize, L);
  1331. Dec(Offset, L);
  1332. if (Offset = 0) or
  1333. { This is needed so toolbars can push other toolbars to the
  1334. right when splitting: }
  1335. (J = DragIndex) then
  1336. Break;
  1337. end;
  1338. end;
  1339. end;
  1340. { Still exceeding MaxSize? Make sure the rightmost toolbar(s) are
  1341. at least partially visible with a width of MinimumSize }
  1342. if PixelsPastMaxSize > 0 then begin
  1343. for I := NewDockList.Count-1 downto 0 do begin
  1344. P := @PosData[I];
  1345. if (P.Row <> R) or (P.ShrinkMode = tbsmNone) or
  1346. ((P.ShrinkMode = tbsmWrap) and (ToolbarsOnRow > 1)) then
  1347. Continue;
  1348. J := P.Size - P.MinimumSize;
  1349. if J > 0 then begin { can we shrink this toolbar any? }
  1350. if J > PixelsPastMaxSize then
  1351. J := PixelsPastMaxSize;
  1352. Dec(P.Size, J);
  1353. Dec(PixelsPastMaxSize, J);
  1354. end;
  1355. if PixelsPastMaxSize = 0 then
  1356. Break;
  1357. end;
  1358. end;
  1359. { Set Poses, and adjust size of FullSize & Stretch toolbars }
  1360. CurPos := 0;
  1361. for I := 0 to NewDockList.Count-1 do begin
  1362. P := @PosData[I];
  1363. T := NewDockList[I];
  1364. if P.Row = R then begin
  1365. if T.FullSize or T.Stretch then begin
  1366. { Remove any preceding space from this toolbar }
  1367. Inc(P.Size, P.PrecSpace);
  1368. P.PrecSpace := 0;
  1369. end;
  1370. Inc(CurPos, P.PrecSpace);
  1371. if T.FullSize then begin
  1372. { Claim all space }
  1373. if P.Size < MaxSize then
  1374. P.Size := MaxSize;
  1375. end
  1376. else if T.Stretch then begin
  1377. { Steal any preceding space from the next toolbar }
  1378. for J := I+1 to NewDockList.Count-1 do
  1379. if PosData[J].Row = R then begin
  1380. Inc(P.Size, PosData[J].PrecSpace);
  1381. PosData[J].PrecSpace := 0;
  1382. goto FoundNextToolbar;
  1383. end;
  1384. { or claim any remaining space }
  1385. if P.Size < MaxSize - CurPos then
  1386. P.Size := MaxSize - CurPos;
  1387. FoundNextToolbar:
  1388. { MP }
  1389. { When dock shrinks, shrink the stretched toolbars too }
  1390. if P.Size > MaxSize - CurPos then
  1391. P.Size := MaxSize - CurPos;
  1392. { /MP }
  1393. end;
  1394. P.Pos := CurPos;
  1395. Inc(CurPos, P.Size);
  1396. end;
  1397. end;
  1398. Inc(R);
  1399. end;
  1400. for I := 0 to NewDockList.Count-1 do begin
  1401. T := NewDockList[I];
  1402. T.FEffectiveDockRow := PosData[I].ActualRow;
  1403. T.FEffectiveDockPos := PosData[I].Pos;
  1404. { If FCommitNewPositions is True, update all the toolbars' DockPos and
  1405. DockRow properties to match the actual positions.
  1406. Also update the ordering of DockList to match NewDockList }
  1407. if FCommitNewPositions then begin
  1408. T.FDockRow := T.FEffectiveDockRow;
  1409. T.FDockPos := T.FEffectiveDockPos;
  1410. DockList[I] := NewDockList[I];
  1411. end;
  1412. end;
  1413. { Now actually move the toolbars }
  1414. CurRowPixel := 0;
  1415. for R := 0 to HighestRow do begin
  1416. CurRowSize := 0;
  1417. for I := 0 to NewDockList.Count-1 do begin
  1418. P := @PosData[I];
  1419. T := NewDockList[I];
  1420. if P.Row = R then begin
  1421. K := T.FCurrentSize;
  1422. T.FCurrentSize := P.Size;
  1423. if P.Size >= P.FullSize then begin
  1424. T.FCurrentSize := 0;
  1425. { Reason: so that if new items are added to a non-shrunk toolbar
  1426. at run-time (causing its width to increase), the toolbar won't
  1427. shrink unnecessarily }
  1428. end;
  1429. if (P.ShrinkMode <> tbsmNone) and (T.FCurrentSize <> K) then begin
  1430. { If Size is changing and we are to display a chevron or wrap,
  1431. call DoArrange to get an accurate row size }
  1432. S := T.DoArrange(False, TBGetDockTypeOf(Self, False), False, Self);
  1433. { Force a rearrange in case the actual size isn't changing but the
  1434. chevron visibility might have changed (which can happen if
  1435. items are added to a FullSize=True toolbar at run-time) }
  1436. P.NeedArrange := True;
  1437. end
  1438. else begin
  1439. if (P.ShrinkMode = tbsmWrap) and (P.Size < P.FullSize) then begin
  1440. { Preserve existing height (or width) on a wrapped toolbar
  1441. whose size isn't changing now }
  1442. S.X := T.Width - T.NonClientWidth;
  1443. S.Y := T.Height - T.NonClientHeight;
  1444. end
  1445. else
  1446. T.GetBaseSize(S);
  1447. end;
  1448. if not LeftRight then
  1449. K := S.Y
  1450. else
  1451. K := S.X;
  1452. T.FLastRowSize := K;
  1453. if K > CurRowSize then
  1454. CurRowSize := K;
  1455. end;
  1456. end;
  1457. if CurRowSize <> 0 then
  1458. Inc(CurRowSize, DockedBorderSize2);
  1459. for I := 0 to NewDockList.Count-1 do begin
  1460. P := @PosData[I];
  1461. T := NewDockList[I];
  1462. if P.Row = R then begin
  1463. Inc(T.FUpdatingBounds);
  1464. try
  1465. K := T.FCurrentSize;
  1466. if P.NeedArrange then
  1467. T.FArrangeNeeded := True;
  1468. if not LeftRight then
  1469. T.SetBounds(P.Pos, CurRowPixel, P.Size, CurRowSize)
  1470. else
  1471. T.SetBounds(CurRowPixel, P.Pos, CurRowSize, P.Size);
  1472. if T.FArrangeNeeded then
  1473. { ^ don't arrange again if SetBounds call already caused one }
  1474. T.Arrange;
  1475. { Restore FCurrentSize since TTBToolbarView.DoUpdatePositions
  1476. clears it }
  1477. T.FCurrentSize := K;
  1478. finally
  1479. Dec(T.FUpdatingBounds);
  1480. end;
  1481. end;
  1482. end;
  1483. Inc(CurRowPixel, CurRowSize);
  1484. end;
  1485. { Set the size of the dock }
  1486. if not LeftRight then
  1487. ChangeWidthHeight(Width, CurRowPixel + FNonClientHeight)
  1488. else
  1489. ChangeWidthHeight(CurRowPixel + FNonClientWidth, Height);
  1490. finally
  1491. Dec(FDisableArrangeToolbars);
  1492. FArrangeToolbarsNeeded := False;
  1493. FCommitNewPositions := False;
  1494. FreeMem(PosData);
  1495. NewDockList.Free;
  1496. end;
  1497. end;
  1498. procedure TTBDock.CommitPositions;
  1499. { Copies docked toolbars' EffectiveDockRow and EffectiveDockPos properties
  1500. into DockRow and DockPos respectively.
  1501. Note that this does not reorder DockList like ArrangeToolbars does when
  1502. FCommitNewPositions=True. }
  1503. var
  1504. I: Integer;
  1505. T: TTBCustomDockableWindow;
  1506. begin
  1507. for I := 0 to DockVisibleList.Count-1 do begin
  1508. T := DockVisibleList[I];
  1509. T.FDockRow := T.FEffectiveDockRow;
  1510. T.FDockPos := T.FEffectiveDockPos;
  1511. end;
  1512. end;
  1513. procedure TTBDock.ChangeDockList(const Insert: Boolean;
  1514. const Bar: TTBCustomDockableWindow);
  1515. { Inserts or removes Bar from DockList }
  1516. var
  1517. I: Integer;
  1518. begin
  1519. I := DockList.IndexOf(Bar);
  1520. if Insert then begin
  1521. if I = -1 then begin
  1522. Bar.FreeNotification(Self);
  1523. DockList.Add(Bar);
  1524. end;
  1525. end
  1526. else begin
  1527. if I <> -1 then
  1528. DockList.Delete(I);
  1529. end;
  1530. ToolbarVisibilityChanged(Bar, False);
  1531. end;
  1532. procedure TTBDock.ToolbarVisibilityChanged(const Bar: TTBCustomDockableWindow;
  1533. const ForceRemove: Boolean);
  1534. var
  1535. Modified, VisibleOnDock: Boolean;
  1536. I: Integer;
  1537. begin
  1538. Modified := False;
  1539. I := DockVisibleList.IndexOf(Bar);
  1540. VisibleOnDock := not ForceRemove and ToolbarVisibleOnDock(Bar);
  1541. if VisibleOnDock then begin
  1542. if I = -1 then begin
  1543. DockVisibleList.Add(Bar);
  1544. Modified := True;
  1545. end;
  1546. end
  1547. else begin
  1548. if I <> -1 then begin
  1549. DockVisibleList.Remove(Bar);
  1550. Modified := True;
  1551. end;
  1552. end;
  1553. if Modified then begin
  1554. ArrangeToolbars;
  1555. if Assigned(FOnInsertRemoveBar) then
  1556. FOnInsertRemoveBar(Self, VisibleOnDock, Bar);
  1557. end;
  1558. end;
  1559. procedure TTBDock.Loaded;
  1560. begin
  1561. inherited;
  1562. { Rearranging is disabled while the component is loading, so now that it's
  1563. loaded, rearrange it. }
  1564. ArrangeToolbars;
  1565. end;
  1566. procedure TTBDock.Notification(AComponent: TComponent; Operation: TOperation);
  1567. begin
  1568. inherited;
  1569. if Operation = opRemove then begin
  1570. {$IFNDEF MPEXCLUDE}
  1571. if AComponent = FBackground then
  1572. Background := nil
  1573. else {$ENDIF} if AComponent is TTBCustomDockableWindow then begin
  1574. DockList.Remove(AComponent);
  1575. DockVisibleList.Remove(AComponent);
  1576. end;
  1577. end;
  1578. end;
  1579. {$IFNDEF MPEXCLUDE}
  1580. function TTBDock.GetPalette: HPALETTE;
  1581. begin
  1582. if UsingBackground and Assigned(FBackground) then
  1583. { ^ by default UsingBackground returns False if FBackground isn't assigned,
  1584. but UsingBackground may be overridden and return True when it isn't }
  1585. Result := FBackground.GetPalette
  1586. else
  1587. Result := 0;
  1588. end;
  1589. {$ENDIF}
  1590. procedure TTBDock.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  1591. var
  1592. R, R2: TRect;
  1593. P1, P2: TPoint;
  1594. SaveIndex: Integer;
  1595. begin
  1596. { Draw the Background if there is one, otherwise use default erasing
  1597. behavior }
  1598. if UsingBackground then begin
  1599. R := ClientRect;
  1600. R2 := R;
  1601. { Make up for nonclient area }
  1602. P1 := ClientToScreen(Point(0, 0));
  1603. P2 := Parent.ClientToScreen(BoundsRect.TopLeft);
  1604. Dec(R2.Left, Left + (P1.X-P2.X));
  1605. Dec(R2.Top, Top + (P1.Y-P2.Y));
  1606. SaveIndex := SaveDC(Message.DC);
  1607. IntersectClipRect(Message.DC, R.Left, R.Top, R.Right, R.Bottom);
  1608. DrawBackground(Message.DC, R2);
  1609. RestoreDC(Message.DC, SaveIndex);
  1610. Message.Result := 1;
  1611. end
  1612. else
  1613. inherited;
  1614. end;
  1615. procedure TTBDock.Paint;
  1616. var
  1617. R: TRect;
  1618. begin
  1619. inherited;
  1620. { Draw dotted border in design mode }
  1621. if csDesigning in ComponentState then begin
  1622. R := ClientRect;
  1623. with Canvas do begin
  1624. Pen.Style := psDot;
  1625. Pen.Color := clBtnShadow;
  1626. Brush.Style := bsClear;
  1627. Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  1628. Pen.Style := psSolid;
  1629. end;
  1630. end;
  1631. end;
  1632. procedure TTBDock.WMMove(var Message: TWMMove);
  1633. begin
  1634. inherited;
  1635. if UsingBackground then
  1636. InvalidateBackgrounds;
  1637. end;
  1638. {$IFNDEF JR_D4}
  1639. procedure TTBDock.WMSize(var Message: TWMSize);
  1640. begin
  1641. inherited;
  1642. if not(csLoading in ComponentState) and Assigned(FOnResize) then
  1643. FOnResize(Self);
  1644. end;
  1645. {$ENDIF}
  1646. procedure TTBDock.WMNCCalcSize(var Message: TWMNCCalcSize);
  1647. begin
  1648. inherited;
  1649. { note to self: non-client size is stored in FNonClientWidth &
  1650. FNonClientHeight }
  1651. with Message.CalcSize_Params^.rgrc[0] do begin
  1652. if blTop in BoundLines then Inc(Top);
  1653. if blBottom in BoundLines then Dec(Bottom);
  1654. if blLeft in BoundLines then Inc(Left);
  1655. if blRight in BoundLines then Dec(Right);
  1656. end;
  1657. end;
  1658. procedure TTBDock.DrawNCArea(const DrawToDC: Boolean; const ADC: HDC;
  1659. const Clip: HRGN);
  1660. procedure DrawLine(const DC: HDC; const X1, Y1, X2, Y2: Integer);
  1661. begin
  1662. MoveToEx(DC, X1, Y1, nil); LineTo(DC, X2, Y2);
  1663. end;
  1664. var
  1665. RW, R, R2, RC: TRect;
  1666. DC: HDC;
  1667. HighlightPen, ShadowPen, SavePen: HPEN;
  1668. FillBrush: HBRUSH;
  1669. label 1;
  1670. begin
  1671. { This works around WM_NCPAINT problem described at top of source code }
  1672. {no! R := Rect(0, 0, Width, Height);}
  1673. GetWindowRect(Handle, RW);
  1674. R := RW;
  1675. OffsetRect(R, -R.Left, -R.Top);
  1676. if not DrawToDC then
  1677. DC := GetWindowDC(Handle)
  1678. else
  1679. DC := ADC;
  1680. try
  1681. { Use update region }
  1682. if not DrawToDC then
  1683. SelectNCUpdateRgn(Handle, DC, Clip);
  1684. { Draw BoundLines }
  1685. R2 := R;
  1686. if (BoundLines <> []) and
  1687. ((csDesigning in ComponentState) or HasVisibleToolbars) then begin
  1688. HighlightPen := CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
  1689. ShadowPen := CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  1690. SavePen := SelectObject(DC, ShadowPen);
  1691. if blTop in BoundLines then begin
  1692. DrawLine(DC, R.Left, R.Top, R.Right, R.Top);
  1693. Inc(R2.Top);
  1694. end;
  1695. if blLeft in BoundLines then begin
  1696. DrawLine(DC, R.Left, R.Top, R.Left, R.Bottom);
  1697. Inc(R2.Left);
  1698. end;
  1699. SelectObject(DC, HighlightPen);
  1700. if blBottom in BoundLines then begin
  1701. DrawLine(DC, R.Left, R.Bottom-1, R.Right, R.Bottom-1);
  1702. Dec(R2.Bottom);
  1703. end;
  1704. if blRight in BoundLines then begin
  1705. DrawLine(DC, R.Right-1, R.Top, R.Right-1, R.Bottom);
  1706. Dec(R2.Right);
  1707. end;
  1708. SelectObject(DC, SavePen);
  1709. DeleteObject(ShadowPen);
  1710. DeleteObject(HighlightPen);
  1711. end;
  1712. Windows.GetClientRect(Handle, RC);
  1713. if not IsRectEmpty(RC) then begin
  1714. { ^ ExcludeClipRect can't be passed rectangles that have (Bottom < Top) or
  1715. (Right < Left) since it doesn't treat them as empty }
  1716. MapWindowPoints(Handle, 0, RC, 2);
  1717. OffsetRect(RC, -RW.Left, -RW.Top);
  1718. if EqualRect(RC, R2) then
  1719. { Skip FillRect because there would be nothing left after ExcludeClipRect }
  1720. goto 1;
  1721. ExcludeClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom);
  1722. end;
  1723. FillBrush := CreateSolidBrush(ColorToRGB(Color));
  1724. FillRect(DC, R2, FillBrush);
  1725. DeleteObject(FillBrush);
  1726. 1:
  1727. finally
  1728. if not DrawToDC then
  1729. ReleaseDC(Handle, DC);
  1730. end;
  1731. end;
  1732. procedure TTBDock.WMNCPaint(var Message: TMessage);
  1733. begin
  1734. DrawNCArea(False, 0, HRGN(Message.WParam));
  1735. end;
  1736. procedure DockNCPaintProc(Wnd: HWND; DC: HDC; AppData: Longint);
  1737. begin
  1738. TTBDock(AppData).DrawNCArea(True, DC, 0);
  1739. end;
  1740. procedure TTBDock.WMPrint(var Message: TMessage);
  1741. begin
  1742. HandleWMPrint(Handle, Message, DockNCPaintProc, Longint(Self));
  1743. end;
  1744. procedure TTBDock.WMPrintClient(var Message: TMessage);
  1745. begin
  1746. HandleWMPrintClient(Self, Message);
  1747. end;
  1748. {$IFNDEF MPEXCLUDE}
  1749. procedure TTBDock.CMSysColorChange(var Message: TMessage);
  1750. begin
  1751. inherited;
  1752. if Assigned(FBackground) then
  1753. FBackground.SysColorChanged;
  1754. end;
  1755. {$ENDIF}
  1756. procedure TTBDock.RelayMsgToFloatingBars(var Message: TMessage);
  1757. var
  1758. I: Integer;
  1759. T: TTBCustomDockableWindow;
  1760. begin
  1761. for I := 0 to DockList.Count-1 do begin
  1762. T := DockList[I];
  1763. if (csMenuEvents in T.ControlStyle) and T.Floating and T.Showing and
  1764. T.Enabled then begin
  1765. Message.Result := T.Perform(Message.Msg, Message.WParam, Message.LParam);
  1766. if Message.Result <> 0 then
  1767. Exit;
  1768. end;
  1769. end;
  1770. end;
  1771. procedure TTBDock.WMSysCommand(var Message: TWMSysCommand);
  1772. begin
  1773. { Relay WM_SYSCOMMAND messages to floating toolbars which were formerly
  1774. docked. That way, items on floating menu bars can be accessed with Alt. }
  1775. RelayMsgToFloatingBars(TMessage(Message));
  1776. end;
  1777. procedure TTBDock.CMDialogKey(var Message: TCMDialogKey);
  1778. begin
  1779. RelayMsgToFloatingBars(TMessage(Message));
  1780. if Message.Result = 0 then
  1781. inherited;
  1782. end;
  1783. procedure TTBDock.CMDialogChar(var Message: TCMDialogChar);
  1784. begin
  1785. RelayMsgToFloatingBars(TMessage(Message));
  1786. if Message.Result = 0 then
  1787. inherited;
  1788. end;
  1789. { TTBDock - property access methods }
  1790. procedure TTBDock.SetAllowDrag(Value: Boolean);
  1791. var
  1792. I: Integer;
  1793. begin
  1794. if FAllowDrag <> Value then begin
  1795. FAllowDrag := Value;
  1796. for I := 0 to ControlCount-1 do
  1797. if Controls[I] is TTBCustomDockableWindow then
  1798. RecalcNCArea(TTBCustomDockableWindow(Controls[I]));
  1799. end;
  1800. end;
  1801. function TTBDock.UsingBackground: Boolean;
  1802. begin
  1803. {$IFNDEF MPEXCLUDE}
  1804. Result := Assigned(FBackground) and FBackground.UsingBackground;
  1805. {$ELSE}
  1806. Result := False;
  1807. {$ENDIF}
  1808. end;
  1809. procedure TTBDock.DrawBackground(DC: HDC; const DrawRect: TRect);
  1810. begin
  1811. {$IFNDEF MPEXCLUDE}
  1812. FBackground.Draw(DC, DrawRect);
  1813. {$ENDIF}
  1814. end;
  1815. procedure TTBDock.InvalidateBackgrounds;
  1816. { Called after background is changed }
  1817. var
  1818. I: Integer;
  1819. T: TTBCustomDockableWindow;
  1820. begin
  1821. Invalidate;
  1822. { Synchronize child toolbars also }
  1823. for I := 0 to DockList.Count-1 do begin
  1824. T := TTBCustomDockableWindow(DockList[I]);
  1825. if ToolbarVisibleOnDock(T) then
  1826. { Invalidate both non-client and client area }
  1827. InvalidateAll(T);
  1828. end;
  1829. end;
  1830. {$IFNDEF MPEXCLUDE}
  1831. procedure TTBDock.SetBackground(Value: TTBBasicBackground);
  1832. begin
  1833. if FBackground <> Value then begin
  1834. if Assigned(FBackground) then
  1835. FBackground.UnregisterChanges(BackgroundChanged);
  1836. FBackground := Value;
  1837. if Assigned(Value) then begin
  1838. Value.FreeNotification(Self);
  1839. Value.RegisterChanges(BackgroundChanged);
  1840. end;
  1841. InvalidateBackgrounds;
  1842. end;
  1843. end;
  1844. procedure TTBDock.BackgroundChanged(Sender: TObject);
  1845. begin
  1846. InvalidateBackgrounds;
  1847. end;
  1848. procedure TTBDock.SetBackgroundOnToolbars(Value: Boolean);
  1849. begin
  1850. if FBkgOnToolbars <> Value then begin
  1851. FBkgOnToolbars := Value;
  1852. InvalidateBackgrounds;
  1853. end;
  1854. end;
  1855. {$ENDIF}
  1856. procedure TTBDock.SetBoundLines(Value: TTBDockBoundLines);
  1857. var
  1858. X, Y: Integer;
  1859. B: TTBDockBoundLines;
  1860. begin
  1861. if FBoundLines <> Value then begin
  1862. FBoundLines := Value;
  1863. X := 0;
  1864. Y := 0;
  1865. B := BoundLines; { optimization }
  1866. if blTop in B then Inc(Y);
  1867. if blBottom in B then Inc(Y);
  1868. if blLeft in B then Inc(X);
  1869. if blRight in B then Inc(X);
  1870. FNonClientWidth := X;
  1871. FNonClientHeight := Y;
  1872. RecalcNCArea(Self);
  1873. end;
  1874. end;
  1875. procedure TTBDock.SetFixAlign(Value: Boolean);
  1876. begin
  1877. if FFixAlign <> Value then begin
  1878. FFixAlign := Value;
  1879. ArrangeToolbars;
  1880. end;
  1881. end;
  1882. procedure TTBDock.SetPosition(Value: TTBDockPosition);
  1883. begin
  1884. if (FPosition <> Value) and (ControlCount <> 0) then
  1885. raise EInvalidOperation.Create(STBDockCannotChangePosition);
  1886. FPosition := Value;
  1887. case Position of
  1888. dpTop: Align := alTop;
  1889. dpBottom: Align := alBottom;
  1890. dpLeft: Align := alLeft;
  1891. dpRight: Align := alRight;
  1892. end;
  1893. end;
  1894. function TTBDock.GetToolbarCount: Integer;
  1895. begin
  1896. Result := DockVisibleList.Count;
  1897. end;
  1898. function TTBDock.GetToolbars(Index: Integer): TTBCustomDockableWindow;
  1899. begin
  1900. Result := TTBCustomDockableWindow(DockVisibleList[Index]);
  1901. end;
  1902. (*function TTBDock.GetVersion: TToolbar97Version;
  1903. begin
  1904. Result := Toolbar97VersionPropText;
  1905. end;
  1906. procedure TTBDock.SetVersion(const Value: TToolbar97Version);
  1907. begin
  1908. { write method required for the property to show up in Object Inspector }
  1909. end;*)
  1910. { TTBFloatingWindowParent - Internal }
  1911. constructor TTBFloatingWindowParent.Create(AOwner: TComponent);
  1912. begin
  1913. { Don't use TForm's Create since it attempts to load a form resource, which
  1914. TTBFloatingWindowParent doesn't have. }
  1915. CreateNew(AOwner {$IFDEF VER93} , 0 {$ENDIF});
  1916. end;
  1917. destructor TTBFloatingWindowParent.Destroy;
  1918. begin
  1919. inherited;
  1920. end;
  1921. procedure TTBFloatingWindowParent.CreateParams(var Params: TCreateParams);
  1922. const
  1923. ThickFrames: array[Boolean] of DWORD = (0, WS_THICKFRAME);
  1924. begin
  1925. inherited;
  1926. { Disable complete redraws when size changes. CS_H/VREDRAW cause flicker
  1927. and are not necessary for this control at run time }
  1928. if not(csDesigning in ComponentState) then
  1929. with Params.WindowClass do
  1930. Style := Style and not(CS_HREDRAW or CS_VREDRAW);
  1931. with Params do begin
  1932. { Note: WS_THICKFRAME and WS_BORDER styles are included to ensure that
  1933. sizing grips are displayed on child controls with scrollbars. The
  1934. thick frame or border is not drawn by Windows; TCustomToolWindow97
  1935. handles all border drawing by itself. }
  1936. if not(csDesigning in ComponentState) then
  1937. Style := WS_POPUP or WS_BORDER or ThickFrames[FDockableWindow.FResizable]
  1938. else
  1939. Style := Style or WS_BORDER or ThickFrames[FDockableWindow.FResizable];
  1940. { The WS_EX_TOOLWINDOW style is needed so there isn't a taskbar button
  1941. for the toolbar when FloatingMode = fmOnTopOfAllForms. }
  1942. ExStyle := WS_EX_TOOLWINDOW;
  1943. end;
  1944. end;
  1945. procedure TTBFloatingWindowParent.AlignControls(AControl: TControl; var Rect: TRect);
  1946. begin
  1947. { ignore Align setting of the child toolbar }
  1948. end;
  1949. procedure TTBFloatingWindowParent.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
  1950. begin
  1951. inherited;
  1952. { Because the window uses the WS_THICKFRAME style (but not for the usual
  1953. purpose), it must process the WM_GETMINMAXINFO message to remove the
  1954. minimum and maximum size limits it imposes by default. }
  1955. with Message.MinMaxInfo^ do begin
  1956. with ptMinTrackSize do begin
  1957. X := 1;
  1958. Y := 1;
  1959. { Note to self: Don't put GetMinimumSize code here, since
  1960. ClientWidth/Height values are sometimes invalid during a RecreateWnd }
  1961. end;
  1962. with ptMaxTrackSize do begin
  1963. { Because of the 16-bit (signed) size limitations of Windows 95,
  1964. Smallints must be used instead of Integers or Longints }
  1965. X := High(Smallint);
  1966. Y := High(Smallint);
  1967. end;
  1968. end;
  1969. end;
  1970. procedure TTBFloatingWindowParent.CMShowingChanged(var Message: TMessage);
  1971. const
  1972. ShowFlags: array[Boolean] of UINT = (
  1973. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW,
  1974. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  1975. begin
  1976. { Must override TCustomForm/TForm's CM_SHOWINGCHANGED handler so that the
  1977. form doesn't get activated when Visible is set to True. }
  1978. SetWindowPos(WindowHandle, 0, 0, 0, 0, 0, ShowFlags[Showing and FShouldShow]);
  1979. end;
  1980. procedure TTBFloatingWindowParent.CMDialogKey(var Message: TCMDialogKey);
  1981. begin
  1982. { If Escape if pressed on a floating toolbar, return focus to the form }
  1983. if (Message.CharCode = VK_ESCAPE) and (KeyDataToShiftState(Message.KeyData) = []) and
  1984. Assigned(ParentForm) then begin
  1985. ParentForm.SetFocus;
  1986. Message.Result := 1;
  1987. end
  1988. else
  1989. inherited;
  1990. end;
  1991. procedure TTBFloatingWindowParent.CMTextChanged(var Message: TMessage);
  1992. begin
  1993. inherited;
  1994. RedrawNCArea([twrdCaption]);
  1995. end;
  1996. function GetCaptionRect(const Control: TTBFloatingWindowParent;
  1997. const AdjustForBorder, MinusCloseButton: Boolean): TRect;
  1998. begin
  1999. Result := Rect(0, 0, Control.ClientWidth, GetSmallCaptionHeight-1);
  2000. if MinusCloseButton then
  2001. Dec(Result.Right, Result.Bottom);
  2002. if AdjustForBorder then
  2003. with Control.FDockableWindow.GetFloatingBorderSize do
  2004. OffsetRect(Result, X, Y);
  2005. end;
  2006. function GetCloseButtonRect(const Control: TTBFloatingWindowParent;
  2007. const AdjustForBorder: Boolean): TRect;
  2008. begin
  2009. Result := GetCaptionRect(Control, AdjustForBorder, False);
  2010. Result.Left := Result.Right - (GetSmallCaptionHeight-1);
  2011. end;
  2012. procedure TTBFloatingWindowParent.WMNCCalcSize(var Message: TWMNCCalcSize);
  2013. var
  2014. TL, BR: TPoint;
  2015. begin
  2016. { Doesn't call inherited since it overrides the normal NC sizes }
  2017. Message.Result := 0;
  2018. with Message.CalcSize_Params^ do begin
  2019. FDockableWindow.GetFloatingNCArea(TL, BR);
  2020. with rgrc[0] do begin
  2021. Inc(Left, TL.X);
  2022. Inc(Top, TL.Y);
  2023. Dec(Right, BR.X);
  2024. Dec(Bottom, BR.Y);
  2025. end;
  2026. end;
  2027. end;
  2028. procedure TTBFloatingWindowParent.WMNCPaint(var Message: TMessage);
  2029. begin
  2030. { Don't call inherited because it overrides the default NC painting }
  2031. DrawNCArea(False, 0, HRGN(Message.WParam), twrdAll);
  2032. end;
  2033. procedure FloatingWindowParentNCPaintProc(Wnd: HWND; DC: HDC; AppData: Longint);
  2034. begin
  2035. with TTBFloatingWindowParent(AppData) do
  2036. DrawNCArea(True, DC, 0, twrdAll);
  2037. end;
  2038. procedure TTBFloatingWindowParent.WMPrint(var Message: TMessage);
  2039. begin
  2040. HandleWMPrint(Handle, Message, FloatingWindowParentNCPaintProc, Longint(Self));
  2041. end;
  2042. procedure TTBFloatingWindowParent.WMPrintClient(var Message: TMessage);
  2043. begin
  2044. HandleWMPrintClient(Self, Message);
  2045. end;
  2046. procedure TTBFloatingWindowParent.WMNCHitTest(var Message: TWMNCHitTest);
  2047. var
  2048. P: TPoint;
  2049. R: TRect;
  2050. BorderSize: TPoint;
  2051. C: Integer;
  2052. begin
  2053. inherited;
  2054. with Message do begin
  2055. P := SmallPointToPoint(Pos);
  2056. GetWindowRect(Handle, R);
  2057. Dec(P.X, R.Left); Dec(P.Y, R.Top);
  2058. if Result <> HTCLIENT then begin
  2059. Result := HTNOWHERE;
  2060. if FDockableWindow.ShowCaption and PtInRect(GetCaptionRect(Self, True, False), P) then begin
  2061. if FDockableWindow.FCloseButton and PtInRect(GetCloseButtonRect(Self, True), P) then
  2062. Result := HT_TB2k_Close
  2063. else
  2064. Result := HT_TB2k_Caption;
  2065. end
  2066. else
  2067. if FDockableWindow.Resizable then begin
  2068. BorderSize := FDockableWindow.GetFloatingBorderSize;
  2069. if not(tbdsResizeEightCorner in FDockableWindow.FDockableWindowStyles) then begin
  2070. if (P.Y >= 0) and (P.Y < BorderSize.Y) then Result := HTTOP else
  2071. if (P.Y < Height) and (P.Y >= Height-BorderSize.Y-1) then Result := HTBOTTOM else
  2072. if (P.X >= 0) and (P.X < BorderSize.X) then Result := HTLEFT else
  2073. if (P.X < Width) and (P.X >= Width-BorderSize.X-1) then Result := HTRIGHT;
  2074. end
  2075. else begin
  2076. C := BorderSize.X + (GetSmallCaptionHeight-1);
  2077. if (P.X >= 0) and (P.X < BorderSize.X) then begin
  2078. Result := HTLEFT;
  2079. if (P.Y < C) then Result := HTTOPLEFT else
  2080. if (P.Y >= Height-C) then Result := HTBOTTOMLEFT;
  2081. end
  2082. else
  2083. if (P.X < Width) and (P.X >= Width-BorderSize.X-1) then begin
  2084. Result := HTRIGHT;
  2085. if (P.Y < C) then Result := HTTOPRIGHT else
  2086. if (P.Y >= Height-C) then Result := HTBOTTOMRIGHT;
  2087. end
  2088. else
  2089. if (P.Y >= 0) and (P.Y < BorderSize.Y) then begin
  2090. Result := HTTOP;
  2091. if (P.X < C) then Result := HTTOPLEFT else
  2092. if (P.X >= Width-C) then Result := HTTOPRIGHT;
  2093. end
  2094. else
  2095. if (P.Y < Height) and (P.Y >= Height-BorderSize.Y-1) then begin
  2096. Result := HTBOTTOM;
  2097. if (P.X < C) then Result := HTBOTTOMLEFT else
  2098. if (P.X >= Width-C) then Result := HTBOTTOMRIGHT;
  2099. end;
  2100. end;
  2101. end;
  2102. end;
  2103. end;
  2104. end;
  2105. procedure TTBFloatingWindowParent.SetCloseButtonState(Pushed: Boolean);
  2106. begin
  2107. if FCloseButtonDown <> Pushed then begin
  2108. FCloseButtonDown := Pushed;
  2109. RedrawNCArea([twrdCloseButton]);
  2110. end;
  2111. end;
  2112. procedure TTBFloatingWindowParent.WMNCLButtonDown(var Message: TWMNCLButtonDown);
  2113. var
  2114. P: TPoint;
  2115. R, BR: TRect;
  2116. begin
  2117. case Message.HitTest of
  2118. HT_TB2k_Caption: begin
  2119. P := FDockableWindow.ScreenToClient(Point(Message.XCursor, Message.YCursor));
  2120. FDockableWindow.BeginMoving(P.X, P.Y);
  2121. end;
  2122. HTLEFT..HTBOTTOMRIGHT:
  2123. if FDockableWindow.Resizable then
  2124. FDockableWindow.BeginSizing(TTBSizeHandle(Message.HitTest - HTLEFT));
  2125. HT_TB2k_Close: begin
  2126. GetWindowRect(Handle, R);
  2127. BR := GetCloseButtonRect(Self, True);
  2128. OffsetRect(BR, R.Left, R.Top);
  2129. if CloseButtonLoop(Handle, BR, SetCloseButtonState) then
  2130. FDockableWindow.Close;
  2131. end;
  2132. else
  2133. inherited;
  2134. end;
  2135. end;
  2136. procedure TTBFloatingWindowParent.WMNCLButtonDblClk(var Message: TWMNCLButtonDblClk);
  2137. begin
  2138. if Message.HitTest = HT_TB2k_Caption then
  2139. FDockableWindow.DoubleClick;
  2140. end;
  2141. procedure TTBFloatingWindowParent.WMNCRButtonUp(var Message: TWMNCRButtonUp);
  2142. begin
  2143. FDockableWindow.ShowNCContextMenu(TSmallPoint(TMessage(Message).LParam));
  2144. end;
  2145. procedure TTBFloatingWindowParent.WMClose(var Message: TWMClose);
  2146. var
  2147. MDIParentForm: TTBCustomForm;
  2148. begin
  2149. { A floating toolbar does not use WM_CLOSE messages when its close button
  2150. is clicked, but Windows still sends a WM_CLOSE message if the user
  2151. presses Alt+F4 while one of the toolbar's controls is focused. Inherited
  2152. is not called since we do not want Windows' default processing - which
  2153. destroys the window. Instead, relay the message to the parent form. }
  2154. MDIParentForm := GetMDIParent(TBGetToolWindowParentForm(FDockableWindow));
  2155. if Assigned(MDIParentForm) and MDIParentForm.HandleAllocated then
  2156. SendMessage(MDIParentForm.Handle, WM_CLOSE, 0, 0);
  2157. { Note to self: MDIParentForm is used instead of OwnerForm since MDI
  2158. childs don't process Alt+F4 as Close }
  2159. end;
  2160. procedure TTBFloatingWindowParent.WMActivate(var Message: TWMActivate);
  2161. var
  2162. ParentForm: TTBCustomForm;
  2163. begin
  2164. if csDesigning in ComponentState then begin
  2165. inherited;
  2166. Exit;
  2167. end;
  2168. ParentForm := GetMDIParent(TBGetToolWindowParentForm(FDockableWindow));
  2169. if Assigned(ParentForm) and ParentForm.HandleAllocated then
  2170. SendMessage(ParentForm.Handle, WM_NCACTIVATE, Ord(Message.Active <> WA_INACTIVE), 0);
  2171. if Message.Active <> WA_INACTIVE then begin
  2172. { This works around a "gotcha" in TCustomForm.CMShowingChanged. When a form
  2173. is hidden, it uses the internal VCL function FindTopMostWindow to
  2174. find a new active window. The problem is that handles of floating
  2175. toolbars on the form being hidden can be returned by
  2176. FindTopMostWindow, so the following code is used to prevent floating
  2177. toolbars on the hidden form from being left active. }
  2178. if not IsWindowVisible(Handle) then
  2179. { ^ Calling IsWindowVisible with a floating toolbar handle will
  2180. always return False if its parent form is hidden since the
  2181. WH_CALLWNDPROC hook automatically updates the toolbars'
  2182. visibility. }
  2183. { Find and activate a window besides this toolbar }
  2184. SetActiveWindow(FindTopLevelWindow(Handle))
  2185. else
  2186. { If the toolbar is being activated and the previous active window wasn't
  2187. its parent form, the form is activated instead. This is done so that if
  2188. the application is deactivated while a floating toolbar was active and
  2189. the application is reactivated again, it returns focus to the form. }
  2190. if Assigned(ParentForm) and ParentForm.HandleAllocated and
  2191. (Message.ActiveWindow <> ParentForm.Handle) then
  2192. SetActiveWindow(ParentForm.Handle);
  2193. end;
  2194. end;
  2195. procedure TTBFloatingWindowParent.WMMouseActivate(var Message: TWMMouseActivate);
  2196. var
  2197. ParentForm, MDIParentForm: TTBCustomForm;
  2198. begin
  2199. if csDesigning in ComponentState then begin
  2200. inherited;
  2201. Exit;
  2202. end;
  2203. { When floating, prevent the toolbar from activating when clicked.
  2204. This is so it doesn't take the focus away from the window that had it }
  2205. Message.Result := MA_NOACTIVATE;
  2206. { Similar to calling BringWindowToTop, but doesn't activate it }
  2207. SetWindowPos(Handle, HWND_TOP, 0, 0, 0, 0,
  2208. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  2209. { Since it is returning MA_NOACTIVATE, activate the form instead. }
  2210. ParentForm := TBGetToolWindowParentForm(FDockableWindow);
  2211. MDIParentForm := GetMDIParent(ParentForm);
  2212. if (FDockableWindow.FFloatingMode = fmOnTopOfParentForm) and
  2213. FDockableWindow.FActivateParent and
  2214. Assigned(MDIParentForm) and (GetActiveWindow <> Handle) then begin
  2215. { ^ Note to self: The GetActiveWindow check must be in there so that
  2216. double-clicks work properly on controls like Edits }
  2217. if MDIParentForm.HandleAllocated then
  2218. SetActiveWindow(MDIParentForm.Handle);
  2219. if (MDIParentForm <> ParentForm) and { if it's an MDI child form }
  2220. ParentForm.HandleAllocated then
  2221. BringWindowToTop(ParentForm.Handle);
  2222. end;
  2223. end;
  2224. procedure TTBFloatingWindowParent.WMMove(var Message: TWMMove);
  2225. begin
  2226. inherited;
  2227. FDockableWindow.Moved;
  2228. end;
  2229. procedure TTBFloatingWindowParent.DrawNCArea(const DrawToDC: Boolean;
  2230. const ADC: HDC; const Clip: HRGN; RedrawWhat: TTBToolWindowNCRedrawWhat);
  2231. { Redraws all the non-client area (the border, title bar, and close button) of
  2232. the toolbar when it is floating. }
  2233. const
  2234. COLOR_GRADIENTACTIVECAPTION = 27;
  2235. COLOR_GRADIENTINACTIVECAPTION = 28;
  2236. CaptionBkColors: array[Boolean, Boolean] of Integer =
  2237. ((COLOR_ACTIVECAPTION, COLOR_INACTIVECAPTION),
  2238. (COLOR_GRADIENTACTIVECAPTION, COLOR_GRADIENTINACTIVECAPTION));
  2239. CaptionTextColors: array[Boolean] of Integer =
  2240. (COLOR_CAPTIONTEXT, COLOR_INACTIVECAPTIONTEXT);
  2241. function GradientCaptionsEnabled: Boolean;
  2242. const
  2243. SPI_GETGRADIENTCAPTIONS = $1008; { Win98/NT5 only }
  2244. var
  2245. S: BOOL;
  2246. begin
  2247. Result := SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, @S, 0) and S;
  2248. end;
  2249. const
  2250. CloseButtonState: array[Boolean] of UINT = (0, DFCS_PUSHED);
  2251. ActiveCaptionFlags: array[Boolean] of UINT = (DC_ACTIVE, 0);
  2252. DC_GRADIENT = $20;
  2253. GradientCaptionFlags: array[Boolean] of UINT = (0, DC_GRADIENT);
  2254. var
  2255. DC: HDC;
  2256. R, R2: TRect;
  2257. Gradient: Boolean;
  2258. SavePen: HPEN;
  2259. SaveIndex: Integer;
  2260. S: TPoint;
  2261. begin
  2262. if not HandleAllocated then Exit;
  2263. if not DrawToDC then
  2264. DC := GetWindowDC(Handle)
  2265. else
  2266. DC := ADC;
  2267. try
  2268. { Use update region }
  2269. if not DrawToDC then
  2270. SelectNCUpdateRgn(Handle, DC, Clip);
  2271. { Work around an apparent NT 4.0 & 2000 bug. If the width of the DC is
  2272. greater than the width of the screen, then any call to ExcludeClipRect
  2273. inexplicably shrinks the clipping rectangle to the screen width. I've
  2274. found that calling IntersectClipRect as done below magically fixes the
  2275. problem (but I'm not sure why). }
  2276. GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top);
  2277. IntersectClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);
  2278. Gradient := GradientCaptionsEnabled;
  2279. { Border }
  2280. if twrdBorder in RedrawWhat then begin
  2281. { This works around WM_NCPAINT problem described at top of source code }
  2282. {no! R := Rect(0, 0, Width, Height);}
  2283. GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top);
  2284. DrawEdge(DC, R, EDGE_RAISED, BF_RECT);
  2285. SaveIndex := SaveDC(DC);
  2286. S := FDockableWindow.GetFloatingBorderSize;
  2287. with R do
  2288. ExcludeClipRect(DC, Left + S.X, Top + S.Y, Right - S.X, Bottom - S.Y);
  2289. InflateRect(R, -2, -2);
  2290. FillRect(DC, R, GetSysColorBrush(COLOR_BTNFACE));
  2291. RestoreDC(DC, SaveIndex);
  2292. end;
  2293. if FDockableWindow.ShowCaption then begin
  2294. if (twrdCaption in RedrawWhat) and FDockableWindow.FCloseButton and
  2295. (twrdCloseButton in RedrawWhat) then
  2296. SaveIndex := SaveDC(DC)
  2297. else
  2298. SaveIndex := 0;
  2299. try
  2300. if SaveIndex <> 0 then
  2301. with GetCloseButtonRect(Self, True) do
  2302. { Reduces flicker }
  2303. ExcludeClipRect(DC, Left, Top, Right, Bottom);
  2304. { Caption }
  2305. if twrdCaption in RedrawWhat then begin
  2306. R := GetCaptionRect(Self, True, FDockableWindow.FCloseButton);
  2307. { Note that Delphi's Win32 help for DrawCaption is totally wrong!
  2308. I got updated info from www.microsoft.com/msdn/sdk/ }
  2309. DrawCaption(Handle, DC, R, DC_TEXT or DC_SMALLCAP or
  2310. ActiveCaptionFlags[FDockableWindow.FInactiveCaption] or
  2311. GradientCaptionFlags[Gradient]);
  2312. { Line below caption }
  2313. R := GetCaptionRect(Self, True, False);
  2314. SavePen := SelectObject(DC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE)));
  2315. MoveToEx(DC, R.Left, R.Bottom, nil);
  2316. LineTo(DC, R.Right, R.Bottom);
  2317. DeleteObject(SelectObject(DC, SavePen));
  2318. end;
  2319. finally
  2320. if SaveIndex <> 0 then
  2321. RestoreDC(DC, SaveIndex);
  2322. end;
  2323. { Close button }
  2324. if FDockableWindow.FCloseButton then begin
  2325. R := GetCloseButtonRect(Self, True);
  2326. R2 := R;
  2327. InflateRect(R2, 0, -2);
  2328. Dec(R2.Right, 2);
  2329. if twrdCaption in RedrawWhat then begin
  2330. SaveIndex := SaveDC(DC);
  2331. ExcludeClipRect(DC, R2.Left, R2.Top, R2.Right, R2.Bottom);
  2332. FillRect(DC, R, GetSysColorBrush(CaptionBkColors[Gradient,
  2333. FDockableWindow.FInactiveCaption]));
  2334. RestoreDC(DC, SaveIndex);
  2335. end;
  2336. if twrdCloseButton in RedrawWhat then
  2337. DrawFrameControl(DC, R2, DFC_CAPTION, DFCS_CAPTIONCLOSE or
  2338. CloseButtonState[FCloseButtonDown]);
  2339. end;
  2340. end;
  2341. finally
  2342. if not DrawToDC then
  2343. ReleaseDC(Handle, DC);
  2344. end;
  2345. end;
  2346. procedure TTBFloatingWindowParent.RedrawNCArea(const RedrawWhat: TTBToolWindowNCRedrawWhat);
  2347. begin
  2348. { Note: IsWindowVisible is called as an optimization. There's no need to
  2349. draw on invisible windows. }
  2350. if HandleAllocated and IsWindowVisible(Handle) then
  2351. DrawNCArea(False, 0, 0, RedrawWhat);
  2352. end;
  2353. { TTBCustomDockableWindow }
  2354. constructor TTBCustomDockableWindow.Create(AOwner: TComponent);
  2355. begin
  2356. inherited;
  2357. ControlStyle := ControlStyle +
  2358. [csAcceptsControls, csClickEvents, csDoubleClicks, csSetCaption] -
  2359. [csCaptureMouse{capturing is done manually}, csOpaque];
  2360. FAutoResize := True;
  2361. FActivateParent := True;
  2362. FBorderStyle := bsSingle;
  2363. FCloseButton := True;
  2364. FDblClickUndock := True;
  2365. FDockableTo := [dpTop, dpBottom, dpLeft, dpRight];
  2366. FDockableWindowStyles := [tbdsResizeEightCorner, tbdsResizeClipCursor];
  2367. FDockPos := -1;
  2368. FDragHandleStyle := dhSingle;
  2369. FEffectiveDockRow := -1;
  2370. FHideWhenInactive := True;
  2371. FResizable := True;
  2372. FShowCaption := True;
  2373. FSmoothDrag := True;
  2374. FUseLastDock := True;
  2375. Color := clBtnFace;
  2376. if not(csDesigning in ComponentState) then
  2377. InstallHookProc(Self, ToolbarHookProc, [hpSendActivate, hpSendActivateApp,
  2378. hpSendWindowPosChanged, hpPreDestroy]);
  2379. end;
  2380. destructor TTBCustomDockableWindow.Destroy;
  2381. begin
  2382. inherited;
  2383. FDockForms.Free; { must be done after 'inherited' because Notification accesses FDockForms }
  2384. FFloatParent.Free;
  2385. UninstallHookProc(Self, ToolbarHookProc);
  2386. end;
  2387. function TTBCustomDockableWindow.HasParent: Boolean;
  2388. begin
  2389. if Parent is TTBFloatingWindowParent then
  2390. Result := False
  2391. else
  2392. Result := inherited HasParent;
  2393. end;
  2394. function TTBCustomDockableWindow.GetParentComponent: TComponent;
  2395. begin
  2396. if Parent is TTBFloatingWindowParent then
  2397. Result := nil
  2398. else
  2399. Result := inherited GetParentComponent;
  2400. end;
  2401. procedure TTBCustomDockableWindow.Moved;
  2402. begin
  2403. if not(csLoading in ComponentState) and Assigned(FOnMove) and (FDisableOnMove <= 0) then
  2404. FOnMove(Self);
  2405. end;
  2406. procedure TTBCustomDockableWindow.WMMove(var Message: TWMMove);
  2407. procedure Redraw;
  2408. { Redraws the control using an off-screen bitmap to avoid flicker }
  2409. var
  2410. CR, R: TRect;
  2411. W: HWND;
  2412. DC, BmpDC: HDC;
  2413. Bmp: HBITMAP;
  2414. begin
  2415. if not HandleAllocated then Exit;
  2416. CR := ClientRect;
  2417. W := Handle;
  2418. if GetUpdateRect(W, R, False) and EqualRect(R, CR) then begin
  2419. { The client area is already completely invalid, so don't bother using
  2420. an off-screen bitmap }
  2421. InvalidateAll(Self);
  2422. Exit;
  2423. end;
  2424. BmpDC := 0;
  2425. Bmp := 0;
  2426. DC := GetDC(W);
  2427. try
  2428. BmpDC := CreateCompatibleDC(DC);
  2429. Bmp := CreateCompatibleBitmap(DC, CR.Right, CR.Bottom);
  2430. SelectObject(BmpDC, Bmp);
  2431. SendMessage(W, WM_NCPAINT, 0, 0);
  2432. SendMessage(W, WM_ERASEBKGND, WPARAM(BmpDC), 0);
  2433. SendMessage(W, WM_PAINT, WPARAM(BmpDC), 0);
  2434. BitBlt(DC, 0, 0, CR.Right, CR.Bottom, BmpDC, 0, 0, SRCCOPY);
  2435. finally
  2436. if BmpDC <> 0 then DeleteDC(BmpDC);
  2437. if Bmp <> 0 then DeleteObject(Bmp);
  2438. ReleaseDC(W, DC);
  2439. end;
  2440. ValidateRect(W, nil);
  2441. end;
  2442. begin
  2443. inherited;
  2444. FMoved := True;
  2445. if Docked and CurrentDock.UsingBackground then begin
  2446. { Needs to redraw so that the background is lined up with the dock at the
  2447. new position. }
  2448. Redraw;
  2449. end;
  2450. Moved;
  2451. end;
  2452. {$IFNDEF JR_D4}
  2453. procedure TTBCustomDockableWindow.WMSize(var Message: TWMSize);
  2454. begin
  2455. inherited;
  2456. if not(csLoading in ComponentState) and Assigned(FOnResize) then
  2457. FOnResize(Self);
  2458. end;
  2459. {$ENDIF}
  2460. procedure TTBCustomDockableWindow.WMEnable(var Message: TWMEnable);
  2461. begin
  2462. inherited;
  2463. { When a modal dialog is displayed and the toolbar window gets disabled as
  2464. a result, remove its topmost flag. }
  2465. if FFloatingMode = fmOnTopOfAllForms then
  2466. UpdateTopmostFlag;
  2467. end;
  2468. procedure TTBCustomDockableWindow.UpdateCaptionState;
  2469. { Updates the caption active/inactive state of a floating tool window.
  2470. Called when the tool window is visible or is about to be shown. }
  2471. function IsPopupWindowActive: Boolean;
  2472. const
  2473. IID_ITBPopupWindow: TGUID = '{E45CBE74-1ECF-44CB-B064-6D45B1924708}';
  2474. var
  2475. Ctl: TWinControl;
  2476. begin
  2477. Ctl := FindControl(GetActiveWindow);
  2478. { Instead of using "is TTBPopupWindow", which would require linking to the
  2479. TB2Item unit, check if the control implements the ITBPopupWindow
  2480. interface. This will tell us if it's a TTBPopupWindow or descendant. }
  2481. Result := Assigned(Ctl) and Assigned(Ctl.GetInterfaceEntry(IID_ITBPopupWindow));
  2482. end;
  2483. function GetActiveFormWindow: HWND;
  2484. var
  2485. Ctl: TWinControl;
  2486. begin
  2487. Result := GetActiveWindow;
  2488. { If the active window is a TTBFloatingWindowParent (i.e. a control on a
  2489. floating toolbar is focused), return the parent form handle instead }
  2490. Ctl := FindControl(Result);
  2491. if Assigned(Ctl) and (Ctl is TTBFloatingWindowParent) then begin
  2492. Ctl := TTBFloatingWindowParent(Ctl).ParentForm;
  2493. if Assigned(Ctl) and Ctl.HandleAllocated then
  2494. Result := Ctl.Handle;
  2495. end;
  2496. end;
  2497. var
  2498. Inactive: Boolean;
  2499. ActiveWnd: HWND;
  2500. begin
  2501. { Update caption state if floating, but not if a control on a popup window
  2502. (e.g. a TTBEditItem) is currently focused; we don't want the captions on
  2503. all floating toolbars to turn gray in that case. (The caption state will
  2504. get updated when we're called the next time the active window changes,
  2505. i.e. when the user dismisses the popup window.) }
  2506. if (Parent is TTBFloatingWindowParent) and Parent.HandleAllocated and
  2507. not IsPopupWindowActive then begin
  2508. Inactive := False;
  2509. if not ApplicationIsActive then
  2510. Inactive := True
  2511. else if (FFloatingMode = fmOnTopOfParentForm) and
  2512. (HWND(GetWindowLong(Parent.Handle, GWL_HWNDPARENT)) <> Application.Handle) then begin
  2513. { Use inactive caption if the active window doesn't own the float parent
  2514. (directly or indirectly). Note: For compatibility with browser-embedded
  2515. TActiveForms, we use IsAncestorOfWindow instead of checking
  2516. TBGetToolWindowParentForm. }
  2517. ActiveWnd := GetActiveFormWindow;
  2518. if (ActiveWnd = 0) or not IsAncestorOfWindow(ActiveWnd, Parent.Handle) then
  2519. Inactive := True;
  2520. end;
  2521. if FInactiveCaption <> Inactive then begin
  2522. FInactiveCaption := Inactive;
  2523. TTBFloatingWindowParent(Parent).RedrawNCArea(twrdAll);
  2524. end;
  2525. end;
  2526. end;
  2527. function TTBCustomDockableWindow.GetShowingState: Boolean;
  2528. function IsWindowVisibleAndNotMinimized(Wnd: HWND): Boolean;
  2529. begin
  2530. Result := IsWindowVisible(Wnd);
  2531. if Result then begin
  2532. { Wnd may not be a top-level window (e.g. in the case of an MDI child
  2533. form, or an ActiveForm embedded in a web page), so go up the chain of
  2534. parent windows and see if any of them are minimized }
  2535. repeat
  2536. if IsIconic(Wnd) then begin
  2537. Result := False;
  2538. Break;
  2539. end;
  2540. { Stop if we're at a top-level window (no need to check owner windows) }
  2541. if GetWindowLong(Wnd, GWL_STYLE) and WS_CHILD = 0 then
  2542. Break;
  2543. Wnd := GetParent(Wnd);
  2544. until Wnd = 0;
  2545. end;
  2546. end;
  2547. var
  2548. HideFloatingToolbars: Boolean;
  2549. ParentForm: TTBCustomForm;
  2550. begin
  2551. Result := Showing and (FHidden = 0);
  2552. if Floating and not(csDesigning in ComponentState) then begin
  2553. HideFloatingToolbars := FFloatingMode = fmOnTopOfParentForm;
  2554. if HideFloatingToolbars then begin
  2555. ParentForm := TBGetToolWindowParentForm(Self);
  2556. if Assigned(ParentForm) and ParentForm.HandleAllocated and
  2557. IsWindowVisibleAndNotMinimized(ParentForm.Handle) then
  2558. HideFloatingToolbars := False;
  2559. end;
  2560. Result := Result and not (HideFloatingToolbars or (FHideWhenInactive and not ApplicationIsActive));
  2561. end;
  2562. end;
  2563. procedure TTBCustomDockableWindow.UpdateVisibility;
  2564. { Updates the visibility of the tool window, and additionally the caption
  2565. state if floating and showing }
  2566. var
  2567. IsVisible: Boolean;
  2568. begin
  2569. if HandleAllocated then begin
  2570. IsVisible := IsWindowVisible(Handle);
  2571. if IsVisible <> GetShowingState then begin
  2572. Perform(CM_SHOWINGCHANGED, 0, 0);
  2573. { Note: CMShowingChanged will call UpdateCaptionState automatically
  2574. when floating and showing }
  2575. end
  2576. else if IsVisible and Floating then begin
  2577. { If we're floating and we didn't send the CM_SHOWINGCHANGED message
  2578. then we have to call UpdateCaptionState manually }
  2579. UpdateCaptionState;
  2580. end;
  2581. end;
  2582. end;
  2583. function IsTopmost(const Wnd: HWND): Boolean;
  2584. begin
  2585. Result := GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0;
  2586. end;
  2587. procedure TTBCustomDockableWindow.UpdateTopmostFlag;
  2588. const
  2589. Wnds: array[Boolean] of HWND = (HWND_NOTOPMOST, HWND_TOPMOST);
  2590. var
  2591. ShouldBeTopmost: Boolean;
  2592. begin
  2593. if HandleAllocated then begin
  2594. if FFloatingMode = fmOnTopOfAllForms then
  2595. ShouldBeTopmost := IsWindowEnabled(Handle)
  2596. else
  2597. ShouldBeTopmost := IsTopmost(HWND(GetWindowLong(Parent.Handle, GWL_HWNDPARENT)));
  2598. if ShouldBeTopmost <> IsTopmost(Parent.Handle) then
  2599. { ^ it must check if it already was topmost or non-topmost or else
  2600. it causes problems on Win95/98 for some reason }
  2601. SetWindowPos(Parent.Handle, Wnds[ShouldBeTopmost], 0, 0, 0, 0,
  2602. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  2603. end;
  2604. end;
  2605. procedure TTBCustomDockableWindow.CMShowingChanged(var Message: TMessage);
  2606. function GetPrevWnd(W: HWND): HWND;
  2607. var
  2608. WasTopmost, Done: Boolean;
  2609. ParentWnd: HWND;
  2610. begin
  2611. WasTopmost := IsTopmost(Parent.Handle);
  2612. Result := W;
  2613. repeat
  2614. Done := True;
  2615. Result := GetWindow(Result, GW_HWNDPREV);
  2616. ParentWnd := Result;
  2617. while ParentWnd <> 0 do begin
  2618. if WasTopmost and not IsTopmost(ParentWnd) then begin
  2619. Done := False;
  2620. Break;
  2621. end;
  2622. ParentWnd := HWND(GetWindowLong(ParentWnd, GWL_HWNDPARENT));
  2623. if ParentWnd = W then begin
  2624. Done := False;
  2625. Break;
  2626. end;
  2627. end;
  2628. until Done;
  2629. end;
  2630. const
  2631. ShowFlags: array[Boolean] of UINT = (
  2632. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW,
  2633. SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  2634. var
  2635. Show: Boolean;
  2636. Form: TTBCustomForm;
  2637. begin
  2638. { inherited isn't called since TTBCustomDockableWindow handles CM_SHOWINGCHANGED
  2639. itself. For reference, the original TWinControl implementation is:
  2640. const
  2641. ShowFlags: array[Boolean] of Word = (
  2642. SWP_NOSIZE + SWP_NOMOVE + SWP_NOZORDER + SWP_NOACTIVATE + SWP_HIDEWINDOW,
  2643. SWP_NOSIZE + SWP_NOMOVE + SWP_NOZORDER + SWP_NOACTIVATE + SWP_SHOWWINDOW);
  2644. begin
  2645. SetWindowPos(FHandle, 0, 0, 0, 0, 0, ShowFlags[FShowing]);
  2646. end;
  2647. }
  2648. if HandleAllocated then begin
  2649. Show := GetShowingState;
  2650. if Parent is TTBFloatingWindowParent then begin
  2651. if Show then begin
  2652. { If the toolbar is floating, set its "owner window" to the parent form
  2653. so that the toolbar window always stays on top of the form }
  2654. if FFloatingMode = fmOnTopOfParentForm then begin
  2655. Form := GetMDIParent(TBGetToolWindowParentForm(Self));
  2656. if Assigned(Form) and Form.HandleAllocated and
  2657. (HWND(GetWindowLong(Parent.Handle, GWL_HWNDPARENT)) <> Form.Handle) then begin
  2658. SetWindowLong(Parent.Handle, GWL_HWNDPARENT, Longint(Form.Handle));
  2659. { Following is necessarily to make it immediately realize the
  2660. GWL_HWNDPARENT change }
  2661. SetWindowPos(Parent.Handle, GetPrevWnd(Form.Handle), 0, 0, 0, 0, SWP_NOACTIVATE or
  2662. SWP_NOMOVE or SWP_NOSIZE);
  2663. end;
  2664. end
  2665. else begin
  2666. SetWindowLong(Parent.Handle, GWL_HWNDPARENT, Longint(Application.Handle));
  2667. end;
  2668. { Initialize caption state after setting owner but before showing }
  2669. UpdateCaptionState;
  2670. end;
  2671. UpdateTopmostFlag;
  2672. { Show/hide the TTBFloatingWindowParent. The following lines had to be
  2673. added to fix a problem that was in 1.65d/e. In 1.65d/e, it always
  2674. kept TTBFloatingWindowParent visible (this change was made to improve
  2675. compatibility with D4's Actions), but this for some odd reason would
  2676. cause a Stack Overflow error if the program's main form was closed
  2677. while a floating toolwindow was focused. (This problem did not occur
  2678. on NT.) }
  2679. TTBFloatingWindowParent(Parent).FShouldShow := Show;
  2680. Parent.Perform(CM_SHOWINGCHANGED, 0, 0);
  2681. end;
  2682. SetWindowPos(Handle, 0, 0, 0, 0, 0, ShowFlags[Show]);
  2683. if not Show and (GetActiveWindow = Handle) then
  2684. { If the window is hidden but is still active, find and activate a
  2685. different window }
  2686. SetActiveWindow(FindTopLevelWindow(Handle));
  2687. end;
  2688. end;
  2689. procedure TTBCustomDockableWindow.CreateParams(var Params: TCreateParams);
  2690. begin
  2691. inherited;
  2692. { Disable complete redraws when size changes. CS_H/VREDRAW cause flicker
  2693. and are not necessary for this control at run time }
  2694. if not(csDesigning in ComponentState) then
  2695. with Params.WindowClass do
  2696. Style := Style and not(CS_HREDRAW or CS_VREDRAW);
  2697. end;
  2698. procedure TTBCustomDockableWindow.Notification(AComponent: TComponent; Operation: TOperation);
  2699. begin
  2700. inherited;
  2701. if Operation = opRemove then begin
  2702. if AComponent = FDefaultDock then
  2703. FDefaultDock := nil
  2704. else
  2705. if AComponent = FLastDock then
  2706. FLastDock := nil
  2707. else begin
  2708. RemoveFromList(FDockForms, AComponent);
  2709. if Assigned(FFloatParent) and (csDestroying in FFloatParent.ComponentState) and
  2710. (AComponent = FFloatParent.FParentForm) then begin
  2711. { ^ Note: Must check csDestroying so that we are sure that FFloatParent
  2712. is actually being destroyed and not just being removed from its
  2713. Owner's component list }
  2714. if Parent = FFloatParent then begin
  2715. if FFloatingMode = fmOnTopOfParentForm then
  2716. Parent := nil
  2717. else
  2718. FFloatParent.FParentForm := nil;
  2719. end
  2720. else begin
  2721. FFloatParent.Free;
  2722. FFloatParent := nil;
  2723. end;
  2724. end;
  2725. end;
  2726. end;
  2727. end;
  2728. procedure TTBCustomDockableWindow.MoveOnScreen(const OnlyIfFullyOffscreen: Boolean);
  2729. { Moves the (floating) toolbar so that it is fully (or at least mostly) in
  2730. view on the screen }
  2731. var
  2732. R, S, Test: TRect;
  2733. begin
  2734. if Floating then begin
  2735. R := Parent.BoundsRect;
  2736. S := GetRectOfMonitorContainingRect(R, True);
  2737. if OnlyIfFullyOffscreen and IntersectRect(Test, R, S) then
  2738. Exit;
  2739. if R.Right > S.Right then
  2740. OffsetRect(R, S.Right - R.Right, 0);
  2741. if R.Bottom > S.Bottom then
  2742. OffsetRect(R, 0, S.Bottom - R.Bottom);
  2743. if R.Left < S.Left then
  2744. OffsetRect(R, S.Left - R.Left, 0);
  2745. if R.Top < S.Top then
  2746. OffsetRect(R, 0, S.Top - R.Top);
  2747. Parent.BoundsRect := R;
  2748. end;
  2749. end;
  2750. procedure TTBCustomDockableWindow.ReadPositionData(const Data: TTBReadPositionData);
  2751. begin
  2752. end;
  2753. procedure TTBCustomDockableWindow.DoneReadingPositionData(const Data: TTBReadPositionData);
  2754. begin
  2755. end;
  2756. procedure TTBCustomDockableWindow.WritePositionData(const Data: TTBWritePositionData);
  2757. begin
  2758. end;
  2759. procedure TTBCustomDockableWindow.InitializeOrdering;
  2760. begin
  2761. end;
  2762. procedure TTBCustomDockableWindow.SizeChanging(const AWidth, AHeight: Integer);
  2763. begin
  2764. end;
  2765. procedure TTBCustomDockableWindow.ReadSavedAtRunTime(Reader: TReader);
  2766. begin
  2767. FSavedAtRunTime := Reader.ReadBoolean;
  2768. end;
  2769. procedure TTBCustomDockableWindow.WriteSavedAtRunTime(Writer: TWriter);
  2770. begin
  2771. { WriteSavedAtRunTime only called when not(csDesigning in ComponentState) }
  2772. Writer.WriteBoolean(True);
  2773. end;
  2774. procedure TTBCustomDockableWindow.DefineProperties(Filer: TFiler);
  2775. begin
  2776. inherited;
  2777. Filer.DefineProperty('SavedAtRunTime', ReadSavedAtRunTime,
  2778. WriteSavedAtRunTime, not(csDesigning in ComponentState));
  2779. end;
  2780. procedure TTBCustomDockableWindow.Loaded;
  2781. var
  2782. R: TRect;
  2783. begin
  2784. inherited;
  2785. { Adjust coordinates if it was initially floating }
  2786. if not FSavedAtRunTime and not(csDesigning in ComponentState) and
  2787. (Parent is TTBFloatingWindowParent) then begin
  2788. R := BoundsRect;
  2789. MapWindowPoints(TBValidToolWindowParentForm(Self).Handle, 0, R, 2);
  2790. BoundsRect := R;
  2791. MoveOnScreen(False);
  2792. end;
  2793. InitializeOrdering;
  2794. { Arranging is disabled while component was loading, so arrange now }
  2795. Arrange;
  2796. end;
  2797. procedure TTBCustomDockableWindow.BeginUpdate;
  2798. begin
  2799. Inc(FDisableArrange);
  2800. end;
  2801. procedure TTBCustomDockableWindow.EndUpdate;
  2802. begin
  2803. Dec(FDisableArrange);
  2804. if FArrangeNeeded and (FDisableArrange = 0) then
  2805. Arrange;
  2806. end;
  2807. procedure TTBCustomDockableWindow.AddDockForm(const Form: TTBCustomForm);
  2808. begin
  2809. if Form = nil then Exit;
  2810. if AddToList(FDockForms, Form) then
  2811. Form.FreeNotification(Self);
  2812. end;
  2813. procedure TTBCustomDockableWindow.RemoveDockForm(const Form: TTBCustomForm);
  2814. begin
  2815. RemoveFromList(FDockForms, Form);
  2816. end;
  2817. function TTBCustomDockableWindow.CanDockTo(ADock: TTBDock): Boolean;
  2818. begin
  2819. Result := ADock.Position in DockableTo;
  2820. end;
  2821. function TTBCustomDockableWindow.IsAutoResized: Boolean;
  2822. begin
  2823. Result := AutoResize or Assigned(CurrentDock) or Floating;
  2824. end;
  2825. procedure TTBCustomDockableWindow.ChangeSize(AWidth, AHeight: Integer);
  2826. var
  2827. S: TPoint;
  2828. begin
  2829. if Docked then
  2830. CurrentDock.ArrangeToolbars
  2831. else begin
  2832. S := CalcNCSizes;
  2833. Inc(AWidth, S.X);
  2834. Inc(AHeight, S.Y);
  2835. { Leave the width and/or height alone if the control is Anchored
  2836. (or Aligned) }
  2837. if not Floating then begin
  2838. if (akLeft in Anchors) and (akRight in Anchors) then
  2839. AWidth := Width;
  2840. if (akTop in Anchors) and (akBottom in Anchors) then
  2841. AHeight := Height;
  2842. end;
  2843. Inc(FUpdatingBounds);
  2844. try
  2845. SetBounds(Left, Top, AWidth, AHeight);
  2846. finally
  2847. Dec(FUpdatingBounds);
  2848. end;
  2849. end;
  2850. end;
  2851. procedure TTBCustomDockableWindow.Arrange;
  2852. var
  2853. Size: TPoint;
  2854. begin
  2855. if (FDisableArrange > 0) or
  2856. { Prevent flicker while loading }
  2857. (csLoading in ComponentState) or
  2858. { Don't call DoArrangeControls when Parent is nil. The VCL sets Parent to
  2859. 'nil' during destruction of a component; we can't have an OrderControls
  2860. call after a descendant control has freed its data. }
  2861. (Parent = nil) then begin
  2862. FArrangeNeeded := True;
  2863. Exit;
  2864. end;
  2865. FArrangeNeeded := False;
  2866. Size := DoArrange(True, TBGetDockTypeOf(CurrentDock, Floating), Floating,
  2867. CurrentDock);
  2868. if IsAutoResized then
  2869. ChangeSize(Size.X, Size.Y);
  2870. end;
  2871. procedure TTBCustomDockableWindow.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  2872. begin
  2873. if not(csDesigning in ComponentState) and Floating then begin
  2874. { Force Top & Left to 0 if floating }
  2875. ALeft := 0;
  2876. ATop := 0;
  2877. if Parent is TTBFloatingWindowParent then
  2878. with Parent do
  2879. SetBounds(Left, Top, (Width-ClientWidth) + AWidth,
  2880. (Height-ClientHeight) + AHeight);
  2881. end;
  2882. if (FUpdatingBounds = 0) and ((AWidth <> Width) or (AHeight <> Height)) then
  2883. SizeChanging(AWidth, AHeight);
  2884. { This allows you to drag the toolbar around the dock at design time }
  2885. if (csDesigning in ComponentState) and not(csLoading in ComponentState) and
  2886. Docked and (FUpdatingBounds = 0) and ((ALeft <> Left) or (ATop <> Top)) then begin
  2887. if not(CurrentDock.Position in PositionLeftOrRight) then begin
  2888. FDockRow := CurrentDock.GetDesignModeRowOf(ATop+(Height div 2));
  2889. FDockPos := ALeft;
  2890. end
  2891. else begin
  2892. FDockRow := CurrentDock.GetDesignModeRowOf(ALeft+(Width div 2));
  2893. FDockPos := ATop;
  2894. end;
  2895. inherited SetBounds(Left, Top, AWidth, AHeight); { only pass any size changes }
  2896. CurrentDock.ArrangeToolbars; { let ArrangeToolbars take care of position changes }
  2897. end
  2898. else begin
  2899. inherited;
  2900. {if not(csLoading in ComponentState) and Floating and (FUpdatingBounds = 0) then
  2901. FFloatingPosition := BoundsRect.TopLeft;}
  2902. end;
  2903. end;
  2904. procedure TTBCustomDockableWindow.SetParent(AParent: TWinControl);
  2905. procedure UpdateFloatingToolWindows;
  2906. begin
  2907. if Parent is TTBFloatingWindowParent then begin
  2908. AddToList(FloatingToolWindows, Self);
  2909. Parent.SetBounds(FFloatingPosition.X, FFloatingPosition.Y,
  2910. Parent.Width, Parent.Height);
  2911. end
  2912. else
  2913. RemoveFromList(FloatingToolWindows, Self);
  2914. end;
  2915. function ParentToCurrentDock(const Ctl: TWinControl): TTBDock;
  2916. begin
  2917. if Ctl is TTBDock then
  2918. Result := TTBDock(Ctl)
  2919. else
  2920. Result := nil;
  2921. end;
  2922. var
  2923. OldCurrentDock, NewCurrentDock: TTBDock;
  2924. NewFloating: Boolean;
  2925. OldParent: TWinControl;
  2926. SaveHandle: HWND;
  2927. begin
  2928. OldCurrentDock := ParentToCurrentDock(Parent);
  2929. NewCurrentDock := ParentToCurrentDock(AParent);
  2930. NewFloating := AParent is TTBFloatingWindowParent;
  2931. if AParent = Parent then begin
  2932. { Even though AParent is the same as the current Parent, this code is
  2933. necessary because when the VCL destroys the parent of the tool window,
  2934. it calls TWinControl.Remove to set FParent instead of using SetParent.
  2935. However TControl.Destroy does call SetParent(nil), so it is
  2936. eventually notified of the change before it is destroyed. }
  2937. FCurrentDock := NewCurrentDock;
  2938. FFloating := NewFloating;
  2939. FDocked := Assigned(FCurrentDock);
  2940. UpdateFloatingToolWindows;
  2941. end
  2942. else begin
  2943. if not(csDestroying in ComponentState) and Assigned(AParent) then begin
  2944. if Assigned(FOnDockChanging) then
  2945. FOnDockChanging(Self, NewFloating, NewCurrentDock);
  2946. if Assigned(FOnRecreating) then
  2947. FOnRecreating(Self);
  2948. end;
  2949. { Before changing between docked and floating state (and vice-versa)
  2950. or between docks, increment FHidden and call UpdateVisibility to hide the
  2951. toolbar. This prevents any flashing while it's being moved }
  2952. Inc(FHidden);
  2953. Inc(FDisableOnMove);
  2954. try
  2955. UpdateVisibility;
  2956. if Assigned(OldCurrentDock) then
  2957. OldCurrentDock.BeginUpdate;
  2958. if Assigned(NewCurrentDock) then
  2959. NewCurrentDock.BeginUpdate;
  2960. Inc(FUpdatingBounds);
  2961. try
  2962. if Assigned(AParent) then
  2963. DoDockChangingHidden(NewFloating, NewCurrentDock);
  2964. BeginUpdate;
  2965. try
  2966. { FCurrentSize probably won't be valid after changing Parents, so
  2967. reset it to zero }
  2968. FCurrentSize := 0;
  2969. if Parent is TTBDock then begin
  2970. if not FUseLastDock or (FLastDock <> Parent) then
  2971. TTBDock(Parent).ChangeDockList(False, Self);
  2972. TTBDock(Parent).ToolbarVisibilityChanged(Self, True);
  2973. end;
  2974. OldParent := Parent;
  2975. SaveHandle := 0;
  2976. if Assigned(AParent) then begin
  2977. //AParent.HandleNeeded;
  2978. SaveHandle := WindowHandle;
  2979. WindowHandle := 0;
  2980. end;
  2981. { Ensure that the handle is destroyed now so that any messages in the queue
  2982. get flushed. This is neccessary since existing messages may reference
  2983. FDockedTo or FDocked, which is changed below. }
  2984. inherited SetParent(nil);
  2985. { ^ Note to self: SetParent is used instead of DestroyHandle because it does
  2986. additional processing }
  2987. FCurrentDock := NewCurrentDock;
  2988. FFloating := NewFloating;
  2989. FDocked := Assigned(FCurrentDock);
  2990. try
  2991. if SaveHandle <> 0 then begin
  2992. WindowHandle := SaveHandle;
  2993. Windows.SetParent(SaveHandle, AParent.Handle);
  2994. SetWindowPos(SaveHandle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or
  2995. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
  2996. end;
  2997. inherited;
  2998. except
  2999. { Failure is rare, but just in case, restore FDockedTo and FDocked back. }
  3000. FCurrentDock := ParentToCurrentDock(Parent);
  3001. FFloating := Parent is TTBFloatingWindowParent;
  3002. FDocked := Assigned(FCurrentDock);
  3003. raise;
  3004. end;
  3005. { FEffectiveDockRow probably won't be valid on the new Parent, so
  3006. reset it to -1 so that GetMinRowSize will temporarily ignore this
  3007. toolbar }
  3008. FEffectiveDockRow := -1;
  3009. if not FSmoothDragging and (OldParent is TTBFloatingWindowParent) then begin
  3010. if FFloatParent = OldParent then FFloatParent := nil;
  3011. OldParent.Free;
  3012. end;
  3013. if Parent is TTBDock then begin
  3014. if FUseLastDock and not FSmoothDragging then begin
  3015. LastDock := TTBDock(Parent); { calls ChangeDockList if LastDock changes }
  3016. TTBDock(Parent).ToolbarVisibilityChanged(Self, False);
  3017. end
  3018. else
  3019. TTBDock(Parent).ChangeDockList(True, Self);
  3020. end;
  3021. UpdateFloatingToolWindows;
  3022. { Schedule an arrange }
  3023. Arrange;
  3024. finally
  3025. EndUpdate;
  3026. end;
  3027. finally
  3028. Dec(FUpdatingBounds);
  3029. if Assigned(NewCurrentDock) then
  3030. NewCurrentDock.EndUpdate;
  3031. if Assigned(OldCurrentDock) then
  3032. OldCurrentDock.EndUpdate;
  3033. end;
  3034. finally
  3035. Dec(FDisableOnMove);
  3036. Dec(FHidden);
  3037. UpdateVisibility;
  3038. { ^ The above UpdateVisibility call not only updates the tool window's
  3039. visibility after decrementing FHidden, it also sets the
  3040. active/inactive state of the caption. }
  3041. end;
  3042. if Assigned(Parent) then
  3043. Moved;
  3044. if not(csDestroying in ComponentState) and Assigned(AParent) then begin
  3045. if Assigned(FOnRecreated) then
  3046. FOnRecreated(Self);
  3047. if Assigned(FOnDockChanged) then
  3048. FOnDockChanged(Self);
  3049. end;
  3050. end;
  3051. end;
  3052. procedure TTBCustomDockableWindow.AddDockedNCAreaToSize(var S: TPoint;
  3053. const LeftRight: Boolean);
  3054. var
  3055. TopLeft, BottomRight: TPoint;
  3056. begin
  3057. GetDockedNCArea(TopLeft, BottomRight, LeftRight);
  3058. Inc(S.X, TopLeft.X + BottomRight.X);
  3059. Inc(S.Y, TopLeft.Y + BottomRight.Y);
  3060. end;
  3061. procedure TTBCustomDockableWindow.AddFloatingNCAreaToSize(var S: TPoint);
  3062. var
  3063. TopLeft, BottomRight: TPoint;
  3064. begin
  3065. GetFloatingNCArea(TopLeft, BottomRight);
  3066. Inc(S.X, TopLeft.X + BottomRight.X);
  3067. Inc(S.Y, TopLeft.Y + BottomRight.Y);
  3068. end;
  3069. procedure TTBCustomDockableWindow.GetDockedNCArea(var TopLeft, BottomRight: TPoint;
  3070. const LeftRight: Boolean);
  3071. var
  3072. Z: Integer;
  3073. begin
  3074. Z := DockedBorderSize; { code optimization... }
  3075. TopLeft.X := Z;
  3076. TopLeft.Y := Z;
  3077. BottomRight.X := Z;
  3078. BottomRight.Y := Z;
  3079. if not LeftRight then begin
  3080. Inc(TopLeft.X, DragHandleSizes[CloseButtonWhenDocked, DragHandleStyle]);
  3081. //if FShowChevron then
  3082. // Inc(BottomRight.X, tbChevronSize);
  3083. end
  3084. else begin
  3085. Inc(TopLeft.Y, DragHandleSizes[CloseButtonWhenDocked, DragHandleStyle]);
  3086. //if FShowChevron then
  3087. // Inc(BottomRight.Y, tbChevronSize);
  3088. end;
  3089. end;
  3090. function TTBCustomDockableWindow.GetFloatingBorderSize: TPoint;
  3091. { Returns size of a thick border. Note that, depending on the Windows version,
  3092. this may not be the same as the actual window metrics since it draws its
  3093. own border }
  3094. const
  3095. XMetrics: array[Boolean] of Integer = (SM_CXDLGFRAME, SM_CXFRAME);
  3096. YMetrics: array[Boolean] of Integer = (SM_CYDLGFRAME, SM_CYFRAME);
  3097. begin
  3098. Result.X := GetSystemMetrics(XMetrics[Resizable]);
  3099. Result.Y := GetSystemMetrics(YMetrics[Resizable]);
  3100. end;
  3101. procedure TTBCustomDockableWindow.GetFloatingNCArea(var TopLeft, BottomRight: TPoint);
  3102. begin
  3103. with GetFloatingBorderSize do begin
  3104. TopLeft.X := X;
  3105. TopLeft.Y := Y;
  3106. if ShowCaption then
  3107. Inc(TopLeft.Y, GetSmallCaptionHeight);
  3108. BottomRight.X := X;
  3109. BottomRight.Y := Y;
  3110. end;
  3111. end;
  3112. function TTBCustomDockableWindow.GetDockedCloseButtonRect(LeftRight: Boolean): TRect;
  3113. var
  3114. X, Y, Z: Integer;
  3115. begin
  3116. Z := DragHandleSizes[CloseButtonWhenDocked, FDragHandleStyle] - 3;
  3117. if not LeftRight then begin
  3118. X := DockedBorderSize+1;
  3119. Y := DockedBorderSize;
  3120. end
  3121. else begin
  3122. X := (ClientWidth + DockedBorderSize) - Z;
  3123. Y := DockedBorderSize+1;
  3124. end;
  3125. Result := Bounds(X, Y, Z, Z);
  3126. end;
  3127. function TTBCustomDockableWindow.CalcNCSizes: TPoint;
  3128. var
  3129. Z: Integer;
  3130. begin
  3131. if not Docked then begin
  3132. Result.X := 0;
  3133. Result.Y := 0;
  3134. end
  3135. else begin
  3136. Result.X := DockedBorderSize2;
  3137. Result.Y := DockedBorderSize2;
  3138. if CurrentDock.FAllowDrag then begin
  3139. Z := DragHandleSizes[FCloseButtonWhenDocked, FDragHandleStyle];
  3140. if not(CurrentDock.Position in PositionLeftOrRight) then
  3141. Inc(Result.X, Z)
  3142. else
  3143. Inc(Result.Y, Z);
  3144. end;
  3145. end;
  3146. end;
  3147. procedure TTBCustomDockableWindow.WMNCCalcSize(var Message: TWMNCCalcSize);
  3148. var
  3149. Z: Integer;
  3150. begin
  3151. { Doesn't call inherited since it overrides the normal NC sizes }
  3152. Message.Result := 0;
  3153. if Docked then
  3154. with Message.CalcSize_Params^ do begin
  3155. InflateRect(rgrc[0], -DockedBorderSize, -DockedBorderSize);
  3156. if CurrentDock.FAllowDrag then begin
  3157. Z := DragHandleSizes[FCloseButtonWhenDocked, FDragHandleStyle];
  3158. if not(CurrentDock.Position in PositionLeftOrRight) then
  3159. Inc(rgrc[0].Left, Z)
  3160. else
  3161. Inc(rgrc[0].Top, Z);
  3162. end;
  3163. end;
  3164. end;
  3165. procedure TTBCustomDockableWindow.WMSetCursor(var Message: TWMSetCursor);
  3166. var
  3167. P: TPoint;
  3168. R: TRect;
  3169. I: Integer;
  3170. begin
  3171. if Docked and CurrentDock.FAllowDrag and
  3172. (Message.CursorWnd = WindowHandle) and
  3173. (Smallint(Message.HitTest) = HT_TB2k_Border) and
  3174. (DragHandleStyle <> dhNone) then begin
  3175. GetCursorPos(P);
  3176. GetWindowRect(Handle, R);
  3177. if not(CurrentDock.Position in PositionLeftOrRight) then
  3178. I := P.X - R.Left
  3179. else
  3180. I := P.Y - R.Top;
  3181. if I < DockedBorderSize + DragHandleSizes[CloseButtonWhenDocked, DragHandleStyle] then begin
  3182. SetCursor(LoadCursor(0, IDC_SIZEALL));
  3183. Message.Result := 1;
  3184. Exit;
  3185. end;
  3186. end;
  3187. inherited;
  3188. end;
  3189. procedure TTBCustomDockableWindow.DrawNCArea(const DrawToDC: Boolean;
  3190. const ADC: HDC; const Clip: HRGN);
  3191. { Redraws all the non-client area of the toolbar when it is docked. }
  3192. var
  3193. DC: HDC;
  3194. R: TRect;
  3195. VerticalDock: Boolean;
  3196. X, Y, Y2, Y3, YO, S, SaveIndex: Integer;
  3197. R2, R3, R4: TRect;
  3198. P1, P2: TPoint;
  3199. Brush: HBRUSH;
  3200. Clr: TColorRef;
  3201. UsingBackground, B: Boolean;
  3202. procedure DrawRaisedEdge(R: TRect; const FillInterior: Boolean);
  3203. const
  3204. FillMiddle: array[Boolean] of UINT = (0, BF_MIDDLE);
  3205. begin
  3206. DrawEdge(DC, R, BDR_RAISEDINNER, BF_RECT or FillMiddle[FillInterior]);
  3207. end;
  3208. function CreateCloseButtonBitmap: HBITMAP;
  3209. const
  3210. Pattern: array[0..15] of Byte =
  3211. (0, 0, $CC, 0, $78, 0, $30, 0, $78, 0, $CC, 0, 0, 0, 0, 0);
  3212. begin
  3213. Result := CreateBitmap(8, 8, 1, 1, @Pattern);
  3214. end;
  3215. procedure DrawButtonBitmap(const Bmp: HBITMAP);
  3216. var
  3217. TempBmp: TBitmap;
  3218. begin
  3219. TempBmp := TBitmap.Create;
  3220. try
  3221. TempBmp.Handle := Bmp;
  3222. SetTextColor(DC, clBlack);
  3223. SetBkColor(DC, clWhite);
  3224. SelectObject(DC, GetSysColorBrush(COLOR_BTNTEXT));
  3225. BitBlt(DC, R2.Left, R2.Top, R2.Right - R2.Left, R2.Bottom - R2.Top,
  3226. TempBmp.Canvas.Handle, 0, 0, $00E20746 {ROP_DSPDxax});
  3227. finally
  3228. TempBmp.Free;
  3229. end;
  3230. end;
  3231. const
  3232. CloseButtonState: array[Boolean] of UINT = (0, DFCS_PUSHED);
  3233. begin
  3234. if not Docked or not HandleAllocated then Exit;
  3235. if not DrawToDC then
  3236. DC := GetWindowDC(Handle)
  3237. else
  3238. DC := ADC;
  3239. try
  3240. { Use update region }
  3241. if not DrawToDC then
  3242. SelectNCUpdateRgn(Handle, DC, Clip);
  3243. { This works around WM_NCPAINT problem described at top of source code }
  3244. {no! R := Rect(0, 0, Width, Height);}
  3245. GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top);
  3246. VerticalDock := CurrentDock.Position in PositionLeftOrRight;
  3247. Brush := CreateSolidBrush(ColorToRGB(Color));
  3248. UsingBackground := CurrentDock.UsingBackground and CurrentDock.FBkgOnToolbars;
  3249. { Border }
  3250. if BorderStyle = bsSingle then
  3251. DrawRaisedEdge(R, False)
  3252. else
  3253. FrameRect(DC, R, Brush);
  3254. R2 := R;
  3255. InflateRect(R2, -1, -1);
  3256. if not UsingBackground then
  3257. FrameRect(DC, R2, Brush);
  3258. { Draw the Background }
  3259. if UsingBackground then begin
  3260. R2 := R;
  3261. P1 := CurrentDock.ClientToScreen(Point(0, 0));
  3262. P2 := CurrentDock.Parent.ClientToScreen(CurrentDock.BoundsRect.TopLeft);
  3263. Dec(R2.Left, Left + CurrentDock.Left + (P1.X-P2.X));
  3264. Dec(R2.Top, Top + CurrentDock.Top + (P1.Y-P2.Y));
  3265. InflateRect(R, -1, -1);
  3266. GetWindowRect(Handle, R4);
  3267. R3 := ClientRect;
  3268. with ClientToScreen(Point(0, 0)) do
  3269. OffsetRect(R3, X-R4.Left, Y-R4.Top);
  3270. SaveIndex := SaveDC(DC);
  3271. IntersectClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);
  3272. ExcludeClipRect(DC, R3.Left, R3.Top, R3.Right, R3.Bottom);
  3273. CurrentDock.DrawBackground(DC, R2);
  3274. RestoreDC(DC, SaveIndex);
  3275. end;
  3276. { The drag handle at the left, or top }
  3277. if CurrentDock.FAllowDrag then begin
  3278. SaveIndex := SaveDC(DC);
  3279. if not VerticalDock then
  3280. Y2 := ClientHeight
  3281. else
  3282. Y2 := ClientWidth;
  3283. Inc(Y2, DockedBorderSize);
  3284. S := DragHandleSizes[FCloseButtonWhenDocked, FDragHandleStyle];
  3285. if FDragHandleStyle <> dhNone then begin
  3286. Y3 := Y2;
  3287. X := DockedBorderSize + DragHandleXOffsets[FCloseButtonWhenDocked, FDragHandleStyle];
  3288. Y := DockedBorderSize;
  3289. YO := Ord(FDragHandleStyle = dhSingle);
  3290. if FCloseButtonWhenDocked then begin
  3291. if not VerticalDock then
  3292. Inc(Y, S - 2)
  3293. else
  3294. Dec(Y3, S - 2);
  3295. end;
  3296. Clr := GetSysColor(COLOR_BTNHIGHLIGHT);
  3297. for B := False to (FDragHandleStyle = dhDouble) do begin
  3298. if not VerticalDock then
  3299. R2 := Rect(X, Y+YO, X+3, Y2-YO)
  3300. else
  3301. R2 := Rect(Y+YO, X, Y3-YO, X+3);
  3302. DrawRaisedEdge(R2, True);
  3303. if not VerticalDock then
  3304. SetPixelV(DC, X, Y2-1-YO, Clr)
  3305. else
  3306. SetPixelV(DC, Y3-1-YO, X, Clr);
  3307. ExcludeClipRect(DC, R2.Left, R2.Top, R2.Right, R2.Bottom);
  3308. Inc(X, 3);
  3309. end;
  3310. end;
  3311. if not UsingBackground then begin
  3312. if not VerticalDock then
  3313. R2 := Rect(DockedBorderSize, DockedBorderSize,
  3314. DockedBorderSize+S, Y2)
  3315. else
  3316. R2 := Rect(DockedBorderSize, DockedBorderSize,
  3317. Y2, DockedBorderSize+S);
  3318. FillRect(DC, R2, Brush);
  3319. end;
  3320. RestoreDC(DC, SaveIndex);
  3321. { Close button }
  3322. if FCloseButtonWhenDocked then begin
  3323. R2 := GetDockedCloseButtonRect(VerticalDock);
  3324. if FCloseButtonDown then
  3325. DrawEdge(DC, R2, BDR_SUNKENOUTER, BF_RECT)
  3326. else if FCloseButtonHover then
  3327. DrawRaisedEdge(R2, False);
  3328. InflateRect(R2, -2, -2);
  3329. if FCloseButtonDown then
  3330. OffsetRect(R2, 1, 1);
  3331. DrawButtonBitmap(CreateCloseButtonBitmap);
  3332. end;
  3333. end;
  3334. DeleteObject(Brush);
  3335. finally
  3336. if not DrawToDC then
  3337. ReleaseDC(Handle, DC);
  3338. end;
  3339. end;
  3340. procedure TTBCustomDockableWindow.RedrawNCArea;
  3341. begin
  3342. { Note: IsWindowVisible is called as an optimization. There's no need to
  3343. draw on invisible windows. }
  3344. if HandleAllocated and IsWindowVisible(Handle) then
  3345. DrawNCArea(False, 0, 0);
  3346. end;
  3347. procedure TTBCustomDockableWindow.WMNCPaint(var Message: TMessage);
  3348. begin
  3349. { Don't call inherited because it overrides the default NC painting }
  3350. DrawNCArea(False, 0, HRGN(Message.WParam));
  3351. end;
  3352. procedure DockableWindowNCPaintProc(Wnd: HWND; DC: HDC; AppData: Longint);
  3353. begin
  3354. with TTBCustomDockableWindow(AppData) do
  3355. DrawNCArea(True, DC, 0)
  3356. end;
  3357. procedure TTBCustomDockableWindow.WMPrint(var Message: TMessage);
  3358. begin
  3359. HandleWMPrint(Handle, Message, DockableWindowNCPaintProc, Longint(Self));
  3360. end;
  3361. procedure TTBCustomDockableWindow.WMPrintClient(var Message: TMessage);
  3362. begin
  3363. HandleWMPrintClient(Self, Message);
  3364. end;
  3365. procedure TTBCustomDockableWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  3366. var
  3367. R, R2, R3: TRect;
  3368. P1, P2: TPoint;
  3369. SaveIndex: Integer;
  3370. begin
  3371. if Docked and CurrentDock.UsingBackground and CurrentDock.FBkgOnToolbars then begin
  3372. R := ClientRect;
  3373. R2 := R;
  3374. P1 := CurrentDock.ClientToScreen(Point(0, 0));
  3375. P2 := CurrentDock.Parent.ClientToScreen(CurrentDock.BoundsRect.TopLeft);
  3376. Dec(R2.Left, Left + CurrentDock.Left + (P1.X-P2.X));
  3377. Dec(R2.Top, Top + CurrentDock.Top + (P1.Y-P2.Y));
  3378. GetWindowRect(Handle, R3);
  3379. with ClientToScreen(Point(0, 0)) do begin
  3380. Inc(R2.Left, R3.Left-X);
  3381. Inc(R2.Top, R3.Top-Y);
  3382. end;
  3383. SaveIndex := SaveDC(Message.DC);
  3384. IntersectClipRect(Message.DC, R.Left, R.Top, R.Right, R.Bottom);
  3385. CurrentDock.DrawBackground(Message.DC, R2);
  3386. RestoreDC(Message.DC, SaveIndex);
  3387. Message.Result := 1;
  3388. end
  3389. else
  3390. inherited;
  3391. end;
  3392. function TTBCustomDockableWindow.GetPalette: HPALETTE;
  3393. begin
  3394. if Docked then
  3395. Result := CurrentDock.GetPalette
  3396. else
  3397. Result := 0;
  3398. end;
  3399. function TTBCustomDockableWindow.PaletteChanged(Foreground: Boolean): Boolean;
  3400. begin
  3401. Result := inherited PaletteChanged(Foreground);
  3402. if Result and not Foreground then begin
  3403. { There seems to be a bug in Delphi's palette handling. When the form is
  3404. inactive and another window realizes a palette, docked TToolbar97s
  3405. weren't getting redrawn. So this workaround code was added. }
  3406. InvalidateAll(Self);
  3407. end;
  3408. end;
  3409. procedure TTBCustomDockableWindow.DrawDraggingOutline(const DC: HDC;
  3410. const NewRect, OldRect: PRect; const NewDocking, OldDocking: Boolean);
  3411. var
  3412. NewSize, OldSize: TSize;
  3413. begin
  3414. with GetFloatingBorderSize do begin
  3415. if NewDocking then NewSize.cx := 1 else NewSize.cx := X;
  3416. NewSize.cy := NewSize.cx;
  3417. if OldDocking then OldSize.cx := 1 else OldSize.cx := X;
  3418. OldSize.cy := OldSize.cx;
  3419. end;
  3420. DrawHalftoneInvertRect(DC, NewRect, OldRect, NewSize, OldSize);
  3421. end;
  3422. procedure TTBCustomDockableWindow.CMColorChanged(var Message: TMessage);
  3423. begin
  3424. { Make sure non-client area is redrawn }
  3425. InvalidateAll(Self);
  3426. inherited; { the inherited handler calls Invalidate }
  3427. end;
  3428. procedure TTBCustomDockableWindow.CMTextChanged(var Message: TMessage);
  3429. begin
  3430. inherited;
  3431. if Parent is TTBFloatingWindowParent then
  3432. TTBFloatingWindowParent(Parent).Caption := Caption;
  3433. end;
  3434. procedure TTBCustomDockableWindow.CMVisibleChanged(var Message: TMessage);
  3435. begin
  3436. if not(csDesigning in ComponentState) and Docked then
  3437. CurrentDock.ToolbarVisibilityChanged(Self, False);
  3438. inherited;
  3439. if Assigned(FOnVisibleChanged) then
  3440. FOnVisibleChanged(Self);
  3441. end;
  3442. procedure TTBCustomDockableWindow.BeginMoving(const InitX, InitY: Integer);
  3443. type
  3444. PDockedSize = ^TDockedSize;
  3445. TDockedSize = record
  3446. Dock: TTBDock;
  3447. BoundsRect: TRect;
  3448. Size: TPoint;
  3449. RowSizes: TList;
  3450. end;
  3451. const
  3452. SplitCursors: array[Boolean] of PChar = (IDC_SIZEWE, IDC_SIZENS);
  3453. var
  3454. UseSmoothDrag: Boolean;
  3455. DockList: TList;
  3456. NewDockedSizes: TList; {items are pointers to TDockedSizes}
  3457. OriginalDock, MouseOverDock: TTBDock;
  3458. MoveRect: TRect;
  3459. StartDocking, PreventDocking, PreventFloating, WatchForSplit, SplitVertical: Boolean;
  3460. ScreenDC: HDC;
  3461. OldCursor: HCURSOR;
  3462. NPoint, DPoint: TPoint;
  3463. OriginalDockRow, OriginalDockPos: Integer;
  3464. FirstPos, LastPos, CurPos: TPoint;
  3465. function FindDockedSize(const ADock: TTBDock): PDockedSize;
  3466. var
  3467. I: Integer;
  3468. begin
  3469. for I := 0 to NewDockedSizes.Count-1 do begin
  3470. Result := NewDockedSizes[I];
  3471. if Result.Dock = ADock then
  3472. Exit;
  3473. end;
  3474. Result := nil;
  3475. end;
  3476. function GetRowOf(const RowSizes: TList; const XY: Integer;
  3477. var Before: Boolean): Integer;
  3478. { Returns row number of the specified coordinate. Before is set to True if it
  3479. was in the top (or left) quarter of the row. }
  3480. var
  3481. HighestRow, R, CurY, NextY, CurRowSize, EdgeSize: Integer;
  3482. FullSizeRow: Boolean;
  3483. begin
  3484. Before := False;
  3485. HighestRow := RowSizes.Count-1;
  3486. CurY := 0;
  3487. for R := 0 to HighestRow do begin
  3488. CurRowSize := Integer(RowSizes[R]);
  3489. FullSizeRow := FullSize or (CurRowSize and $10000 <> 0);
  3490. CurRowSize := Smallint(CurRowSize);
  3491. if CurRowSize = 0 then
  3492. Continue;
  3493. NextY := CurY + CurRowSize;
  3494. if not FullSizeRow then
  3495. EdgeSize := CurRowSize div 4
  3496. else
  3497. EdgeSize := CurRowSize div 2;
  3498. if XY < CurY + EdgeSize then begin
  3499. Result := R;
  3500. Before := True;
  3501. Exit;
  3502. end;
  3503. if not FullSizeRow and (XY < NextY - EdgeSize) then begin
  3504. Result := R;
  3505. Exit;
  3506. end;
  3507. CurY := NextY;
  3508. end;
  3509. Result := HighestRow+1;
  3510. end;
  3511. procedure Dropped;
  3512. var
  3513. NewDockRow: Integer;
  3514. Before: Boolean;
  3515. MoveRectClient: TRect;
  3516. C: Integer;
  3517. DockedSize: PDockedSize;
  3518. begin
  3519. if MouseOverDock <> nil then begin
  3520. DockedSize := FindDockedSize(MouseOverDock);
  3521. MoveRectClient := MoveRect;
  3522. OffsetRect(MoveRectClient, -DockedSize.BoundsRect.Left,
  3523. -DockedSize.BoundsRect.Top);
  3524. if not FDragSplitting then begin
  3525. if not(MouseOverDock.Position in PositionLeftOrRight) then
  3526. C := (MoveRectClient.Top+MoveRectClient.Bottom) div 2
  3527. else
  3528. C := (MoveRectClient.Left+MoveRectClient.Right) div 2;
  3529. NewDockRow := GetRowOf(DockedSize.RowSizes, C, Before);
  3530. if Before then
  3531. WatchForSplit := False;
  3532. end
  3533. else begin
  3534. NewDockRow := FDockRow;
  3535. Before := False;
  3536. end;
  3537. if WatchForSplit then begin
  3538. if (MouseOverDock <> OriginalDock) or (NewDockRow <> OriginalDockRow) then
  3539. WatchForSplit := False
  3540. else begin
  3541. if not SplitVertical then
  3542. C := FirstPos.X - LastPos.X
  3543. else
  3544. C := FirstPos.Y - LastPos.Y;
  3545. if Abs(C) >= 10 then begin
  3546. WatchForSplit := False;
  3547. FDragSplitting := True;
  3548. SetCursor(LoadCursor(0, SplitCursors[SplitVertical]));
  3549. end;
  3550. end;
  3551. end;
  3552. FDockRow := NewDockRow;
  3553. if not(MouseOverDock.Position in PositionLeftOrRight) then
  3554. FDockPos := MoveRectClient.Left
  3555. else
  3556. FDockPos := MoveRectClient.Top;
  3557. Parent := MouseOverDock;
  3558. if not FSmoothDragging then
  3559. CurrentDock.CommitNewPositions := True;
  3560. FInsertRowBefore := Before;
  3561. try
  3562. CurrentDock.ArrangeToolbars;
  3563. finally
  3564. FInsertRowBefore := False;
  3565. end;
  3566. end
  3567. else begin
  3568. WatchForSplit := False;
  3569. FloatingPosition := MoveRect.TopLeft;
  3570. Floating := True;
  3571. { Make sure it doesn't go completely off the screen }
  3572. MoveOnScreen(True);
  3573. end;
  3574. { Make sure it's repainted immediately (looks better on really slow
  3575. computers when smooth dragging is enabled) }
  3576. Update;
  3577. end;
  3578. procedure MouseMoved;
  3579. var
  3580. OldMouseOverDock: TTBDock;
  3581. OldMoveRect: TRect;
  3582. Pos: TPoint;
  3583. function GetDockRect(Control: TTBDock): TRect;
  3584. var
  3585. I: Integer;
  3586. begin
  3587. for I := 0 to NewDockedSizes.Count-1 do
  3588. with PDockedSize(NewDockedSizes[I])^ do begin
  3589. if Dock <> Control then Continue;
  3590. Result := Bounds(Pos.X-MulDiv(Size.X-1, NPoint.X, DPoint.X),
  3591. Pos.Y-MulDiv(Size.Y-1, NPoint.Y, DPoint.Y),
  3592. Size.X, Size.Y);
  3593. Exit;
  3594. end;
  3595. SetRectEmpty(Result);
  3596. end;
  3597. function CheckIfCanDockTo(Control: TTBDock; R: TRect): Boolean;
  3598. const
  3599. DockSensX = 25;
  3600. DockSensY = 25;
  3601. var
  3602. S, Temp: TRect;
  3603. Sens: Integer;
  3604. begin
  3605. with Control do begin
  3606. Result := False;
  3607. InflateRect(R, 3, 3);
  3608. S := GetDockRect(Control);
  3609. { Like Office, distribute ~25 pixels of extra dock detection area
  3610. to the left side if the toolbar was grabbed at the left, both sides
  3611. if the toolbar was grabbed at the middle, or the right side if
  3612. toolbar was grabbed at the right. If outside, don't try to dock. }
  3613. Sens := MulDiv(DockSensX, NPoint.X, DPoint.X);
  3614. if (Pos.X < R.Left-(DockSensX-Sens)) or (Pos.X >= R.Right+Sens) then
  3615. Exit;
  3616. { Don't try to dock to the left or right if pointer is above or below
  3617. the boundaries of the dock }
  3618. if (Control.Position in PositionLeftOrRight) and
  3619. ((Pos.Y < R.Top) or (Pos.Y >= R.Bottom)) then
  3620. Exit;
  3621. { And also distribute ~25 pixels of extra dock detection area to
  3622. the top or bottom side }
  3623. Sens := MulDiv(DockSensY, NPoint.Y, DPoint.Y);
  3624. if (Pos.Y < R.Top-(DockSensY-Sens)) or (Pos.Y >= R.Bottom+Sens) then
  3625. Exit;
  3626. Result := IntersectRect(Temp, R, S);
  3627. end;
  3628. end;
  3629. var
  3630. R, R2: TRect;
  3631. I: Integer;
  3632. Dock: TTBDock;
  3633. Accept: Boolean;
  3634. TL, BR: TPoint;
  3635. begin
  3636. OldMouseOverDock := MouseOverDock;
  3637. OldMoveRect := MoveRect;
  3638. GetCursorPos(Pos);
  3639. if FDragSplitting then
  3640. MouseOverDock := CurrentDock
  3641. else begin
  3642. { Check if it can dock }
  3643. MouseOverDock := nil;
  3644. if StartDocking and not PreventDocking then
  3645. { MP }
  3646. { reversal of for cycle proposed by 'rl' is rejected as it suffers a bug:
  3647. { whenever toolbar is "catched", it is moved to different row }
  3648. for I := 0 to DockList.Count-1 do begin
  3649. Dock := DockList[I];
  3650. if CheckIfCanDockTo(Dock, FindDockedSize(Dock).BoundsRect) then begin
  3651. MouseOverDock := Dock;
  3652. Accept := True;
  3653. if Assigned(MouseOverDock.FOnRequestDock) then
  3654. MouseOverDock.FOnRequestDock(MouseOverDock, Self, Accept);
  3655. if Accept then
  3656. Break
  3657. else
  3658. MouseOverDock := nil;
  3659. end;
  3660. end;
  3661. end;
  3662. { If not docking, clip the point so it doesn't get dragged under the
  3663. taskbar }
  3664. if MouseOverDock = nil then begin
  3665. R := GetRectOfMonitorContainingPoint(Pos, True);
  3666. if Pos.X < R.Left then Pos.X := R.Left;
  3667. if Pos.X > R.Right then Pos.X := R.Right;
  3668. if Pos.Y < R.Top then Pos.Y := R.Top;
  3669. if Pos.Y > R.Bottom then Pos.Y := R.Bottom;
  3670. end;
  3671. MoveRect := GetDockRect(MouseOverDock);
  3672. { Make sure title bar (or at least part of the toolbar) is still accessible
  3673. if it's dragged almost completely off the screen. This prevents the
  3674. problem seen in Office 97 where you drag it offscreen so that only the
  3675. border is visible, sometimes leaving you no way to move it back short of
  3676. resetting the toolbar. }
  3677. if MouseOverDock = nil then begin
  3678. R2 := GetRectOfMonitorContainingPoint(Pos, True);
  3679. R := R2;
  3680. with GetFloatingBorderSize do
  3681. InflateRect(R, -(X+4), -(Y+4));
  3682. if MoveRect.Bottom < R.Top then
  3683. OffsetRect(MoveRect, 0, R.Top-MoveRect.Bottom);
  3684. if MoveRect.Top > R.Bottom then
  3685. OffsetRect(MoveRect, 0, R.Bottom-MoveRect.Top);
  3686. if MoveRect.Right < R.Left then
  3687. OffsetRect(MoveRect, R.Left-MoveRect.Right, 0);
  3688. if MoveRect.Left > R.Right then
  3689. OffsetRect(MoveRect, R.Right-MoveRect.Left, 0);
  3690. GetFloatingNCArea(TL, BR);
  3691. I := R2.Top + 4 - TL.Y;
  3692. if MoveRect.Top < I then
  3693. OffsetRect(MoveRect, 0, I-MoveRect.Top);
  3694. end;
  3695. { Empty MoveRect if it's wanting to float but it's not allowed to, and
  3696. set the mouse cursor accordingly. }
  3697. if PreventFloating and not Assigned(MouseOverDock) then begin
  3698. SetRectEmpty(MoveRect);
  3699. SetCursor(LoadCursor(0, IDC_NO));
  3700. end
  3701. else begin
  3702. if FDragSplitting then
  3703. SetCursor(LoadCursor(0, SplitCursors[SplitVertical]))
  3704. else
  3705. SetCursor(OldCursor);
  3706. end;
  3707. { Update the dragging outline }
  3708. if not UseSmoothDrag then
  3709. DrawDraggingOutline(ScreenDC, @MoveRect, @OldMoveRect, MouseOverDock <> nil,
  3710. OldMouseOverDock <> nil)
  3711. else
  3712. if not IsRectEmpty(MoveRect) then
  3713. Dropped;
  3714. end;
  3715. procedure BuildDockList;
  3716. procedure Recurse(const ParentCtl: TWinControl);
  3717. var
  3718. D: TTBDockPosition;
  3719. I: Integer;
  3720. begin
  3721. if ContainsControl(ParentCtl) or not ParentCtl.Showing then
  3722. Exit;
  3723. with ParentCtl do begin
  3724. for D := Low(D) to High(D) do
  3725. for I := 0 to ParentCtl.ControlCount-1 do
  3726. if (Controls[I] is TTBDock) and (TTBDock(Controls[I]).Position = D) then
  3727. Recurse(TWinControl(Controls[I]));
  3728. for I := 0 to ParentCtl.ControlCount-1 do
  3729. if (Controls[I] is TWinControl) and not(Controls[I] is TTBDock) then
  3730. Recurse(TWinControl(Controls[I]));
  3731. end;
  3732. if (ParentCtl is TTBDock) and TTBDock(ParentCtl).Accepts(Self) and CanDockTo(TTBDock(ParentCtl)) and
  3733. (DockList.IndexOf(ParentCtl) = -1) then
  3734. DockList.Add(ParentCtl);
  3735. end;
  3736. var
  3737. ParentForm: TTBCustomForm;
  3738. DockFormsList: TList;
  3739. I, J: Integer;
  3740. begin
  3741. { Manually add CurrentDock to the DockList first so that it gets priority
  3742. over other docks }
  3743. if Assigned(CurrentDock) and CurrentDock.Accepts(Self) and CanDockTo(CurrentDock) then
  3744. DockList.Add(CurrentDock);
  3745. ParentForm := TBGetToolWindowParentForm(Self);
  3746. DockFormsList := TList.Create;
  3747. try
  3748. if Assigned(FDockForms) then begin
  3749. for I := 0 to Screen.{$IFDEF JR_D3}CustomFormCount{$ELSE}FormCount{$ENDIF}-1 do begin
  3750. J := FDockForms.IndexOf(Screen.{$IFDEF JR_D3}CustomForms{$ELSE}Forms{$ENDIF}[I]);
  3751. if (J <> -1) and (FDockForms[J] <> ParentForm) then
  3752. DockFormsList.Add(FDockForms[J]);
  3753. end;
  3754. end;
  3755. if Assigned(ParentForm) then
  3756. DockFormsList.Insert(0, ParentForm);
  3757. for I := 0 to DockFormsList.Count-1 do
  3758. Recurse(DockFormsList[I]);
  3759. finally
  3760. DockFormsList.Free;
  3761. end;
  3762. end;
  3763. var
  3764. Accept, FullSizeRow: Boolean;
  3765. R: TRect;
  3766. Msg: TMsg;
  3767. NewDockedSize: PDockedSize;
  3768. I, J, S: Integer;
  3769. begin
  3770. Accept := False;
  3771. SplitVertical := False;
  3772. WatchForSplit := False;
  3773. OriginalDock := CurrentDock;
  3774. OriginalDockRow := FDockRow;
  3775. OriginalDockPos := FDockPos;
  3776. try
  3777. FDragMode := True;
  3778. FDragSplitting := False;
  3779. if Docked then begin
  3780. FDragCanSplit := False;
  3781. CurrentDock.CommitNewPositions := True;
  3782. CurrentDock.ArrangeToolbars; { needed for WatchForSplit assignment below }
  3783. SplitVertical := CurrentDock.Position in PositionLeftOrRight;
  3784. WatchForSplit := FDragCanSplit;
  3785. end;
  3786. DockList := nil;
  3787. NewDockedSizes := nil;
  3788. try
  3789. UseSmoothDrag := FSmoothDrag;
  3790. FSmoothDragging := UseSmoothDrag;
  3791. NPoint := Point(InitX, InitY);
  3792. { Adjust for non-client area }
  3793. if not(Parent is TTBFloatingWindowParent) then begin
  3794. GetWindowRect(Handle, R);
  3795. R.BottomRight := ClientToScreen(Point(0, 0));
  3796. DPoint := Point(Width-1, Height-1);
  3797. end
  3798. else begin
  3799. GetWindowRect(Parent.Handle, R);
  3800. R.BottomRight := Parent.ClientToScreen(Point(0, 0));
  3801. DPoint := Point(Parent.Width-1, Parent.Height-1);
  3802. end;
  3803. Dec(NPoint.X, R.Left-R.Right);
  3804. Dec(NPoint.Y, R.Top-R.Bottom);
  3805. PreventDocking := GetKeyState(VK_CONTROL) < 0;
  3806. PreventFloating := DockMode <> dmCanFloat;
  3807. { Build list of all TTBDock's on the form }
  3808. DockList := TList.Create;
  3809. if DockMode <> dmCannotFloatOrChangeDocks then
  3810. BuildDockList
  3811. else
  3812. if Docked then
  3813. DockList.Add(CurrentDock);
  3814. { Ensure positions of each possible dock are committed }
  3815. for I := 0 to DockList.Count-1 do
  3816. TTBDock(DockList[I]).CommitPositions;
  3817. { Set up potential sizes for each dock type }
  3818. NewDockedSizes := TList.Create;
  3819. for I := -1 to DockList.Count-1 do begin
  3820. New(NewDockedSize);
  3821. NewDockedSize.RowSizes := nil;
  3822. try
  3823. with NewDockedSize^ do begin
  3824. if I = -1 then begin
  3825. { -1 adds the floating size }
  3826. Dock := nil;
  3827. SetRectEmpty(BoundsRect);
  3828. Size := DoArrange(False, TBGetDockTypeOf(CurrentDock, Floating), True, nil);
  3829. AddFloatingNCAreaToSize(Size);
  3830. end
  3831. else begin
  3832. Dock := TTBDock(DockList[I]);
  3833. GetWindowRect(Dock.Handle, BoundsRect);
  3834. if Dock <> CurrentDock then begin
  3835. Size := DoArrange(False, TBGetDockTypeOf(CurrentDock, Floating), False, Dock);
  3836. AddDockedNCAreaToSize(Size, Dock.Position in PositionLeftOrRight);
  3837. end
  3838. else
  3839. Size := Point(Width, Height);
  3840. end;
  3841. end;
  3842. if Assigned(NewDockedSize.Dock) then begin
  3843. NewDockedSize.RowSizes := TList.Create;
  3844. for J := 0 to NewDockedSize.Dock.GetHighestRow(True) do begin
  3845. S := Smallint(NewDockedSize.Dock.GetCurrentRowSize(J, FullSizeRow));
  3846. if FullSizeRow then
  3847. S := S or $10000;
  3848. NewDockedSize.RowSizes.Add(Pointer(S));
  3849. end;
  3850. end;
  3851. NewDockedSizes.Add(NewDockedSize);
  3852. except
  3853. NewDockedSize.RowSizes.Free;
  3854. Dispose(NewDockedSize);
  3855. raise;
  3856. end;
  3857. end;
  3858. { Before locking, make sure all pending paint messages are processed }
  3859. ProcessPaintMessages;
  3860. { Save the original mouse cursor }
  3861. OldCursor := GetCursor;
  3862. if not UseSmoothDrag then begin
  3863. { This uses LockWindowUpdate to suppress all window updating so the
  3864. dragging outlines doesn't sometimes get garbled. (This is safe, and in
  3865. fact, is the main purpose of the LockWindowUpdate function)
  3866. IMPORTANT! While debugging you might want to enable the 'TB2Dock_DisableLock'
  3867. conditional define (see top of the source code). }
  3868. {$IFNDEF TB2Dock_DisableLock}
  3869. LockWindowUpdate(GetDesktopWindow);
  3870. {$ENDIF}
  3871. { Get a DC of the entire screen. Works around the window update lock
  3872. by specifying DCX_LOCKWINDOWUPDATE. }
  3873. ScreenDC := GetDCEx(GetDesktopWindow, 0,
  3874. DCX_LOCKWINDOWUPDATE or DCX_CACHE or DCX_WINDOW);
  3875. end
  3876. else
  3877. ScreenDC := 0;
  3878. try
  3879. SetCapture(Handle);
  3880. { Initialize }
  3881. StartDocking := Docked;
  3882. MouseOverDock := nil;
  3883. SetRectEmpty(MoveRect);
  3884. GetCursorPos(FirstPos);
  3885. LastPos := FirstPos;
  3886. MouseMoved;
  3887. StartDocking := True;
  3888. { Stay in message loop until capture is lost. Capture is removed either
  3889. by this procedure manually doing it, or by an outside influence (like
  3890. a message box or menu popping up) }
  3891. while GetCapture = Handle do begin
  3892. case Integer(GetMessage(Msg, 0, 0, 0)) of
  3893. -1: Break; { if GetMessage failed }
  3894. 0: begin
  3895. { Repost WM_QUIT messages }
  3896. PostQuitMessage(Msg.WParam);
  3897. Break;
  3898. end;
  3899. end;
  3900. case Msg.Message of
  3901. WM_KEYDOWN, WM_KEYUP:
  3902. { Ignore all keystrokes while dragging. But process Ctrl and Escape }
  3903. case Msg.WParam of
  3904. VK_CONTROL:
  3905. if PreventDocking <> (Msg.Message = WM_KEYDOWN) then begin
  3906. PreventDocking := Msg.Message = WM_KEYDOWN;
  3907. MouseMoved;
  3908. end;
  3909. VK_ESCAPE:
  3910. Break;
  3911. end;
  3912. WM_MOUSEMOVE: begin
  3913. { Note to self: WM_MOUSEMOVE messages should never be dispatched
  3914. here to ensure no hints get shown during the drag process }
  3915. CurPos := SmallPointToPoint(TSmallPoint(DWORD(GetMessagePos)));
  3916. if (LastPos.X <> CurPos.X) or (LastPos.Y <> CurPos.Y) then begin
  3917. MouseMoved;
  3918. LastPos := CurPos;
  3919. end;
  3920. end;
  3921. WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
  3922. { Make sure it doesn't begin another loop }
  3923. Break;
  3924. WM_LBUTTONUP: begin
  3925. Accept := True;
  3926. Break;
  3927. end;
  3928. WM_RBUTTONDOWN..WM_MBUTTONDBLCLK:
  3929. { Ignore all other mouse up/down messages }
  3930. ;
  3931. else
  3932. TranslateMessage(Msg);
  3933. DispatchMessage(Msg);
  3934. end;
  3935. end;
  3936. finally
  3937. { Since it sometimes breaks out of the loop without capture being
  3938. released }
  3939. if GetCapture = Handle then
  3940. ReleaseCapture;
  3941. if not UseSmoothDrag then begin
  3942. { Hide dragging outline. Since NT will release a window update lock if
  3943. another thread comes to the foreground, it has to release the DC
  3944. and get a new one for erasing the dragging outline. Otherwise,
  3945. the DrawDraggingOutline appears to have no effect when this happens. }
  3946. ReleaseDC(GetDesktopWindow, ScreenDC);
  3947. ScreenDC := GetDCEx(GetDesktopWindow, 0,
  3948. DCX_LOCKWINDOWUPDATE or DCX_CACHE or DCX_WINDOW);
  3949. DrawDraggingOutline(ScreenDC, nil, @MoveRect, True, MouseOverDock <> nil);
  3950. ReleaseDC(GetDesktopWindow, ScreenDC);
  3951. { Release window update lock }
  3952. {$IFNDEF TB2Dock_DisableLock}
  3953. LockWindowUpdate(0);
  3954. {$ENDIF}
  3955. end;
  3956. end;
  3957. { Move to new position only if MoveRect isn't empty }
  3958. FSmoothDragging := False;
  3959. if Accept and not IsRectEmpty(MoveRect) then
  3960. { Note: Dropped must be called again after FSmoothDragging is reset to
  3961. False so that TTBDock.ArrangeToolbars makes the DockPos changes
  3962. permanent }
  3963. Dropped;
  3964. { LastDock isn't automatically updated while FSmoothDragging=True, so
  3965. update it now that it's back to False }
  3966. if FUseLastDock and Assigned(CurrentDock) then
  3967. LastDock := CurrentDock;
  3968. { Free FFloatParent if it's no longer the Parent }
  3969. if Assigned(FFloatParent) and (Parent <> FFloatParent) then begin
  3970. FFloatParent.Free;
  3971. FFloatParent := nil;
  3972. end;
  3973. finally
  3974. FSmoothDragging := False;
  3975. if not Docked then begin
  3976. { If we didn't end up docking, restore the original DockRow & DockPos
  3977. values }
  3978. FDockRow := OriginalDockRow;
  3979. FDockPos := OriginalDockPos;
  3980. end;
  3981. if Assigned(NewDockedSizes) then begin
  3982. for I := NewDockedSizes.Count-1 downto 0 do begin
  3983. NewDockedSize := NewDockedSizes[I];
  3984. NewDockedSize.RowSizes.Free;
  3985. Dispose(NewDockedSize);
  3986. end;
  3987. NewDockedSizes.Free;
  3988. end;
  3989. DockList.Free;
  3990. end;
  3991. finally
  3992. FDragMode := False;
  3993. FDragSplitting := False;
  3994. end;
  3995. end;
  3996. function TTBCustomDockableWindow.ChildControlTransparent(Ctl: TControl): Boolean;
  3997. begin
  3998. Result := False;
  3999. end;
  4000. procedure TTBCustomDockableWindow.ControlExistsAtPos(const P: TPoint;
  4001. var ControlExists: Boolean);
  4002. var
  4003. I: Integer;
  4004. begin
  4005. for I := 0 to ControlCount-1 do
  4006. if not ChildControlTransparent(Controls[I]) and Controls[I].Visible and
  4007. PtInRect(Controls[I].BoundsRect, P) then begin
  4008. ControlExists := True;
  4009. Break;
  4010. end;
  4011. end;
  4012. procedure TTBCustomDockableWindow.DoubleClick;
  4013. begin
  4014. if Docked then begin
  4015. if DblClickUndock and (DockMode = dmCanFloat) then begin
  4016. Floating := True;
  4017. MoveOnScreen(True);
  4018. end;
  4019. end
  4020. else if Floating then begin
  4021. if Assigned(LastDock) then
  4022. Parent := LastDock
  4023. else
  4024. if Assigned(DefaultDock) then begin
  4025. FDockRow := ForceDockAtTopRow;
  4026. FDockPos := ForceDockAtLeftPos;
  4027. Parent := DefaultDock;
  4028. end;
  4029. end;
  4030. end;
  4031. function TTBCustomDockableWindow.IsMovable: Boolean;
  4032. begin
  4033. Result := (Docked and CurrentDock.FAllowDrag) or Floating;
  4034. end;
  4035. procedure TTBCustomDockableWindow.MouseDown(Button: TMouseButton;
  4036. Shift: TShiftState; X, Y: Integer);
  4037. var
  4038. P: TPoint;
  4039. CtlExists: Boolean;
  4040. begin
  4041. inherited;
  4042. if (Button <> mbLeft) or not IsMovable then
  4043. Exit;
  4044. { Ignore message if user clicked on a child control }
  4045. P := Point(X, Y);
  4046. if PtInRect(ClientRect, P) then begin
  4047. CtlExists := False;
  4048. ControlExistsAtPos(P, CtlExists);
  4049. if CtlExists then
  4050. Exit;
  4051. end;
  4052. if not(ssDouble in Shift) then begin
  4053. BeginMoving(X, Y);
  4054. MouseUp(mbLeft, [], -1, -1);
  4055. end
  4056. else
  4057. { Handle double click }
  4058. DoubleClick;
  4059. end;
  4060. procedure TTBCustomDockableWindow.WMNCHitTest(var Message: TWMNCHitTest);
  4061. var
  4062. P: TPoint;
  4063. R: TRect;
  4064. begin
  4065. inherited;
  4066. if Docked then
  4067. with Message do begin
  4068. P := SmallPointToPoint(Pos);
  4069. GetWindowRect(Handle, R);
  4070. Dec(P.X, R.Left); Dec(P.Y, R.Top);
  4071. if Result <> HTCLIENT then begin
  4072. Result := HTNOWHERE;
  4073. if FCloseButtonWhenDocked and CurrentDock.FAllowDrag and
  4074. PtInRect(GetDockedCloseButtonRect(
  4075. TBGetDockTypeOf(CurrentDock, Floating) = dtLeftRight), P) then
  4076. Result := HT_TB2k_Close
  4077. else
  4078. Result := HT_TB2k_Border;
  4079. end;
  4080. end;
  4081. end;
  4082. procedure TTBCustomDockableWindow.WMNCMouseMove(var Message: TWMNCMouseMove);
  4083. var
  4084. InArea: Boolean;
  4085. begin
  4086. inherited;
  4087. { Note: TME_NONCLIENT was introduced in Windows 98 and 2000 }
  4088. CallTrackMouseEvent(Handle, TME_LEAVE or $10 {TME_NONCLIENT});
  4089. InArea := Message.HitTest = HT_TB2k_Close;
  4090. if FCloseButtonHover <> InArea then begin
  4091. FCloseButtonHover := InArea;
  4092. RedrawNCArea;
  4093. end;
  4094. end;
  4095. procedure TTBCustomDockableWindow.WMNCMouseLeave(var Message: TMessage);
  4096. begin
  4097. if not MouseCapture then
  4098. CancelNCHover;
  4099. inherited;
  4100. end;
  4101. procedure TTBCustomDockableWindow.CMMouseLeave(var Message: TMessage);
  4102. begin
  4103. inherited;
  4104. { On Windows versions that can't send a WM_NCMOUSELEAVE message, trap
  4105. CM_MOUSELEAVE to detect when the mouse moves from the non-client area to
  4106. another control. }
  4107. CancelNCHover;
  4108. end;
  4109. procedure TTBCustomDockableWindow.WMMouseMove(var Message: TMessage);
  4110. begin
  4111. { On Windows versions that can't send a WM_NCMOUSELEAVE message, trap
  4112. WM_MOUSEMOVE to detect when the mouse moves from the non-client area to
  4113. the client area.
  4114. Note: We are overriding WM_MOUSEMOVE instead of MouseMove so that our
  4115. processing always gets done first. }
  4116. CancelNCHover;
  4117. inherited;
  4118. end;
  4119. procedure TTBCustomDockableWindow.CancelNCHover;
  4120. begin
  4121. if FCloseButtonHover then begin
  4122. FCloseButtonHover := False;
  4123. RedrawNCArea;
  4124. end;
  4125. end;
  4126. procedure TTBCustomDockableWindow.Close;
  4127. var
  4128. Accept: Boolean;
  4129. begin
  4130. Accept := True;
  4131. if Assigned(FOnCloseQuery) then
  4132. FOnCloseQuery(Self, Accept);
  4133. { Did the CloseQuery event return True? }
  4134. if Accept then begin
  4135. Hide;
  4136. if Assigned(FOnClose) then
  4137. FOnClose(Self);
  4138. end;
  4139. end;
  4140. procedure TTBCustomDockableWindow.SetCloseButtonState(Pushed: Boolean);
  4141. begin
  4142. if FCloseButtonDown <> Pushed then begin
  4143. FCloseButtonDown := Pushed;
  4144. RedrawNCArea;
  4145. end;
  4146. end;
  4147. procedure TTBCustomDockableWindow.WMNCLButtonDown(var Message: TWMNCLButtonDown);
  4148. var
  4149. R, BR: TRect;
  4150. P: TPoint;
  4151. begin
  4152. case Message.HitTest of
  4153. HT_TB2k_Close: begin
  4154. GetWindowRect(Handle, R);
  4155. BR := GetDockedCloseButtonRect(
  4156. TBGetDockTypeOf(CurrentDock, Floating) = dtLeftRight);
  4157. OffsetRect(BR, R.Left, R.Top);
  4158. if CloseButtonLoop(Handle, BR, SetCloseButtonState) then
  4159. Close;
  4160. end;
  4161. HT_TB2k_Border: begin
  4162. P := ScreenToClient(SmallPointToPoint(TSmallPoint(GetMessagePos())));
  4163. if IsMovable then
  4164. BeginMoving(P.X, P.Y);
  4165. end;
  4166. else
  4167. inherited;
  4168. end;
  4169. end;
  4170. procedure TTBCustomDockableWindow.WMNCLButtonDblClk(var Message: TWMNCLButtonDblClk);
  4171. begin
  4172. if Message.HitTest = HT_TB2k_Border then begin
  4173. if IsMovable then
  4174. DoubleClick;
  4175. end
  4176. else
  4177. inherited;
  4178. end;
  4179. procedure TTBCustomDockableWindow.ShowNCContextMenu(const Pos: TSmallPoint);
  4180. {$IFNDEF JR_D5}
  4181. { Note: this is identical to TControl.CheckMenuPopup (from Delphi 4),
  4182. except where noted.
  4183. TControl.CheckMenuPopup is unfortunately 'private', so it can't be called
  4184. outside of the Controls unit. }
  4185. procedure CheckMenuPopup;
  4186. var
  4187. Control: TControl;
  4188. PopupMenu: TPopupMenu;
  4189. begin
  4190. if csDesigning in ComponentState then Exit;
  4191. Control := Self;
  4192. while Control <> nil do
  4193. begin
  4194. { Added TControlAccess cast because GetPopupMenu is 'protected' }
  4195. PopupMenu := TControlAccess(Control).GetPopupMenu;
  4196. if (PopupMenu <> nil) then
  4197. begin
  4198. if not PopupMenu.AutoPopup then Exit;
  4199. SendCancelMode(nil);
  4200. PopupMenu.PopupComponent := Control;
  4201. { Changed the following. LPARAM of WM_NCRBUTTONUP is in screen
  4202. coordinates, not client coordinates }
  4203. {with ClientToScreen(SmallPointToPoint(Pos)) do
  4204. PopupMenu.Popup(X, Y);}
  4205. PopupMenu.Popup(Pos.X, Pos.Y);
  4206. Exit;
  4207. end;
  4208. Control := Control.Parent;
  4209. end;
  4210. end;
  4211. {$ENDIF}
  4212. begin
  4213. {$IFDEF JR_D5}
  4214. { Delphi 5 and later use the WM_CONTEXTMENU message for popup menus }
  4215. SendMessage(Handle, WM_CONTEXTMENU, 0, LPARAM(Pos));
  4216. {$ELSE}
  4217. CheckMenuPopup;
  4218. {$ENDIF}
  4219. end;
  4220. procedure TTBCustomDockableWindow.WMNCRButtonUp(var Message: TWMNCRButtonUp);
  4221. begin
  4222. ShowNCContextMenu(TSmallPoint(TMessage(Message).LParam));
  4223. end;
  4224. {$IFDEF JR_D5}
  4225. procedure TTBCustomDockableWindow.WMContextMenu(var Message: TWMContextMenu);
  4226. { Unfortunately TControl.WMContextMenu ignores clicks in the non-client area.
  4227. On docked toolbars, we need right clicks on the border, part of the
  4228. non-client area, to display the popup menu. The only way I see to have it do
  4229. that is to create a new version of WMContextMenu specifically for the
  4230. non-client area, and that is what this method is.
  4231. Note: This is identical to Delphi 5's TControl.WMContextMenu, except where
  4232. noted. }
  4233. var
  4234. Pt, Temp: TPoint;
  4235. Handled: Boolean;
  4236. PopupMenu: TPopupMenu;
  4237. begin
  4238. { Added 'inherited;' here }
  4239. inherited;
  4240. if Message.Result <> 0 then Exit;
  4241. if csDesigning in ComponentState then Exit;
  4242. Pt := SmallPointToPoint(Message.Pos);
  4243. if Pt.X < 0 then
  4244. Temp := Pt
  4245. else
  4246. begin
  4247. Temp := ScreenToClient(Pt);
  4248. { Changed the following. We're only interested in the non-client area }
  4249. {if not PtInRect(ClientRect, Temp) then}
  4250. if PtInRect(ClientRect, Temp) then
  4251. begin
  4252. {inherited;}
  4253. Exit;
  4254. end;
  4255. end;
  4256. Handled := False;
  4257. DoContextPopup(Temp, Handled);
  4258. Message.Result := Ord(Handled);
  4259. if Handled then Exit;
  4260. PopupMenu := GetPopupMenu;
  4261. if (PopupMenu <> nil) and PopupMenu.AutoPopup then
  4262. begin
  4263. SendCancelMode(nil);
  4264. PopupMenu.PopupComponent := Self;
  4265. if Pt.X < 0 then
  4266. Pt := ClientToScreen(Point(0,0));
  4267. PopupMenu.Popup(Pt.X, Pt.Y);
  4268. Message.Result := 1;
  4269. end;
  4270. if Message.Result = 0 then
  4271. inherited;
  4272. end;
  4273. {$ENDIF}
  4274. procedure TTBCustomDockableWindow.GetMinShrinkSize(var AMinimumSize: Integer);
  4275. begin
  4276. end;
  4277. function TTBCustomDockableWindow.GetFloatingWindowParentClass: TTBFloatingWindowParentClass;
  4278. begin
  4279. Result := TTBFloatingWindowParent;
  4280. end;
  4281. procedure TTBCustomDockableWindow.GetMinMaxSize(var AMinClientWidth,
  4282. AMinClientHeight, AMaxClientWidth, AMaxClientHeight: Integer);
  4283. begin
  4284. end;
  4285. function TTBCustomDockableWindow.GetShrinkMode: TTBShrinkMode;
  4286. begin
  4287. Result := tbsmNone;
  4288. end;
  4289. procedure TTBCustomDockableWindow.ResizeBegin;
  4290. begin
  4291. end;
  4292. procedure TTBCustomDockableWindow.ResizeTrack(var Rect: TRect; const OrigRect: TRect);
  4293. begin
  4294. end;
  4295. procedure TTBCustomDockableWindow.ResizeTrackAccept;
  4296. begin
  4297. end;
  4298. procedure TTBCustomDockableWindow.ResizeEnd;
  4299. begin
  4300. end;
  4301. procedure TTBCustomDockableWindow.BeginSizing(const ASizeHandle: TTBSizeHandle);
  4302. var
  4303. UseSmoothDrag, DragX, DragY, ReverseX, ReverseY: Boolean;
  4304. MinWidth, MinHeight, MaxWidth, MaxHeight: Integer;
  4305. DragRect, OrigDragRect: TRect;
  4306. ScreenDC: HDC;
  4307. OrigPos, OldPos: TPoint;
  4308. procedure DoResize;
  4309. begin
  4310. BeginUpdate;
  4311. try
  4312. ResizeTrackAccept;
  4313. Parent.BoundsRect := DragRect;
  4314. SetBounds(Left, Top, Parent.ClientWidth, Parent.ClientHeight);
  4315. finally
  4316. EndUpdate;
  4317. end;
  4318. { Make sure it doesn't go completely off the screen }
  4319. MoveOnScreen(True);
  4320. end;
  4321. procedure MouseMoved;
  4322. var
  4323. Pos: TPoint;
  4324. OldDragRect: TRect;
  4325. begin
  4326. GetCursorPos(Pos);
  4327. { It needs to check if the cursor actually moved since last time. This is
  4328. because a call to LockWindowUpdate (apparently) generates a mouse move
  4329. message even when mouse hasn't moved. }
  4330. if (Pos.X = OldPos.X) and (Pos.Y = OldPos.Y) then Exit;
  4331. OldPos := Pos;
  4332. OldDragRect := DragRect;
  4333. DragRect := OrigDragRect;
  4334. if DragX then begin
  4335. if not ReverseX then Inc(DragRect.Right, Pos.X-OrigPos.X)
  4336. else Inc(DragRect.Left, Pos.X-OrigPos.X);
  4337. end;
  4338. if DragY then begin
  4339. if not ReverseY then Inc(DragRect.Bottom, Pos.Y-OrigPos.Y)
  4340. else Inc(DragRect.Top, Pos.Y-OrigPos.Y);
  4341. end;
  4342. if DragRect.Right-DragRect.Left < MinWidth then begin
  4343. if not ReverseX then DragRect.Right := DragRect.Left + MinWidth
  4344. else DragRect.Left := DragRect.Right - MinWidth;
  4345. end;
  4346. if (MaxWidth > 0) and (DragRect.Right-DragRect.Left > MaxWidth) then begin
  4347. if not ReverseX then DragRect.Right := DragRect.Left + MaxWidth
  4348. else DragRect.Left := DragRect.Right - MaxWidth;
  4349. end;
  4350. if DragRect.Bottom-DragRect.Top < MinHeight then begin
  4351. if not ReverseY then DragRect.Bottom := DragRect.Top + MinHeight
  4352. else DragRect.Top := DragRect.Bottom - MinHeight;
  4353. end;
  4354. if (MaxHeight > 0) and (DragRect.Bottom-DragRect.Top > MaxHeight) then begin
  4355. if not ReverseY then DragRect.Bottom := DragRect.Top + MaxHeight
  4356. else DragRect.Top := DragRect.Bottom - MaxHeight;
  4357. end;
  4358. ResizeTrack(DragRect, OrigDragRect);
  4359. if not UseSmoothDrag then
  4360. DrawDraggingOutline(ScreenDC, @DragRect, @OldDragRect, False, False)
  4361. else
  4362. DoResize;
  4363. end;
  4364. var
  4365. Accept: Boolean;
  4366. Msg: TMsg;
  4367. R: TRect;
  4368. begin
  4369. if not Floating then Exit;
  4370. Accept := False;
  4371. UseSmoothDrag := FSmoothDrag;
  4372. MinWidth := 0;
  4373. MinHeight := 0;
  4374. MaxWidth := 0;
  4375. MaxHeight := 0;
  4376. GetMinMaxSize(MinWidth, MinHeight, MaxWidth, MaxHeight);
  4377. Inc(MinWidth, Parent.Width-Width);
  4378. Inc(MinHeight, Parent.Height-Height);
  4379. if MaxWidth > 0 then
  4380. Inc(MaxWidth, Parent.Width-Width);
  4381. if MaxHeight > 0 then
  4382. Inc(MaxHeight, Parent.Height-Height);
  4383. DragX := ASizeHandle in [twshLeft, twshRight, twshTopLeft, twshTopRight,
  4384. twshBottomLeft, twshBottomRight];
  4385. ReverseX := ASizeHandle in [twshLeft, twshTopLeft, twshBottomLeft];
  4386. DragY := ASizeHandle in [twshTop, twshTopLeft, twshTopRight, twshBottom,
  4387. twshBottomLeft, twshBottomRight];
  4388. ReverseY := ASizeHandle in [twshTop, twshTopLeft, twshTopRight];
  4389. ResizeBegin(ASizeHandle);
  4390. try
  4391. { Before locking, make sure all pending paint messages are processed }
  4392. ProcessPaintMessages;
  4393. if not UseSmoothDrag then begin
  4394. { This uses LockWindowUpdate to suppress all window updating so the
  4395. dragging outlines doesn't sometimes get garbled. (This is safe, and in
  4396. fact, is the main purpose of the LockWindowUpdate function)
  4397. IMPORTANT! While debugging you might want to enable the 'TB2Dock_DisableLock'
  4398. conditional define (see top of the source code). }
  4399. {$IFNDEF TB2Dock_DisableLock}
  4400. LockWindowUpdate(GetDesktopWindow);
  4401. {$ENDIF}
  4402. { Get a DC of the entire screen. Works around the window update lock
  4403. by specifying DCX_LOCKWINDOWUPDATE. }
  4404. ScreenDC := GetDCEx(GetDesktopWindow, 0,
  4405. DCX_LOCKWINDOWUPDATE or DCX_CACHE or DCX_WINDOW);
  4406. end
  4407. else
  4408. ScreenDC := 0;
  4409. try
  4410. SetCapture(Handle);
  4411. if (tbdsResizeClipCursor in FDockableWindowStyles) and
  4412. not UsingMultipleMonitors then begin
  4413. R := GetRectOfPrimaryMonitor(False);
  4414. ClipCursor(@R);
  4415. end;
  4416. { Initialize }
  4417. OrigDragRect := Parent.BoundsRect;
  4418. DragRect := OrigDragRect;
  4419. if not UseSmoothDrag then
  4420. DrawDraggingOutline(ScreenDC, @DragRect, nil, False, False);
  4421. GetCursorPos(OrigPos);
  4422. OldPos := OrigPos;
  4423. { Stay in message loop until capture is lost. Capture is removed either
  4424. by this procedure manually doing it, or by an outside influence (like
  4425. a message box or menu popping up) }
  4426. while GetCapture = Handle do begin
  4427. case Integer(GetMessage(Msg, 0, 0, 0)) of
  4428. -1: Break; { if GetMessage failed }
  4429. 0: begin
  4430. { Repost WM_QUIT messages }
  4431. PostQuitMessage(Msg.WParam);
  4432. Break;
  4433. end;
  4434. end;
  4435. case Msg.Message of
  4436. WM_KEYDOWN, WM_KEYUP:
  4437. { Ignore all keystrokes while sizing except for Escape }
  4438. if Msg.WParam = VK_ESCAPE then
  4439. Break;
  4440. WM_MOUSEMOVE:
  4441. { Note to self: WM_MOUSEMOVE messages should never be dispatched
  4442. here to ensure no hints get shown during the drag process }
  4443. MouseMoved;
  4444. WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
  4445. { Make sure it doesn't begin another loop }
  4446. Break;
  4447. WM_LBUTTONUP: begin
  4448. Accept := True;
  4449. Break;
  4450. end;
  4451. WM_RBUTTONDOWN..WM_MBUTTONDBLCLK:
  4452. { Ignore all other mouse up/down messages }
  4453. ;
  4454. else
  4455. TranslateMessage(Msg);
  4456. DispatchMessage(Msg);
  4457. end;
  4458. end;
  4459. finally
  4460. { Since it sometimes breaks out of the loop without capture being
  4461. released }
  4462. if GetCapture = Handle then
  4463. ReleaseCapture;
  4464. ClipCursor(nil);
  4465. if not UseSmoothDrag then begin
  4466. { Hide dragging outline. Since NT will release a window update lock if
  4467. another thread comes to the foreground, it has to release the DC
  4468. and get a new one for erasing the dragging outline. Otherwise,
  4469. the DrawDraggingOutline appears to have no effect when this happens. }
  4470. ReleaseDC(GetDesktopWindow, ScreenDC);
  4471. ScreenDC := GetDCEx(GetDesktopWindow, 0,
  4472. DCX_LOCKWINDOWUPDATE or DCX_CACHE or DCX_WINDOW);
  4473. DrawDraggingOutline(ScreenDC, nil, @DragRect, False, False);
  4474. ReleaseDC(GetDesktopWindow, ScreenDC);
  4475. { Release window update lock }
  4476. {$IFNDEF TB2Dock_DisableLock}
  4477. LockWindowUpdate(0);
  4478. {$ENDIF}
  4479. end;
  4480. end;
  4481. if not UseSmoothDrag and Accept then
  4482. DoResize;
  4483. finally
  4484. ResizeEnd;
  4485. end;
  4486. end;
  4487. procedure TTBCustomDockableWindow.DoDockChangingHidden(NewFloating: Boolean;
  4488. DockingTo: TTBDock);
  4489. begin
  4490. if not(csDestroying in ComponentState) and Assigned(FOnDockChangingHidden) then
  4491. FOnDockChangingHidden(Self, NewFloating, DockingTo);
  4492. end;
  4493. { TTBCustomDockableWindow - property access methods }
  4494. function TTBCustomDockableWindow.GetNonClientWidth: Integer;
  4495. begin
  4496. Result := CalcNCSizes.X;
  4497. end;
  4498. function TTBCustomDockableWindow.GetNonClientHeight: Integer;
  4499. begin
  4500. Result := CalcNCSizes.Y;
  4501. end;
  4502. function TTBCustomDockableWindow.IsLastDockStored: Boolean;
  4503. begin
  4504. Result := FCurrentDock = nil; {}{should this be changed to 'Floating'?}
  4505. end;
  4506. function TTBCustomDockableWindow.IsWidthAndHeightStored: Boolean;
  4507. begin
  4508. Result := (CurrentDock = nil) and not Floating;
  4509. end;
  4510. procedure TTBCustomDockableWindow.SetCloseButton(Value: Boolean);
  4511. begin
  4512. if FCloseButton <> Value then begin
  4513. FCloseButton := Value;
  4514. { Update the close button's visibility }
  4515. if Parent is TTBFloatingWindowParent then
  4516. TTBFloatingWindowParent(Parent).RedrawNCArea([twrdCaption, twrdCloseButton]);
  4517. end;
  4518. end;
  4519. procedure TTBCustomDockableWindow.SetCloseButtonWhenDocked(Value: Boolean);
  4520. begin
  4521. if FCloseButtonWhenDocked <> Value then begin
  4522. FCloseButtonWhenDocked := Value;
  4523. if Docked then
  4524. RecalcNCArea(Self);
  4525. end;
  4526. end;
  4527. procedure TTBCustomDockableWindow.SetDefaultDock(Value: TTBDock);
  4528. begin
  4529. if FDefaultDock <> Value then begin
  4530. FDefaultDock := Value;
  4531. if Assigned(Value) then
  4532. Value.FreeNotification(Self);
  4533. end;
  4534. end;
  4535. procedure TTBCustomDockableWindow.SetCurrentDock(Value: TTBDock);
  4536. begin
  4537. if not(csLoading in ComponentState) then begin
  4538. if Assigned(Value) then
  4539. Parent := Value
  4540. else
  4541. Parent := TBValidToolWindowParentForm(Self);
  4542. end;
  4543. end;
  4544. procedure TTBCustomDockableWindow.SetDockPos(Value: Integer);
  4545. begin
  4546. FDockPos := Value;
  4547. if Docked then
  4548. CurrentDock.ArrangeToolbars;
  4549. end;
  4550. procedure TTBCustomDockableWindow.SetDockRow(Value: Integer);
  4551. begin
  4552. FDockRow := Value;
  4553. if Docked then
  4554. CurrentDock.ArrangeToolbars;
  4555. end;
  4556. procedure TTBCustomDockableWindow.SetAutoResize(Value: Boolean);
  4557. begin
  4558. if FAutoResize <> Value then begin
  4559. FAutoResize := Value;
  4560. if Value then
  4561. Arrange;
  4562. end;
  4563. end;
  4564. procedure TTBCustomDockableWindow.SetBorderStyle(Value: TBorderStyle);
  4565. begin
  4566. if FBorderStyle <> Value then begin
  4567. FBorderStyle := Value;
  4568. if Docked then
  4569. RecalcNCArea(Self);
  4570. end;
  4571. end;
  4572. procedure TTBCustomDockableWindow.SetDragHandleStyle(Value: TTBDragHandleStyle);
  4573. begin
  4574. if FDragHandleStyle <> Value then begin
  4575. FDragHandleStyle := Value;
  4576. if Docked then
  4577. RecalcNCArea(Self);
  4578. end;
  4579. end;
  4580. procedure TTBCustomDockableWindow.SetFloating(Value: Boolean);
  4581. var
  4582. ParentFrm: TTBCustomForm;
  4583. NewFloatParent: TTBFloatingWindowParent;
  4584. begin
  4585. if FFloating <> Value then begin
  4586. if Value and not(csDesigning in ComponentState) then begin
  4587. ParentFrm := TBValidToolWindowParentForm(Self);
  4588. if (FFloatParent = nil) or (FFloatParent.FParentForm <> ParentFrm) then begin
  4589. NewFloatParent := GetFloatingWindowParentClass.Create(nil);
  4590. try
  4591. with NewFloatParent do begin
  4592. TWinControl(FParentForm) := ParentFrm;
  4593. FDockableWindow := Self;
  4594. Name := Format('NBFloatingWindowParent_%.8x', [Longint(NewFloatParent)]);
  4595. { ^ Must assign a unique name. In previous versions, reading in
  4596. components at run-time that had no name caused them to get assigned
  4597. names like "_1" because a component with no name -- the
  4598. TTBFloatingWindowParent form -- already existed. }
  4599. Caption := Self.Caption;
  4600. BorderStyle := bsToolWindow;
  4601. SetBounds(0, 0, (Width-ClientWidth) + Self.ClientWidth,
  4602. (Height-ClientHeight) + Self.ClientHeight);
  4603. ShowHint := True;
  4604. Visible := True;
  4605. end;
  4606. except
  4607. NewFloatParent.Free;
  4608. raise;
  4609. end;
  4610. FFloatParent := NewFloatParent;
  4611. end;
  4612. ParentFrm.FreeNotification(Self);
  4613. Parent := FFloatParent;
  4614. SetBounds(0, 0, Width, Height);
  4615. end
  4616. else
  4617. Parent := TBValidToolWindowParentForm(Self);
  4618. end;
  4619. end;
  4620. procedure TTBCustomDockableWindow.SetFloatingMode(Value: TTBFloatingMode);
  4621. begin
  4622. if FFloatingMode <> Value then begin
  4623. FFloatingMode := Value;
  4624. if HandleAllocated then
  4625. Perform(CM_SHOWINGCHANGED, 0, 0);
  4626. end;
  4627. end;
  4628. procedure TTBCustomDockableWindow.SetFloatingPosition(Value: TPoint);
  4629. begin
  4630. FFloatingPosition := Value;
  4631. if Floating and Assigned(Parent) then
  4632. Parent.SetBounds(Value.X, Value.Y, Parent.Width, Parent.Height);
  4633. end;
  4634. procedure TTBCustomDockableWindow.SetFullSize(Value: Boolean);
  4635. begin
  4636. if FFullSize <> Value then begin
  4637. FFullSize := Value;
  4638. if Docked then
  4639. CurrentDock.ArrangeToolbars;
  4640. end;
  4641. end;
  4642. procedure TTBCustomDockableWindow.SetLastDock(Value: TTBDock);
  4643. begin
  4644. if FUseLastDock and Assigned(FCurrentDock) then
  4645. { When docked, LastDock must be equal to DockedTo }
  4646. Value := FCurrentDock;
  4647. if FLastDock <> Value then begin
  4648. if Assigned(FLastDock) and (FLastDock <> Parent) then
  4649. FLastDock.ChangeDockList(False, Self);
  4650. FLastDock := Value;
  4651. if Assigned(Value) then begin
  4652. FUseLastDock := True;
  4653. Value.FreeNotification(Self);
  4654. Value.ChangeDockList(True, Self);
  4655. end;
  4656. end;
  4657. end;
  4658. procedure TTBCustomDockableWindow.SetResizable(Value: Boolean);
  4659. begin
  4660. if FResizable <> Value then begin
  4661. FResizable := Value;
  4662. if Floating and (Parent is TTBFloatingWindowParent) then begin
  4663. { Recreate the window handle because Resizable affects whether the
  4664. tool window is created with a WS_THICKFRAME style }
  4665. TTBFloatingWindowParent(Parent).RecreateWnd;
  4666. end;
  4667. end;
  4668. end;
  4669. procedure TTBCustomDockableWindow.SetShowCaption(Value: Boolean);
  4670. begin
  4671. if FShowCaption <> Value then begin
  4672. FShowCaption := Value;
  4673. if Floating then begin
  4674. { Recalculate FloatingWindowParent's NC area, and resize the toolbar
  4675. accordingly }
  4676. RecalcNCArea(Parent);
  4677. Arrange;
  4678. end;
  4679. end;
  4680. end;
  4681. procedure TTBCustomDockableWindow.SetStretch(Value: Boolean);
  4682. begin
  4683. if FStretch <> Value then begin
  4684. FStretch := Value;
  4685. if Docked then
  4686. CurrentDock.ArrangeToolbars;
  4687. end;
  4688. end;
  4689. procedure TTBCustomDockableWindow.SetUseLastDock(Value: Boolean);
  4690. begin
  4691. if FUseLastDock <> Value then begin
  4692. FUseLastDock := Value;
  4693. if not Value then
  4694. LastDock := nil
  4695. else
  4696. LastDock := FCurrentDock;
  4697. end;
  4698. end;
  4699. (*function TTBCustomDockableWindow.GetVersion: TToolbar97Version;
  4700. begin
  4701. Result := Toolbar97VersionPropText;
  4702. end;
  4703. procedure TTBCustomDockableWindow.SetVersion(const Value: TToolbar97Version);
  4704. begin
  4705. { write method required for the property to show up in Object Inspector }
  4706. end;*)
  4707. {$IFNDEF MPEXCLUDE}
  4708. { TTBBackground }
  4709. type
  4710. PNotifyEvent = ^TNotifyEvent;
  4711. constructor TTBBackground.Create(AOwner: TComponent);
  4712. begin
  4713. inherited;
  4714. FBkColor := clBtnFace;
  4715. FBitmap := TBitmap.Create;
  4716. FBitmap.OnChange := BitmapChanged;
  4717. end;
  4718. destructor TTBBackground.Destroy;
  4719. var
  4720. I: Integer;
  4721. begin
  4722. inherited;
  4723. FBitmapCache.Free;
  4724. FBitmap.Free;
  4725. if Assigned(FNotifyList) then begin
  4726. for I := FNotifyList.Count-1 downto 0 do
  4727. Dispose(PNotifyEvent(FNotifyList[I]));
  4728. FNotifyList.Free;
  4729. end;
  4730. end;
  4731. procedure TTBBackground.BitmapChanged(Sender: TObject);
  4732. var
  4733. I: Integer;
  4734. begin
  4735. { Erase the cache and notify }
  4736. FBitmapCache.Free;
  4737. FBitmapCache := nil;
  4738. if Assigned(FNotifyList) then
  4739. for I := 0 to FNotifyList.Count-1 do
  4740. PNotifyEvent(FNotifyList[I])^(Self);
  4741. end;
  4742. procedure TTBBackground.Draw(DC: HDC; const DrawRect: TRect);
  4743. var
  4744. UseBmp: TBitmap;
  4745. R2: TRect;
  4746. SaveIndex: Integer;
  4747. DC2: HDC;
  4748. Brush: HBRUSH;
  4749. P: TPoint;
  4750. begin
  4751. if FBitmapCache = nil then begin
  4752. FBitmapCache := TBitmap.Create;
  4753. FBitmapCache.Palette := CopyPalette(FBitmap.Palette);
  4754. FBitmapCache.Width := FBitmap.Width;
  4755. FBitmapCache.Height := FBitmap.Height;
  4756. if not FTransparent then begin
  4757. { Copy from a possible DIB to our DDB }
  4758. BitBlt(FBitmapCache.Canvas.Handle, 0, 0, FBitmapCache.Width,
  4759. FBitmapCache.Height, FBitmap.Canvas.Handle, 0, 0, SRCCOPY);
  4760. end
  4761. else begin
  4762. with FBitmapCache do begin
  4763. Canvas.Brush.Color := FBkColor;
  4764. R2 := Rect(0, 0, Width, Height);
  4765. Canvas.BrushCopy(R2, FBitmap, R2,
  4766. FBitmap.Canvas.Pixels[0, Height-1] or $02000000);
  4767. end;
  4768. end;
  4769. FBitmap.Dormant;
  4770. end;
  4771. UseBmp := FBitmapCache;
  4772. DC2 := 0;
  4773. SaveIndex := SaveDC(DC);
  4774. try
  4775. if UseBmp.Palette <> 0 then begin
  4776. SelectPalette(DC, UseBmp.Palette, True);
  4777. RealizePalette(DC);
  4778. end;
  4779. { Note: versions of Toolbar97 prior to 1.68 used 'UseBmp.Canvas.Handle'
  4780. instead of DC2 in the BitBlt call. This was changed because there
  4781. seems to be a bug in D2/BCB1's Graphics.pas: if you called
  4782. <dockname>.Background.LoadFromFile(<filename>) twice the background
  4783. would not be shown. }
  4784. if (UseBmp.Width = 8) and (UseBmp.Height = 8) then begin
  4785. { Use pattern brushes to draw 8x8 bitmaps.
  4786. Note: Win9x can't use bitmaps <8x8 in size for pattern brushes }
  4787. Brush := CreatePatternBrush(UseBmp.Handle);
  4788. GetWindowOrgEx(DC, P);
  4789. SetBrushOrgEx(DC, DrawRect.Left - P.X, DrawRect.Top - P.Y, nil);
  4790. FillRect(DC, DrawRect, Brush);
  4791. DeleteObject(Brush);
  4792. end
  4793. else begin
  4794. { BitBlt is faster than pattern brushes on large bitmaps }
  4795. DC2 := CreateCompatibleDC(DC);
  4796. SelectObject(DC2, UseBmp.Handle);
  4797. R2 := DrawRect;
  4798. while R2.Left < R2.Right do begin
  4799. while R2.Top < R2.Bottom do begin
  4800. BitBlt(DC, R2.Left, R2.Top, UseBmp.Width, UseBmp.Height,
  4801. DC2, 0, 0, SRCCOPY);
  4802. Inc(R2.Top, UseBmp.Height);
  4803. end;
  4804. R2.Top := DrawRect.Top;
  4805. Inc(R2.Left, UseBmp.Width);
  4806. end;
  4807. end;
  4808. finally
  4809. if DC2 <> 0 then
  4810. DeleteDC(DC2);
  4811. { Restore the palette and brush origin back }
  4812. RestoreDC(DC, SaveIndex);
  4813. end;
  4814. end;
  4815. function TTBBackground.GetPalette: HPALETTE;
  4816. begin
  4817. Result := FBitmap.Palette;
  4818. end;
  4819. procedure TTBBackground.SysColorChanged;
  4820. begin
  4821. if FTransparent and (FBkColor < 0) then
  4822. BitmapChanged(nil);
  4823. end;
  4824. function TTBBackground.UsingBackground: Boolean;
  4825. begin
  4826. Result := (FBitmap.Width <> 0) and (FBitmap.Height <> 0);
  4827. end;
  4828. procedure TTBBackground.RegisterChanges(Proc: TNotifyEvent);
  4829. var
  4830. I: Integer;
  4831. P: PNotifyEvent;
  4832. begin
  4833. if FNotifyList = nil then
  4834. FNotifyList := TList.Create;
  4835. for I := 0 to FNotifyList.Count-1 do begin
  4836. P := FNotifyList[I];
  4837. if (TMethod(P^).Code = TMethod(Proc).Code) and
  4838. (TMethod(P^).Data = TMethod(Proc).Data) then
  4839. Exit;
  4840. end;
  4841. FNotifyList.Expand;
  4842. New(P);
  4843. P^ := Proc;
  4844. FNotifyList.Add(P);
  4845. end;
  4846. procedure TTBBackground.UnregisterChanges(Proc: TNotifyEvent);
  4847. var
  4848. I: Integer;
  4849. P: PNotifyEvent;
  4850. begin
  4851. if FNotifyList = nil then
  4852. Exit;
  4853. for I := 0 to FNotifyList.Count-1 do begin
  4854. P := FNotifyList[I];
  4855. if (TMethod(P^).Code = TMethod(Proc).Code) and
  4856. (TMethod(P^).Data = TMethod(Proc).Data) then begin
  4857. FNotifyList.Delete(I);
  4858. Dispose(P);
  4859. Break;
  4860. end;
  4861. end;
  4862. end;
  4863. procedure TTBBackground.SetBkColor(Value: TColor);
  4864. begin
  4865. if FBkColor <> Value then begin
  4866. FBkColor := Value;
  4867. if FTransparent then
  4868. BitmapChanged(nil);
  4869. end;
  4870. end;
  4871. procedure TTBBackground.SetBitmap(Value: TBitmap);
  4872. begin
  4873. FBitmap.Assign(Value);
  4874. end;
  4875. procedure TTBBackground.SetTransparent(Value: Boolean);
  4876. begin
  4877. if FTransparent <> Value then begin
  4878. FTransparent := Value;
  4879. BitmapChanged(nil);
  4880. end;
  4881. end;
  4882. {$ENDIF}
  4883. { Global procedures }
  4884. procedure TBCustomLoadPositions(const OwnerComponent: TComponent;
  4885. const ReadIntProc: TTBPositionReadIntProc;
  4886. const ReadStringProc: TTBPositionReadStringProc; const ExtraData: Pointer);
  4887. var
  4888. Rev: Integer;
  4889. function FindDock(AName: String): TTBDock;
  4890. var
  4891. I: Integer;
  4892. begin
  4893. Result := nil;
  4894. for I := 0 to OwnerComponent.ComponentCount-1 do
  4895. if (OwnerComponent.Components[I] is TTBDock) and
  4896. (CompareText(OwnerComponent.Components[I].Name, AName) = 0) then begin
  4897. Result := TTBDock(OwnerComponent.Components[I]);
  4898. Break;
  4899. end;
  4900. end;
  4901. procedure ReadValues(const Toolbar: TTBCustomDockableWindow; const NewDock: TTBDock);
  4902. var
  4903. Pos: TPoint;
  4904. Data: TTBReadPositionData;
  4905. LastDockName: String;
  4906. ADock: TTBDock;
  4907. begin
  4908. with Toolbar do begin
  4909. DockRow := ReadIntProc(Name, rvDockRow, DockRow, ExtraData);
  4910. DockPos := ReadIntProc(Name, rvDockPos, DockPos, ExtraData);
  4911. Pos.X := ReadIntProc(Name, rvFloatLeft, 0, ExtraData);
  4912. Pos.Y := ReadIntProc(Name, rvFloatTop, 0, ExtraData);
  4913. @Data.ReadIntProc := @ReadIntProc;
  4914. @Data.ReadStringProc := @ReadStringProc;
  4915. Data.ExtraData := ExtraData;
  4916. ReadPositionData(Data);
  4917. FloatingPosition := Pos;
  4918. if Assigned(NewDock) then
  4919. Parent := NewDock
  4920. else begin
  4921. //Parent := Form;
  4922. Floating := True;
  4923. MoveOnScreen(True);
  4924. if (Rev >= 3) and FUseLastDock then begin
  4925. LastDockName := ReadStringProc(Name, rvLastDock, '', ExtraData);
  4926. if LastDockName <> '' then begin
  4927. ADock := FindDock(LastDockName);
  4928. if Assigned(ADock) then
  4929. LastDock := ADock;
  4930. end;
  4931. end;
  4932. end;
  4933. Arrange;
  4934. DoneReadingPositionData(Data);
  4935. end;
  4936. end;
  4937. var
  4938. DocksDisabled: TList;
  4939. I: Integer;
  4940. ToolWindow: TComponent;
  4941. ADock: TTBDock;
  4942. DockedToName: String;
  4943. begin
  4944. DocksDisabled := TList.Create;
  4945. try
  4946. with OwnerComponent do
  4947. for I := 0 to ComponentCount-1 do
  4948. if Components[I] is TTBDock then begin
  4949. TTBDock(Components[I]).BeginUpdate;
  4950. DocksDisabled.Add(Components[I]);
  4951. end;
  4952. for I := 0 to OwnerComponent.ComponentCount-1 do begin
  4953. ToolWindow := OwnerComponent.Components[I];
  4954. if ToolWindow is TTBCustomDockableWindow then
  4955. with TTBCustomDockableWindow(ToolWindow) do begin
  4956. {}{should skip over toolbars that are neither Docked nor Floating }
  4957. if Name = '' then
  4958. raise Exception.Create(STBToolWinNameNotSet);
  4959. Rev := ReadIntProc(Name, rvRev, 0, ExtraData);
  4960. if Rev = 2000 then begin
  4961. Visible := ReadIntProc(Name, rvVisible, Ord(Visible), ExtraData) <> 0;
  4962. DockedToName := ReadStringProc(Name, rvDockedTo, '', ExtraData);
  4963. if DockedToName <> '' then begin
  4964. if DockedToName <> rdDockedToFloating then begin
  4965. ADock := FindDock(DockedToName);
  4966. if (ADock <> nil) and (ADock.FAllowDrag) then
  4967. ReadValues(TTBCustomDockableWindow(ToolWindow), ADock);
  4968. end
  4969. else
  4970. ReadValues(TTBCustomDockableWindow(ToolWindow), nil);
  4971. end;
  4972. end;
  4973. end;
  4974. end;
  4975. finally
  4976. for I := DocksDisabled.Count-1 downto 0 do
  4977. TTBDock(DocksDisabled[I]).EndUpdate;
  4978. DocksDisabled.Free;
  4979. end;
  4980. end;
  4981. procedure TBCustomSavePositions(const OwnerComponent: TComponent;
  4982. const WriteIntProc: TTBPositionWriteIntProc;
  4983. const WriteStringProc: TTBPositionWriteStringProc; const ExtraData: Pointer);
  4984. var
  4985. I: Integer;
  4986. N, L: String;
  4987. Data: TTBWritePositionData;
  4988. begin
  4989. for I := 0 to OwnerComponent.ComponentCount-1 do
  4990. if OwnerComponent.Components[I] is TTBCustomDockableWindow then
  4991. with TTBCustomDockableWindow(OwnerComponent.Components[I]) do begin
  4992. if Name = '' then
  4993. raise Exception.Create(STBToolwinNameNotSet);
  4994. if Floating then
  4995. N := rdDockedToFloating
  4996. else if Docked then begin
  4997. if CurrentDock.FAllowDrag then begin
  4998. N := CurrentDock.Name;
  4999. if N = '' then
  5000. raise Exception.Create(STBToolwinDockedToNameNotSet);
  5001. end
  5002. else
  5003. N := '';
  5004. end
  5005. else
  5006. Continue; { skip if it's neither floating nor docked }
  5007. L := '';
  5008. if Assigned(FLastDock) then
  5009. L := FLastDock.Name;
  5010. WriteIntProc(Name, rvRev, rdCurrentRev, ExtraData);
  5011. WriteIntProc(Name, rvVisible, Ord(Visible), ExtraData);
  5012. WriteStringProc(Name, rvDockedTo, N, ExtraData);
  5013. WriteStringProc(Name, rvLastDock, L, ExtraData);
  5014. WriteIntProc(Name, rvDockRow, FDockRow, ExtraData);
  5015. WriteIntProc(Name, rvDockPos, FDockPos, ExtraData);
  5016. WriteIntProc(Name, rvFloatLeft, FFloatingPosition.X, ExtraData);
  5017. WriteIntProc(Name, rvFloatTop, FFloatingPosition.Y, ExtraData);
  5018. @Data.WriteIntProc := @WriteIntProc;
  5019. @Data.WriteStringProc := @WriteStringProc;
  5020. Data.ExtraData := ExtraData;
  5021. WritePositionData(Data);
  5022. end;
  5023. end;
  5024. type
  5025. PIniReadWriteData = ^TIniReadWriteData;
  5026. TIniReadWriteData = record
  5027. IniFile: TIniFile;
  5028. SectionNamePrefix: String;
  5029. end;
  5030. function IniReadInt(const ToolbarName, Value: String; const Default: Longint;
  5031. const ExtraData: Pointer): Longint; far;
  5032. begin
  5033. Result := PIniReadWriteData(ExtraData).IniFile.ReadInteger(
  5034. PIniReadWriteData(ExtraData).SectionNamePrefix + ToolbarName, Value, Default);
  5035. end;
  5036. function IniReadString(const ToolbarName, Value, Default: String;
  5037. const ExtraData: Pointer): String; far;
  5038. begin
  5039. Result := PIniReadWriteData(ExtraData).IniFile.ReadString(
  5040. PIniReadWriteData(ExtraData).SectionNamePrefix + ToolbarName, Value, Default);
  5041. end;
  5042. procedure IniWriteInt(const ToolbarName, Value: String; const Data: Longint;
  5043. const ExtraData: Pointer); far;
  5044. begin
  5045. PIniReadWriteData(ExtraData).IniFile.WriteInteger(
  5046. PIniReadWriteData(ExtraData).SectionNamePrefix + ToolbarName, Value, Data);
  5047. end;
  5048. procedure IniWriteString(const ToolbarName, Value, Data: String;
  5049. const ExtraData: Pointer); far;
  5050. begin
  5051. PIniReadWriteData(ExtraData).IniFile.WriteString(
  5052. PIniReadWriteData(ExtraData).SectionNamePrefix + ToolbarName, Value, Data);
  5053. end;
  5054. procedure TBIniLoadPositions(const OwnerComponent: TComponent;
  5055. const Filename, SectionNamePrefix: String);
  5056. var
  5057. Data: TIniReadWriteData;
  5058. begin
  5059. Data.IniFile := TIniFile.Create(Filename);
  5060. try
  5061. Data.SectionNamePrefix := SectionNamePrefix;
  5062. TBCustomLoadPositions(OwnerComponent, IniReadInt, IniReadString, @Data);
  5063. finally
  5064. Data.IniFile.Free;
  5065. end;
  5066. end;
  5067. procedure TBIniSavePositions(const OwnerComponent: TComponent;
  5068. const Filename, SectionNamePrefix: String);
  5069. var
  5070. Data: TIniReadWriteData;
  5071. begin
  5072. Data.IniFile := TIniFile.Create(Filename);
  5073. try
  5074. Data.SectionNamePrefix := SectionNamePrefix;
  5075. TBCustomSavePositions(OwnerComponent, IniWriteInt, IniWriteString, @Data);
  5076. finally
  5077. Data.IniFile.Free;
  5078. end;
  5079. end;
  5080. function RegReadInt(const ToolbarName, Value: String; const Default: Longint;
  5081. const ExtraData: Pointer): Longint; far;
  5082. begin
  5083. Result := TRegIniFile(ExtraData).ReadInteger(ToolbarName, Value, Default);
  5084. end;
  5085. function RegReadString(const ToolbarName, Value, Default: String;
  5086. const ExtraData: Pointer): String; far;
  5087. begin
  5088. Result := TRegIniFile(ExtraData).ReadString(ToolbarName, Value, Default);
  5089. end;
  5090. procedure RegWriteInt(const ToolbarName, Value: String; const Data: Longint;
  5091. const ExtraData: Pointer); far;
  5092. begin
  5093. TRegIniFile(ExtraData).WriteInteger(ToolbarName, Value, Data);
  5094. end;
  5095. procedure RegWriteString(const ToolbarName, Value, Data: String;
  5096. const ExtraData: Pointer); far;
  5097. begin
  5098. TRegIniFile(ExtraData).WriteString(ToolbarName, Value, Data);
  5099. end;
  5100. procedure TBRegLoadPositions(const OwnerComponent: TComponent;
  5101. const RootKey: DWORD; const BaseRegistryKey: String);
  5102. var
  5103. Reg: TRegIniFile;
  5104. begin
  5105. Reg := TRegIniFile.Create('');
  5106. try
  5107. Reg.RootKey := RootKey;
  5108. Reg.OpenKey(BaseRegistryKey, True); { assigning to RootKey resets the current key }
  5109. TBCustomLoadPositions(OwnerComponent, RegReadInt, RegReadString, Reg);
  5110. finally
  5111. Reg.Free;
  5112. end;
  5113. end;
  5114. procedure TBRegSavePositions(const OwnerComponent: TComponent;
  5115. const RootKey: DWORD; const BaseRegistryKey: String);
  5116. var
  5117. Reg: TRegIniFile;
  5118. begin
  5119. Reg := TRegIniFile.Create('');
  5120. try
  5121. Reg.RootKey := RootKey;
  5122. Reg.OpenKey(BaseRegistryKey, True); { assigning to RootKey resets the current key }
  5123. TBCustomSavePositions(OwnerComponent, RegWriteInt, RegWriteString, Reg);
  5124. finally
  5125. Reg.Free;
  5126. end;
  5127. end;
  5128. end.