CnDockSupportControl.pas 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. {*******************************************************}
  21. { }
  22. { 停靠的基础控件 }
  23. { CnDockSupportControl 单元 }
  24. { }
  25. { 版权 (C) 2002,2003 鲁小班 }
  26. { }
  27. {*******************************************************}
  28. unit CnDockSupportControl;
  29. {* |<PRE>
  30. ================================================================================
  31. * 软件名称:不可视工具组件包停靠单元
  32. * 单元名称:停靠的基础控件单元
  33. * 单元作者:CnPack开发组 周益波(鲁小班)
  34. * 备 注:本单元由原作者授权CnPack开发组移植,已保留原作者版权信息
  35. * 开发平台:
  36. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7
  37. * 本 地 化:该单元中的字符串均符合本地化处理方式
  38. * 单元标识:$Id$
  39. * 修改记录:2007.07.13 V1.0
  40. * 移植单元
  41. ================================================================================
  42. |</PRE>}
  43. interface
  44. {$I CnPack.inc}
  45. uses Messages, Windows, SysUtils, CommCtrl, Controls, Forms, Classes, ComCtrls,
  46. Graphics, ImgList, ExtCtrls, CnDockHashTable, CnDockTree;
  47. type
  48. TCnDragDockObject = class(TObject)
  49. private
  50. FMouseDeltaX: Double;
  51. FMouseDeltaY: Double;
  52. FControl: TControl;
  53. FDragTarget: Pointer;
  54. FDragPos: TPoint;
  55. FDropOnControl: TControl;
  56. FDropAlign: TAlign;
  57. FDragHandle: HWND;
  58. FDragTargetPos: TPoint;
  59. FCancelling: Boolean;
  60. FFloating: Boolean;
  61. FFrameWidth: Integer;
  62. FBrush: TBrush;
  63. FCtrlDown: Boolean;
  64. procedure SetBrush(const Value: TBrush);
  65. procedure SetDropAlign(const Value: TAlign);
  66. procedure SetDropOnControl(const Value: TControl);
  67. function GetTargetControl: TWinControl;
  68. procedure SetTargetControl(const Value: TWinControl);
  69. protected
  70. procedure DefaultDockImage(Erase: Boolean); virtual;
  71. procedure DrawDragRect(DoErase: Boolean); virtual;
  72. procedure GetBrush_PenSize_DrawRect(
  73. var ABrush: TBrush; var PenSize: Integer; var DrawRect: TRect; Erase: Boolean); virtual;
  74. function GetFrameWidth: Integer; virtual;
  75. procedure SetFrameWidth(const Value: Integer); virtual;
  76. procedure MouseMsg(var Msg: TMessage); virtual;
  77. function CanLeave(NewTarget: TWinControl): Boolean; virtual;
  78. public
  79. DockRect: TRect;
  80. EraseDockRect: TRect;
  81. constructor Create(AControl: TControl); virtual;
  82. destructor Destroy; override;
  83. procedure AdjustDockRect(var ARect: TRect); virtual;
  84. { ------------------------------------------------------------------------ }
  85. function Capture: HWND;
  86. { 查找鼠标位置的控件句柄 }
  87. function DragFindWindow(const Pos: TPoint): HWND; virtual;
  88. procedure ReleaseCapture(Handle: HWND);
  89. procedure EndDrag(Target: TObject; X, Y: Integer); virtual;
  90. procedure Finished(Target: TObject; X, Y: Integer; Accepted: Boolean); virtual;
  91. function GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor; virtual;
  92. function GetDragImages: TDragImageList; virtual;
  93. { ------------------------------------------------------------------------ }
  94. procedure DrawDragDockImage; virtual;
  95. procedure EraseDragDockImage; virtual;
  96. function GetDropCtl: TControl; virtual;
  97. property MouseDeltaX: Double read FMouseDeltaX write FMouseDeltaX;
  98. property MouseDeltaY: Double read FMouseDeltaY write FMouseDeltaY;
  99. property Control: TControl read FControl write FControl;
  100. property DragTarget: Pointer read FDragTarget write FDragTarget;
  101. property DragPos: TPoint read FDragPos write FDragPos;
  102. property DropOnControl: TControl read FDropOnControl write SetDropOnControl;
  103. property DropAlign: TAlign read FDropAlign write SetDropAlign;
  104. property DragHandle: HWND read FDragHandle write FDragHandle;
  105. property DragTargetPos: TPoint read FDragTargetPos write FDragTargetPos;
  106. property Cancelling: Boolean read FCancelling write FCancelling;
  107. property Floating: Boolean read FFloating write FFloating;
  108. property FrameWidth: Integer read GetFrameWidth write SetFrameWidth;
  109. property Brush: TBrush read FBrush write SetBrush;
  110. property CtrlDown: Boolean read FCtrlDown write FCtrlDown;
  111. property TargetControl: TWinControl read GetTargetControl write SetTargetControl;
  112. end;
  113. TCnCustomDockControl = class(TCustomControl)
  114. private
  115. function GetCnDockManager: ICnDockManager;
  116. procedure SetCnDockManager(const Value: ICnDockManager);
  117. protected
  118. procedure WndProc(var Message: TMessage); override;
  119. { ------------------------------------------------------------------------ }
  120. procedure CustomStartDock(var Source: TCnDragDockObject); virtual;
  121. procedure CustomGetSiteInfo(Source: TCnDragDockObject;
  122. Client: TControl; var InfluenceRect: TRect; MousePos: TPoint;
  123. var CanDock: Boolean); virtual;
  124. procedure CustomDockOver(Source: TCnDragDockObject; X, Y: Integer;
  125. State: TDragState; var Accept: Boolean); virtual;
  126. procedure CustomPositionDockRect(Source: TCnDragDockObject; X, Y: Integer); virtual;
  127. procedure CustomDockDrop(Source: TCnDragDockObject; X, Y: Integer); virtual;
  128. procedure CustomEndDock(Target: TObject; X, Y: Integer); virtual;
  129. function CustomUnDock(Source: TCnDragDockObject; NewTarget: TWinControl; Client: TControl): Boolean; virtual;
  130. { ------------------------------------------------------------------------ }
  131. procedure CustomGetDockEdge(Source: TCnDragDockObject; MousePos: TPoint; var DropAlign: TAlign); virtual;
  132. public
  133. procedure UpdateCaption(Exclude: TControl); virtual;
  134. property DockManager;
  135. property CnDockManager: ICnDockManager read GetCnDockManager write SetCnDockManager;
  136. end;
  137. TCnCustomDockPanel = class(TCnCustomDockControl)
  138. protected
  139. function CreateDockManager: IDockManager; override;
  140. public
  141. constructor Create(AOwner: TComponent); override;
  142. destructor Destroy; override;
  143. property DockSite;
  144. end;
  145. TCnDockCustomTabControl = class;
  146. TCnDockDrawTabEvent = procedure(Control: TCnDockCustomTabControl; TabIndex: Integer;
  147. const Rect: TRect; Active: Boolean) of object;
  148. TCnDockPageControl = class;
  149. TCnDockCustomTabControl = class(TCnCustomDockControl)
  150. private
  151. FHotTrack: Boolean;
  152. FImageChangeLink: TChangeLink;
  153. FImages: TCustomImageList;
  154. FMultiLine: Boolean;
  155. FMultiSelect: Boolean;
  156. FOwnerDraw: Boolean;
  157. FRaggedRight: Boolean;
  158. FSaveTabIndex: Integer;
  159. FSaveTabs: TStringList;
  160. FScrollOpposite: Boolean;
  161. FStyle: TTabStyle;
  162. FTabPosition: TTabPosition;
  163. FTabs: TStrings;
  164. FTabSize: TSmallPoint;
  165. FUpdating: Boolean;
  166. FSavedAdjustRect: TRect;
  167. FOnChange: TNotifyEvent;
  168. FOnChanging: TTabChangingEvent;
  169. FOnDrawTab: TCnDockDrawTabEvent;
  170. FOnGetImageIndex: TTabGetImageEvent;
  171. function GetDisplayRect: TRect;
  172. function GetTabIndex: Integer;
  173. procedure ImageListChange(Sender: TObject);
  174. function InternalSetMultiLine(Value: Boolean): Boolean;
  175. procedure SetMultiLine(Value: Boolean);
  176. procedure SetMultiSelect(Value: Boolean);
  177. procedure SetOwnerDraw(Value: Boolean);
  178. procedure SetRaggedRight(Value: Boolean);
  179. procedure SetScrollOpposite(Value: Boolean);
  180. procedure SetStyle(Value: TTabStyle);
  181. procedure SetTabIndex(Value: Integer);
  182. procedure SetTabs(Value: TStrings);
  183. procedure SetTabWidth(Value: Smallint);
  184. procedure TabsChanged;
  185. procedure UpdateTabSize;
  186. procedure CMFontChanged(var Message); message CM_FONTCHANGED;
  187. procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
  188. procedure CMTabStopChanged(var Message: TMessage); message CM_TABSTOPCHANGED;
  189. procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
  190. procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  191. procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
  192. procedure TCMAdjustRect(var Message: TMessage); message TCM_ADJUSTRECT;
  193. procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
  194. procedure WMNotifyFormat(var Message: TMessage); message WM_NOTIFYFORMAT;
  195. procedure WMSize(var Message: TMessage); message WM_SIZE;
  196. protected
  197. procedure AdjustClientRect(var Rect: TRect); override;
  198. function CanChange: Boolean; dynamic;
  199. function CanShowTab(TabIndex: Integer): Boolean; virtual;
  200. procedure Change; dynamic;
  201. procedure CreateParams(var Params: TCreateParams); override;
  202. procedure CreateWnd; override;
  203. procedure DrawTab(TabIndex: Integer; const Rect: TRect; Active: Boolean); virtual;
  204. function GetImageIndex(TabIndex: Integer): Integer; virtual;
  205. procedure Loaded; override;
  206. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  207. procedure PaintWindow(DC: HDC); override;
  208. procedure SetHotTrack(Value: Boolean); virtual;
  209. procedure SetImages(Value: TCustomImageList); virtual;
  210. procedure SetTabHeight(Value: Smallint); virtual;
  211. procedure SetTabPosition(Value: TTabPosition); virtual;
  212. procedure UpdateTabImages;
  213. property DisplayRect: TRect read GetDisplayRect;
  214. property HotTrack: Boolean read FHotTrack write SetHotTrack default False;
  215. property Images: TCustomImageList read FImages write SetImages;
  216. property MultiLine: Boolean read FMultiLine write SetMultiLine default False;
  217. property MultiSelect: Boolean read FMultiSelect write SetMultiSelect default False;
  218. property OwnerDraw: Boolean read FOwnerDraw write SetOwnerDraw default False;
  219. property RaggedRight: Boolean read FRaggedRight write SetRaggedRight default False;
  220. property ScrollOpposite: Boolean read FScrollOpposite
  221. write SetScrollOpposite default False;
  222. property Style: TTabStyle read FStyle write SetStyle default tsTabs;
  223. property TabHeight: Smallint read FTabSize.Y write SetTabHeight default 0;
  224. property TabIndex: Integer read GetTabIndex write SetTabIndex default -1;
  225. property TabPosition: TTabPosition read FTabPosition write SetTabPosition
  226. default tpTop;
  227. property Tabs: TStrings read FTabs write SetTabs;
  228. property TabWidth: Smallint read FTabSize.X write SetTabWidth default 0;
  229. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  230. property OnChanging: TTabChangingEvent read FOnChanging write FOnChanging;
  231. property OnDrawTab: TCnDockDrawTabEvent read FOnDrawTab write FOnDrawTab;
  232. property OnGetImageIndex: TTabGetImageEvent read FOnGetImageIndex write FOnGetImageIndex;
  233. public
  234. constructor Create(AOwner: TComponent); override;
  235. destructor Destroy; override;
  236. function IndexOfTabAt(X, Y: Integer): Integer;
  237. function GetHitTestInfoAt(X, Y: Integer): THitTests;
  238. function TabRect(Index: Integer): TRect;
  239. function RowCount: Integer;
  240. procedure ScrollTabs(Delta: Integer);
  241. property TabStop default True;
  242. end;
  243. TCnDockTabSheet = class(TWinControl)
  244. private
  245. FImageIndex: TImageIndex;
  246. FPageControl: TCnDockPageControl;
  247. FTabVisible: Boolean;
  248. FTabShowing: Boolean;
  249. FHighlighted: Boolean;
  250. FOnHide: TNotifyEvent;
  251. FOnShow: TNotifyEvent;
  252. function GetPageIndex: Integer;
  253. function GetTabIndex: Integer;
  254. procedure SetHighlighted(Value: Boolean);
  255. procedure SetImageIndex(Value: TImageIndex);
  256. procedure SetPageIndex(Value: Integer);
  257. procedure SetTabShowing(Value: Boolean);
  258. procedure SetTabVisible(Value: Boolean);
  259. procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  260. procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  261. protected
  262. procedure CreateParams(var Params: TCreateParams); override;
  263. procedure SetPageControl(APageControl: TCnDockPageControl); virtual;
  264. procedure ReadState(Reader: TReader); override;
  265. procedure DoHide; dynamic;
  266. procedure DoShow; dynamic;
  267. procedure UpdateTabShowing; dynamic;
  268. public
  269. constructor Create(AOwner: TComponent); override;
  270. destructor Destroy; override;
  271. property PageControl: TCnDockPageControl read FPageControl write SetPageControl;
  272. property TabIndex: Integer read GetTabIndex;
  273. published
  274. property Caption;
  275. property Height stored False;
  276. property Highlighted: Boolean read FHighlighted write SetHighlighted default False;
  277. property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default 0;
  278. property Left stored False;
  279. property PageIndex: Integer read GetPageIndex write SetPageIndex stored False;
  280. property TabVisible: Boolean read FTabVisible write SetTabVisible default True;
  281. property Top stored False;
  282. property Visible stored False;
  283. property Width stored False;
  284. property OnHide: TNotifyEvent read FOnHide write FOnHide;
  285. property OnShow: TNotifyEvent read FOnShow write FOnShow;
  286. end;
  287. TCnDockTabSheetClass = class of TCnDockTabSheet;
  288. TCnDockPageControl = class(TCnDockCustomTabControl)
  289. private
  290. FPages: TList;
  291. FActivePage: TCnDockTabSheet;
  292. FNewDockSheet: TCnDockTabSheet;
  293. FUndockingPage: TCnDockTabSheet;
  294. FCnDockTabSheetClass: TCnDockTabSheetClass;
  295. procedure ChangeActivePage(Page: TCnDockTabSheet);
  296. procedure DeleteTab(Page: TCnDockTabSheet; Index: Integer);
  297. function GetActivePageIndex: Integer;
  298. function GetPage(Index: Integer): TCnDockTabSheet;
  299. function GetPageCount: Integer;
  300. procedure InsertPage(Page: TCnDockTabSheet);
  301. procedure InsertTab(Page: TCnDockTabSheet);
  302. procedure MoveTab(CurIndex, NewIndex: Integer);
  303. procedure RemovePage(Page: TCnDockTabSheet);
  304. procedure SetActivePageIndex(const Value: Integer);
  305. procedure UpdateTab(Page: TCnDockTabSheet);
  306. procedure UpdateTabHighlights;
  307. procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST;
  308. procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
  309. procedure CMDockClient(var Message: TCMDockClient); message CM_DOCKCLIENT;
  310. procedure CMDockNotification(var Message: TCMDockNotification); message CM_DOCKNOTIFICATION;
  311. procedure CMUnDockClient(var Message: TCMUnDockClient); message CM_UNDOCKCLIENT;
  312. procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  313. procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
  314. procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
  315. procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
  316. procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;
  317. procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
  318. procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
  319. procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK;
  320. procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP;
  321. protected
  322. function CanShowTab(TabIndex: Integer): Boolean; override;
  323. procedure Change; override;
  324. procedure DoAddDockClient(Client: TControl; const ARect: TRect); override;
  325. procedure DockOver(Source: TDragDockObject; X, Y: Integer;
  326. State: TDragState; var Accept: Boolean); override;
  327. function DoMouseEvent(var Message: TWMMouse; Control: TControl): TWMNCHitMessage; virtual;
  328. procedure DoRemoveDockClient(Client: TControl); override;
  329. function GetDockClientFromMousePos(MousePos: TPoint): TControl; virtual;
  330. function GetImageIndex(TabIndex: Integer): Integer; override;
  331. function GetPageFromDockClient(Client: TControl): TCnDockTabSheet;
  332. procedure GetSiteInfo(Client: TControl; var InfluenceRect: TRect;
  333. MousePos: TPoint; var CanDock: Boolean); override;
  334. procedure Loaded; override;
  335. procedure SetActivePage(Page: TCnDockTabSheet); virtual;
  336. procedure ShowControl(AControl: TControl); override;
  337. procedure UpdateActivePage; virtual;
  338. public
  339. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  340. constructor Create(AOwner: TComponent); override;
  341. destructor Destroy; override;
  342. function FindNextPage(CurPage: TCnDockTabSheet;
  343. GoForward, CheckTabVisible: Boolean): TCnDockTabSheet;
  344. procedure SelectNextPage(GoForward: Boolean; CheckTabVisible: Boolean = True);
  345. procedure SetChildOrder(Child: TComponent; Order: Integer); override;
  346. property ActivePage: TCnDockTabSheet read FActivePage write SetActivePage;
  347. property ActivePageIndex: Integer read GetActivePageIndex
  348. write SetActivePageIndex;
  349. property PageCount: Integer read GetPageCount;
  350. property Pages[Index: Integer]: TCnDockTabSheet read GetPage;
  351. property PageSheets: TList read FPages;
  352. property CnDockTabSheetClass: TCnDockTabSheetClass read FCnDockTabSheetClass
  353. write FCnDockTabSheetClass;
  354. end;
  355. TCnDockTabStrings = class(TStrings)
  356. private
  357. FTabControl: TCnDockCustomTabControl;
  358. protected
  359. function Get(Index: Integer): string; override;
  360. function GetCount: Integer; override;
  361. function GetObject(Index: Integer): TObject; override;
  362. procedure Put(Index: Integer; const S: string); override;
  363. procedure PutObject(Index: Integer; AObject: TObject); override;
  364. procedure SetUpdateState(Updating: Boolean); override;
  365. public
  366. procedure Clear; override;
  367. procedure Delete(Index: Integer); override;
  368. procedure Insert(Index: Integer; const S: string); override;
  369. end;
  370. TDragOperation = (dopNone, dopDrag, dopDock);
  371. PSiteInfoRec = ^TSiteInfoRec;
  372. TSiteInfoRec = record
  373. Site: TWinControl;
  374. TopParent: HWND;
  375. end;
  376. TSiteList = class(TList)
  377. public
  378. procedure AddSite(ASite: TWinControl);
  379. procedure Clear; override;
  380. function Find(ParentWnd: Hwnd; var Index: Integer): Boolean;
  381. function GetTopSite: TWinControl;
  382. end;
  383. TCnDockPresident = class(TObject)
  384. private
  385. FDockServersList: TList; //存放停靠服务器的列表
  386. FDockClientsList: TList; //存放停靠客户的列表
  387. FDockServersHash: TCnDockControlHashTable; //存放停靠服务器的散列
  388. FDockClientsHash: TCnDockControlHashTable; //存放停靠客户的散列
  389. FDockableFormList: TList; //所有停靠服务器的列表
  390. FLoadCount: Integer;
  391. FSaveCount: Integer;
  392. procedure BeginLoad;
  393. procedure EndLoad;
  394. procedure BeginSave;
  395. procedure EndSave;
  396. public
  397. { ------------------------------------------------------------------------ }
  398. DragControl: TControl;
  399. DragObject: TCnDragDockObject;
  400. DragFreeObject: Boolean;
  401. DragCapture: HWND;
  402. DragStartPos: TPoint;
  403. DragSaveCursor: HCURSOR;
  404. DragThreshold: Integer;
  405. ActiveDrag: TDragOperation;
  406. DragImageList: TDragImageList;
  407. DockSiteList: TList;
  408. QualifyingSites: TSiteList;
  409. { ------------------------------------------------------------------------ }
  410. procedure CalcDockSizes(Control: TControl);
  411. // constructor Create(AOwner: TComponent); override;
  412. constructor Create; virtual;
  413. destructor Destroy; override;
  414. procedure AddDockServerToDockManager(AControl: TControl);
  415. procedure AddDockClientToDockManager(AControl: TControl);
  416. procedure RemoveDockServerFromDockManager(AControl: TControl);
  417. procedure RemoveDockClientFromDockManager(AControl: TControl);
  418. function FindDockServerForm(AName: string): TControl;
  419. function FindDockClientForm(AName: string): TControl;
  420. function FindDockControlForm(AName: string): TControl;
  421. function IsLoading: Boolean;
  422. function IsSaving: Boolean;
  423. { 显示窗体 }
  424. procedure ShowDockForm(DockWindow: TWinControl);
  425. { 隐藏窗体 }
  426. procedure HideDockForm(DockWindow: TControl);
  427. { 获得窗体的可见性 }
  428. function GetFormVisible(DockWindow: TWinControl): Boolean;
  429. { 设置分页的服务窗体的显示风格 }
  430. procedure SetTabDockHostBorderStyle(Value: TFormBorderStyle);
  431. { 设置平铺的服务窗体的显示风格 }
  432. procedure SetConjoinDockHostBorderStyle(Value: TFormBorderStyle);
  433. { 把停靠窗体的信息保存进文件 }
  434. procedure SaveDockTreeToFile(FileName: string);
  435. { 从文件里读出停靠窗体的信息 }
  436. procedure LoadDockTreeFromFile(FileName: string);
  437. { 把停靠窗体的信息保存进注册表 }
  438. procedure SaveDockTreeToReg(RootKey: DWORD; RegPath: string);
  439. { 从注册表里读出停靠窗体的信息 }
  440. procedure LoadDockTreeFromReg(RootKey: DWORD; RegPath: string);
  441. { 当鼠标左键按下的时候,开始拖动 }
  442. procedure BeginDrag(Control: TControl;
  443. Immediate: Boolean; Threshold: Integer = -1); virtual;
  444. { 初始化停靠控件 }
  445. procedure DragInitControl(Control: TControl;
  446. Immediate: Boolean; Threshold: Integer); virtual;
  447. { 初始化拖动 }
  448. procedure DragInit(ADragObject: TCnDragDockObject;
  449. Immediate: Boolean; Threshold: Integer); virtual;
  450. { 当鼠标移动的时候,调用DragTo }
  451. procedure DragTo(const Pos: TPoint); virtual;
  452. { 当鼠标释放的时候,调用DragDone }
  453. procedure DragDone(Drop: Boolean); virtual;
  454. { 取消拖动操作 }
  455. procedure CancelDrag; virtual;
  456. { 重新设置光标的形状 }
  457. procedure ResetCursor; virtual;
  458. { 查找可能的停靠服务器,Handle是这个服务器的句柄 }
  459. function DragFindTarget(const Pos: TPoint; var Handle: HWND;
  460. DragKind: TDragKind; Client: TControl): Pointer; virtual;
  461. { 调用控件的OnxxxGetSiteInfo方法 }
  462. procedure DoGetSiteInfo(Target, Client: TControl; var InfluenceRect: TRect;
  463. MousePos: TPoint; var CanDock: Boolean); virtual;
  464. { 调用控件的OnxxxDockOver方法 }
  465. function DoDockOver(DragState: TDragState): Boolean; virtual;
  466. { 调用控件的OnxxxDockDrop方法 }
  467. procedure DoDockDrop(Source: TCnDragDockObject; Pos: TPoint); virtual;
  468. { 调用控件的OnxxxUnDock方法 }
  469. function DoUnDock(Source: TCnDragDockObject; Target: TWinControl; Client: TControl): Boolean; virtual;
  470. { 调用控件的OnxxxEndDock方法 }
  471. procedure DoEndDrag(Target: TObject; X, Y: Integer); virtual;
  472. { 查找鼠标位置的控件句柄 }
  473. function DragFindWindow(const Pos: TPoint): HWND; virtual;
  474. { 获得鼠标位置的控件对象 }
  475. function GetDockSiteAtPos(MousePos: TPoint; Client: TControl): TWinControl; virtual;
  476. { 获得鼠标位置的控件的排列位置 }
  477. procedure DoGetDockEdge(Target: TControl; MousePos: TPoint; var DropAlign: TAlign); virtual;
  478. { 注册停靠服务器 }
  479. procedure RegisterDockSite(Site: TWinControl; DoRegister: Boolean); virtual;
  480. property DockServersList: TList read FDockServersList;
  481. property DockClientsList: TList read FDockClientsList;
  482. property DockServersHash: TCnDockControlHashTable
  483. read FDockServersHash;
  484. property DockClientsHash: TCnDockControlHashTable
  485. read FDockClientsHash;
  486. property DockableFormList: TList read FDockableFormList;
  487. end;
  488. TCustomDockPanelSplitter = class(TCustomControl)
  489. private
  490. FActiveControl: TWinControl;
  491. FAutoSnap: Boolean;
  492. FBeveled: Boolean;
  493. FBrush: TBrush;
  494. FControl: TControl;
  495. FDownPos: TPoint;
  496. FLineDC: HDC;
  497. FLineVisible: Boolean;
  498. FMinSize: NaturalNumber;
  499. FMaxSize: Integer;
  500. FNewSize: Integer;
  501. FOldKeyDown: TKeyEvent;
  502. FOldSize: Integer;
  503. FPrevBrush: HBrush;
  504. FResizeStyle: TResizeStyle;
  505. FSplit: Integer;
  506. FOnCanResize: TCanResizeEvent;
  507. FOnMoved: TNotifyEvent;
  508. FOnPaint: TNotifyEvent;
  509. procedure AllocateLineDC;
  510. procedure CalcSplitSize(X, Y: Integer; var NewSize, Split: Integer);
  511. procedure DrawLine;
  512. procedure FocusKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  513. procedure ReleaseLineDC;
  514. procedure SetBeveled(Value: Boolean);
  515. procedure UpdateControlSize;
  516. procedure UpdateSize(X, Y: Integer);
  517. protected
  518. function CanResize(var NewSize: Integer): Boolean; reintroduce; virtual;
  519. function DoCanResize(var NewSize: Integer): Boolean; virtual;
  520. function FindControl: TControl; virtual;
  521. procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  522. X, Y: Integer); override;
  523. procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  524. procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  525. X, Y: Integer); override;
  526. procedure Paint; override;
  527. procedure RequestAlign; override;
  528. procedure StopSizing; dynamic;
  529. public
  530. constructor Create(AOwner: TComponent); override;
  531. destructor Destroy; override;
  532. property Canvas;
  533. published
  534. property Align default alLeft;
  535. property AutoSnap: Boolean read FAutoSnap write FAutoSnap default True;
  536. property Beveled: Boolean read FBeveled write SetBeveled default False;
  537. property Color;
  538. property Constraints;
  539. property MinSize: NaturalNumber read FMinSize write FMinSize default 30;
  540. property ParentColor;
  541. property ResizeStyle: TResizeStyle read FResizeStyle write FResizeStyle
  542. default rsPattern;
  543. property Visible;
  544. property OnCanResize: TCanResizeEvent read FOnCanResize write FOnCanResize;
  545. property OnMoved: TNotifyEvent read FOnMoved write FOnMoved;
  546. property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
  547. end;
  548. implementation
  549. uses
  550. Consts, ComStrs, CnDockGlobal, CnDockFormControl, CnDockSupportProc;
  551. type
  552. TCnNCButtonProc = procedure(Message: TWMNCHitMessage; Button: TMouseButton;
  553. MouseStation: TMouseStation) of object;
  554. function ButtonEvent(Page: TCnDockPageControl; Message: TWMMouse;
  555. Button: TMouseButton; MouseStation: TMouseStation; Proc: TCnNCButtonProc): TControl;
  556. begin
  557. { 查找到鼠标所在位置的TCnDockTabSheet上的Control }
  558. Result := Page.GetDockClientFromMousePos(SmallPointToPoint(Message.Pos));
  559. if (Result <> nil) and Assigned(Proc) then
  560. begin
  561. { 查找到DockCtl上的TCnDockClient,然后把她赋值给全局变量GlobalDockClient }
  562. GlobalDockClient := FindDockClient(Result);
  563. { 调用全局变量GlobalDockClient的DoNCButtonDown方法 }
  564. Proc(Page.DoMouseEvent(Message, Page), Button, MouseStation);
  565. end;
  566. end;
  567. type
  568. TCnControlAccess = class(TControl);
  569. TCnWinControlAccess = class(TWinControl);
  570. PCheckTargetInfo = ^TCheckTargetInfo;
  571. TCheckTargetInfo = record
  572. ClientWnd, TargetWnd: HWnd;
  573. CurrentWnd: HWnd;
  574. MousePos: TPoint;
  575. Found: Boolean;
  576. end;
  577. procedure TabControlError(const S: string);
  578. begin
  579. raise EListError.Create(S);
  580. end;
  581. procedure SetComCtlStyle(Ctl: TWinControl; Value: Integer; UseStyle: Boolean);
  582. var
  583. Style: Integer;
  584. begin
  585. if Ctl.HandleAllocated then
  586. begin
  587. Style := GetWindowLong(Ctl.Handle, GWL_STYLE);
  588. if not UseStyle then Style := Style and not Value
  589. else Style := Style or Value;
  590. SetWindowLong(Ctl.Handle, GWL_STYLE, Style);
  591. end;
  592. end;
  593. function IsBeforeTargetWindow(Window: HWnd; Data: Longint): Bool; stdcall;
  594. var
  595. R: TRect;
  596. begin
  597. if Window = PCheckTargetInfo(Data)^.TargetWnd then
  598. Result := False
  599. else
  600. begin
  601. if PCheckTargetInfo(Data)^.CurrentWnd = 0 then
  602. begin
  603. GetWindowRect(Window, R);
  604. if PtInRect(R, PCheckTargetInfo(Data)^.MousePos) then
  605. PCheckTargetInfo(Data)^.CurrentWnd := Window;
  606. end;
  607. if Window = PCheckTargetInfo(Data)^.CurrentWnd then
  608. begin
  609. Result := False;
  610. PCheckTargetInfo(Data)^.Found := True;
  611. end
  612. else if Window = PCheckTargetInfo(Data)^.ClientWnd then
  613. begin
  614. Result := True;
  615. PCheckTargetInfo(Data)^.CurrentWnd := 0; // Look for next window
  616. end
  617. else
  618. Result := True;
  619. end;
  620. end;
  621. { TCnDragDockObject }
  622. procedure TCnDragDockObject.AdjustDockRect(var ARect: TRect);
  623. var
  624. DeltaX, DeltaY: Integer;
  625. function AbsMin(Value1, Value2: Integer): Integer;
  626. begin
  627. if Abs(Value1) < Abs(Value2) then Result := Value1
  628. else Result := Value2;
  629. end;
  630. begin
  631. { Make sure dock rect is touching mouse point }
  632. if (ARect.Left > FDragPos.x) or (ARect.Right < FDragPos.x) then
  633. DeltaX := AbsMin(ARect.Left - FDragPos.x, ARect.Right - FDragPos.x)
  634. else DeltaX := 0;
  635. if (ARect.Top > FDragPos.y) or (ARect.Bottom < FDragPos.y) then
  636. DeltaY := AbsMin(ARect.Top - FDragPos.y, ARect.Bottom - FDragPos.y)
  637. else DeltaY := 0;
  638. if (DeltaX <> 0) or (DeltaY <> 0) then
  639. OffsetRect(DockRect, -DeltaX, -DeltaY);
  640. end;
  641. function TCnDragDockObject.CanLeave(NewTarget: TWinControl): Boolean;
  642. begin
  643. Result := NewTarget <> TWinControl(FDragTarget);
  644. end;
  645. function TCnDragDockObject.Capture: HWND;
  646. begin
  647. Result := AllocateHWND(MouseMsg);
  648. SetCapture(Result);
  649. end;
  650. constructor TCnDragDockObject.Create(AControl: TControl);
  651. begin
  652. FControl := AControl;
  653. FBrush := TBrush.Create;
  654. FBrush.Bitmap := AllocPatternBitmap(clBlack, clWhite);
  655. FFrameWidth := 4;
  656. FCtrlDown := False;
  657. end;
  658. procedure TCnDragDockObject.DefaultDockImage(Erase: Boolean);
  659. var
  660. DesktopWindow: HWND;
  661. DC: HDC;
  662. OldBrush: HBrush;
  663. DrawRect: TRect;
  664. PenSize: Integer;
  665. ABrush: TBrush;
  666. begin
  667. { 获得画刷句柄,画笔宽度和绘画区域 }
  668. GetBrush_PenSize_DrawRect(ABrush, PenSize, DrawRect, Erase);
  669. DesktopWindow := GetDesktopWindow;
  670. DC := GetDCEx(DesktopWindow, 0, DCX_CACHE or DCX_LOCKWINDOWUPDATE);
  671. try
  672. OldBrush := SelectObject(DC, ABrush.Handle);
  673. with DrawRect do
  674. begin
  675. PatBlt(DC, Left + PenSize, Top, Right - Left - PenSize, PenSize, PATINVERT);
  676. PatBlt(DC, Right - PenSize, Top + PenSize, PenSize, Bottom - Top - PenSize, PATINVERT);
  677. PatBlt(DC, Left, Bottom - PenSize, Right - Left - PenSize, PenSize, PATINVERT);
  678. PatBlt(DC, Left, Top, PenSize, Bottom - Top - PenSize, PATINVERT);
  679. end;
  680. SelectObject(DC, OldBrush);
  681. finally
  682. ReleaseDC(DesktopWindow, DC);
  683. end;
  684. end;
  685. destructor TCnDragDockObject.Destroy;
  686. begin
  687. if FBrush <> nil then
  688. begin
  689. FBrush.Free;
  690. FBrush := nil;
  691. end;
  692. inherited;
  693. end;
  694. function TCnDragDockObject.DragFindWindow(const Pos: TPoint): HWND;
  695. var WinControl: TWinControl;
  696. begin
  697. { Result := WindowFromPoint(Pos);
  698. while Result <> 0 do
  699. if not IsDelphiHandle(Result) then Result := GetParent(Result)
  700. else Exit;}
  701. // FindControl
  702. WinControl := FindVCLWindow(Pos);
  703. if WinControl <> nil then
  704. Result := WinControl.Handle
  705. else Result := 0;
  706. end;
  707. procedure TCnDragDockObject.DrawDragDockImage;
  708. begin
  709. DefaultDockImage(False);
  710. end;
  711. procedure TCnDragDockObject.DrawDragRect(DoErase: Boolean);
  712. begin
  713. if not CompareMem(@DockRect, @EraseDockRect, SizeOf(TRect)) then
  714. begin
  715. if DoErase then EraseDragDockImage;
  716. DrawDragDockImage;
  717. EraseDockRect := DockRect;
  718. end;
  719. end;
  720. procedure TCnDragDockObject.EndDrag(Target: TObject; X, Y: Integer);
  721. begin
  722. CnGlobalDockPresident.DoEndDrag(Target, X, Y);
  723. end;
  724. procedure TCnDragDockObject.EraseDragDockImage;
  725. begin
  726. DefaultDockImage(True);
  727. end;
  728. procedure TCnDragDockObject.Finished(Target: TObject; X, Y: Integer;
  729. Accepted: Boolean);
  730. begin
  731. if not Accepted then
  732. begin
  733. Target := nil;
  734. end;
  735. EndDrag(Target, X, Y);
  736. end;
  737. procedure TCnDragDockObject.GetBrush_PenSize_DrawRect(
  738. var ABrush: TBrush; var PenSize: Integer; var DrawRect: TRect; Erase: Boolean);
  739. begin
  740. ABrush := Brush;
  741. PenSize := FrameWidth;
  742. if Erase then DrawRect := EraseDockRect
  743. else DrawRect := DockRect;
  744. end;
  745. function TCnDragDockObject.GetDragCursor(Accepted: Boolean; X,
  746. Y: Integer): TCursor;
  747. begin
  748. Result := crDefault;
  749. end;
  750. function TCnDragDockObject.GetDragImages: TDragImageList;
  751. begin
  752. Result := nil;
  753. end;
  754. function TCnDragDockObject.GetDropCtl: TControl;
  755. var
  756. NextCtl: TControl;
  757. TargetCtl: TWinControl;
  758. CtlIdx: Integer;
  759. function GetDockClientsIndex: Integer;
  760. begin
  761. for Result := 0 to TCnWinControlAccess(TargetCtl).DockClientCount - 1 do
  762. begin
  763. if TCnWinControlAccess(TargetCtl).DockClients[Result] = NextCtl then
  764. Exit;
  765. end;
  766. Result := -1;
  767. end;
  768. begin
  769. Result := nil;
  770. TargetCtl := DragTarget;
  771. if (TargetCtl = nil) or not TCnWinControlAccess(TargetCtl).UseDockManager or
  772. (TargetCtl.DockClientCount = 0) or
  773. ((TargetCtl.DockClientCount = 1) and
  774. (TCnWinControlAccess(TargetCtl).DockClients[0] = Control)) then
  775. Exit;
  776. NextCtl := FindDragTarget(DragPos, False);
  777. while (NextCtl <> nil) and (NextCtl <> TargetCtl) do
  778. begin
  779. CtlIdx := GetDockClientsIndex;
  780. if CtlIdx <> -1 then
  781. begin
  782. Result := TargetCtl.DockClients[CtlIdx];
  783. Exit;
  784. end
  785. else
  786. NextCtl := NextCtl.Parent;
  787. end;
  788. end;
  789. function TCnDragDockObject.GetFrameWidth: Integer;
  790. begin
  791. Result := FFrameWidth;
  792. end;
  793. function TCnDragDockObject.GetTargetControl: TWinControl;
  794. begin
  795. if FDragTarget <> nil then
  796. Result := TWinControl(FDragTarget)
  797. else Result := nil;
  798. end;
  799. procedure TCnDragDockObject.MouseMsg(var Msg: TMessage);
  800. var
  801. P: TPoint;
  802. begin
  803. try
  804. case Msg.Msg of
  805. WM_MOUSEMOVE:
  806. begin
  807. P := SmallPointToPoint(TWMMouse(Msg).Pos);
  808. ClientToScreen(CnGlobalDockPresident.DragCapture, P);
  809. CnGlobalDockPresident.DragTo(P);
  810. end;
  811. WM_CAPTURECHANGED:
  812. begin
  813. CnGlobalDockPresident.DragDone(False);
  814. end;
  815. WM_LBUTTONUP, WM_RBUTTONUP:
  816. if not GlobalDockClient.CanFloat then
  817. begin
  818. if (TargetControl = nil) and (GlobalDockClient.ParentForm.HostDockSite = nil) then
  819. CnGlobalDockPresident.DragDone(True)
  820. else
  821. CnGlobalDockPresident.DragDone(TargetControl <> nil);
  822. end
  823. else
  824. CnGlobalDockPresident.DragDone(True);
  825. { Forms.IsKeyMsg sends WM_KEYxxx messages here (+CN_BASE) when a
  826. TPUtilWindow has the mouse capture. }
  827. CN_KEYUP:
  828. if Msg.WParam = VK_CONTROL then
  829. begin
  830. FCtrlDown := False;
  831. CnGlobalDockPresident.DragTo(CnGlobalDockPresident.DragObject.DragPos);
  832. end;
  833. CN_KEYDOWN:
  834. begin
  835. case Msg.WParam of
  836. VK_CONTROL: // 当按下了Ctrl键的后,窗体不允许停靠
  837. begin
  838. FCtrlDown := True;
  839. CnGlobalDockPresident.DragTo(CnGlobalDockPresident.DragObject.DragPos);
  840. end;
  841. VK_ESCAPE:
  842. begin
  843. { Consume keystroke and cancel drag operation }
  844. Msg.Result := 1;
  845. CnGlobalDockPresident.DragDone(False);
  846. end;
  847. end;
  848. end;
  849. end;
  850. except
  851. if CnGlobalDockPresident.DragControl <> nil then
  852. CnGlobalDockPresident.DragDone(False);
  853. raise;
  854. end;
  855. end;
  856. procedure TCnDragDockObject.ReleaseCapture(Handle: HWND);
  857. begin
  858. Windows.ReleaseCapture;
  859. DeallocateHWND(Handle);
  860. end;
  861. procedure TCnDragDockObject.SetBrush(const Value: TBrush);
  862. begin
  863. FBrush.Assign(Value);
  864. end;
  865. procedure TCnDragDockObject.SetDropAlign(const Value: TAlign);
  866. begin
  867. if FDropAlign <> Value then
  868. FDropAlign := Value;
  869. end;
  870. procedure TCnDragDockObject.SetDropOnControl(const Value: TControl);
  871. begin
  872. FDropOnControl := Value;
  873. end;
  874. procedure TCnDragDockObject.SetFrameWidth(const Value: Integer);
  875. begin
  876. FFrameWidth := Value;
  877. end;
  878. procedure TCnDragDockObject.SetTargetControl(const Value: TWinControl);
  879. begin
  880. FDragTarget := Value;
  881. end;
  882. { TCnCustomDockControl }
  883. function TCnCustomDockControl.GetCnDockManager: ICnDockManager;
  884. begin
  885. Result := ICnDockManager(DockManager);
  886. end;
  887. procedure TCnCustomDockControl.SetCnDockManager(const Value: ICnDockManager);
  888. begin
  889. DockManager := Value;
  890. end;
  891. procedure TCnCustomDockControl.CustomDockDrop(Source: TCnDragDockObject; X,
  892. Y: Integer);
  893. var
  894. DestRect: TRect;
  895. Form: TCustomForm;
  896. begin
  897. { Map DockRect to dock site's client coordinates }
  898. DestRect := Source.DockRect;
  899. MapWindowPoints(0, Handle, DestRect, 2);
  900. DisableAlign;
  901. try
  902. Source.Control.Dock(Self, DestRect);
  903. if UseDockManager and (DockManager <> nil) then
  904. begin
  905. DockManager.InsertControl(Source.Control,
  906. Source.DropAlign, Source.DropOnControl);
  907. end;
  908. finally
  909. EnableAlign;
  910. end;
  911. Form := GetParentForm(Self);
  912. if Form <> nil then Form.BringToFront;
  913. { -------------------------------------------------------------------------- }
  914. if Source.Control is TForm then
  915. begin
  916. { 下面一行代码是为了防止窗体的标题栏和窗体上面的控件的内容被清空 }
  917. TForm(Source.Control).ActiveControl := nil;
  918. { ------------------------------------------------------------------------ }
  919. SetDockSite(TForm(Source.Control), False);
  920. end;
  921. end;
  922. procedure TCnCustomDockControl.CustomDockOver(Source: TCnDragDockObject; X,
  923. Y: Integer; State: TDragState; var Accept: Boolean);
  924. begin
  925. CustomPositionDockRect(Source, X, Y);
  926. end;
  927. procedure TCnCustomDockControl.CustomEndDock(Target: TObject; X,
  928. Y: Integer);
  929. begin
  930. end;
  931. procedure TCnCustomDockControl.CustomGetDockEdge(Source: TCnDragDockObject;
  932. MousePos: TPoint; var DropAlign: TAlign);
  933. begin
  934. DropAlign := GetDockEdge(MousePos);
  935. end;
  936. procedure TCnCustomDockControl.CustomGetSiteInfo(Source: TCnDragDockObject;
  937. Client: TControl; var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);
  938. begin
  939. GetWindowRect(Handle, InfluenceRect);
  940. InflateRect(InfluenceRect, DefExpandoRect, DefExpandoRect);
  941. end;
  942. procedure TCnCustomDockControl.CustomPositionDockRect(
  943. Source: TCnDragDockObject; X, Y: Integer);
  944. var
  945. NewWidth, NewHeight: Integer;
  946. TempX, TempY: Double;
  947. begin
  948. with Source do
  949. begin
  950. if (DragTarget = nil) or (not TCnWinControlAccess(DragTarget).UseDockManager) then
  951. begin
  952. NewWidth := Control.UndockWidth;
  953. NewHeight := Control.UndockHeight;
  954. // Drag position for dock rect is scaled relative to control's click point.
  955. TempX := DragPos.X - ((NewWidth) * MouseDeltaX);
  956. TempY := DragPos.Y - ((NewHeight) * MouseDeltaY);
  957. with DockRect do
  958. begin
  959. Left := Round(TempX);
  960. Top := Round(TempY);
  961. Right := Left + NewWidth;
  962. Bottom := Top + NewHeight;
  963. end;
  964. { Allow DragDockObject final say on this new dock rect }
  965. AdjustDockRect(DockRect);
  966. end
  967. else begin
  968. GetWindowRect(TargetControl.Handle, DockRect);
  969. if TCnWinControlAccess(DragTarget).UseDockManager then
  970. begin
  971. if TargetControl is TCnCustomDockPanel then
  972. begin
  973. if (TCnCustomDockPanel(DragTarget).CnDockManager <> nil) then
  974. TCnCustomDockPanel(DragTarget).CnDockManager.PositionDockRect(Control,
  975. DropOnControl, DropAlign, DockRect);
  976. end;
  977. end;
  978. end;
  979. end;
  980. end;
  981. procedure TCnCustomDockControl.CustomStartDock(
  982. var Source: TCnDragDockObject);
  983. begin
  984. end;
  985. function TCnCustomDockControl.CustomUnDock(Source: TCnDragDockObject; NewTarget: TWinControl;
  986. Client: TControl): Boolean;
  987. begin
  988. Result := (Perform(CM_UNDOCKCLIENT, Integer(NewTarget), Integer(Client)) = 0);
  989. end;
  990. procedure TCnCustomDockControl.UpdateCaption(Exclude: TControl);
  991. var i: Integer;
  992. Host: TCnDockableForm;
  993. begin
  994. if Parent is TCnDockableForm then
  995. begin
  996. Host := TCnDockableForm(Parent);
  997. Host.Caption := '';
  998. { 更新本身的Caption }
  999. for I := 0 to Host.DockableControl.DockClientCount - 1 do
  1000. begin
  1001. if Host.DockableControl.DockClients[I].Visible and (Host.DockableControl.DockClients[I] <> Exclude) then
  1002. Host.Caption := Host.Caption + TCustomForm(Host.DockableControl.DockClients[I]).Caption + gs_CnStringSplitter;
  1003. end;
  1004. { 更新TCnTabPageControl的标签 }
  1005. if (Host.HostDockSite is TCnTabPageControl) then
  1006. begin
  1007. with TCnTabPageControl(Host.HostDockSite) do
  1008. if (ActivePage <> nil) and (ActivePage.Controls[0] = Self) then
  1009. ActivePage.Caption := Host.Caption;
  1010. end;
  1011. if Host.HostDockSite is TCnCustomDockControl then
  1012. TCnCustomDockControl(Host.HostDockSite).UpdateCaption(nil);
  1013. end;
  1014. end;
  1015. procedure TCnCustomDockControl.WndProc(var Message: TMessage);
  1016. var CMUnDockClient: TCMUnDockClient;
  1017. DockableForm: TCnDockableForm;
  1018. begin
  1019. if Message.Msg = CM_UNDOCKCLIENT then
  1020. begin
  1021. CMUnDockClient := TCMUnDockClient(Message);
  1022. if CMUnDockClient.Client is TCnDockableForm then
  1023. begin
  1024. DockableForm := TCnDockableForm(CMUnDockClient.Client);
  1025. if DockableForm.FloatingChild <> nil then
  1026. begin
  1027. // Cn_LockWindow(Self);
  1028. try
  1029. { 说明要把停靠客户重新停靠到服务器上,只要调用ReplaceZoneChild替换原先的
  1030. Zone的ChildControl就可以了,不要忘记首先把这个FloatingChild显示出来,
  1031. 因为可能在前面FloatingChild被隐藏了,见CnDockFormControl.pas中的
  1032. TCnDockableForm.DoClose函数 }
  1033. if Self is TCnTabPageControl then
  1034. DockableForm.FloatingChild.ManualDock(Self)
  1035. else
  1036. DockableForm.FloatingChild.Dock(Self, Rect(0,0,0,0));
  1037. DockableForm.FloatingChild.Visible := True;
  1038. if Self is TCnCustomDockPanel then
  1039. CnDockManager.ReplaceZoneChild(DockableForm, DockableForm.FloatingChild);
  1040. finally
  1041. // Cn_UnLockWindow;
  1042. end;
  1043. end;
  1044. end;
  1045. end;
  1046. inherited WndProc(Message);
  1047. end;
  1048. { TCnCustomDockPanel }
  1049. constructor TCnCustomDockPanel.Create(AOwner: TComponent);
  1050. begin
  1051. inherited Create(AOwner);
  1052. ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
  1053. csSetCaption, csOpaque, csDoubleClicks, csReplicatable];
  1054. Color := clBtnFace;
  1055. UseDockManager := True;
  1056. end;
  1057. function TCnCustomDockPanel.CreateDockManager: IDockManager;
  1058. begin
  1059. if (Self is TCnConjoinPanel) and
  1060. (TCnConjoinPanel(Self).DockClient <> nil) and
  1061. (TCnConjoinPanel(Self).DockClient.DockStyle <> nil) and
  1062. (TCnConjoinPanel(Self).DockClient.DockStyle.CnConjoinPanelTreeClass <> nil) and
  1063. (TCnConjoinPanel(Self).DockClient.DockStyle.CnConjoinPanelTreeClass <>
  1064. TCnDockTreeClass(ClassType)) then
  1065. begin
  1066. if (DockManager = nil) and DockSite and UseDockManager then
  1067. Result := TCnConjoinPanel(Self).DockClient.DockStyle.CnConjoinPanelTreeClass.Create(
  1068. Self, TCnDockPanel(Self).DockServer.DockStyle.CnConjoinPanelZoneClass) as ICnDockManager
  1069. else Result := DockManager;
  1070. end else
  1071. if (Self is TCnDockPanel) and
  1072. (TCnDockPanel(Self).DockServer <> nil) and
  1073. (TCnDockPanel(Self).DockServer.DockStyle <> nil) and
  1074. (TCnDockPanel(Self).DockServer.DockStyle.CnDockPanelTreeClass <> nil) and
  1075. (TCnDockPanel(Self).DockServer.DockStyle.CnDockPanelTreeClass <>
  1076. TCnDockTreeClass(ClassType)) then
  1077. begin
  1078. if (DockManager = nil) and DockSite and UseDockManager then
  1079. Result := TCnDockPanel(Self).DockServer.DockStyle.CnDockPanelTreeClass.Create(
  1080. Self, TCnDockPanel(Self).DockServer.DockStyle.CnDockPanelZoneClass) as ICnDockManager
  1081. else Result := DockManager;
  1082. end else
  1083. begin
  1084. if (DockManager = nil) and DockSite and UseDockManager then
  1085. Result := DefaultDockTreeClass.Create(Self, DefaultDockZoneClass) as ICnDockManager
  1086. else Result := DockManager;
  1087. end;
  1088. DoubleBuffered := DoubleBuffered or (Result <> nil);
  1089. end;
  1090. destructor TCnCustomDockPanel.Destroy;
  1091. begin
  1092. SetDockSite(Self, False);
  1093. inherited Destroy;
  1094. end;
  1095. { TCnDockCustomTabControl }
  1096. constructor TCnDockCustomTabControl.Create(AOwner: TComponent);
  1097. begin
  1098. inherited Create(AOwner);
  1099. Width := 289;
  1100. Height := 193;
  1101. TabStop := True;
  1102. ControlStyle := [csAcceptsControls, csDoubleClicks];
  1103. FTabs := TCnDockTabStrings.Create;
  1104. TCnDockTabStrings(FTabs).FTabControl := Self;
  1105. FImageChangeLink := TChangeLink.Create;
  1106. FImageChangeLink.OnChange := ImageListChange;
  1107. end;
  1108. destructor TCnDockCustomTabControl.Destroy;
  1109. begin
  1110. FreeAndNil(FTabs);
  1111. FreeAndNil(FSaveTabs);
  1112. FreeAndNil(FImageChangeLink);
  1113. inherited Destroy;
  1114. end;
  1115. function TCnDockCustomTabControl.CanChange: Boolean;
  1116. begin
  1117. Result := True;
  1118. if Assigned(FOnChanging) then FOnChanging(Self, Result);
  1119. end;
  1120. function TCnDockCustomTabControl.CanShowTab(TabIndex: Integer): Boolean;
  1121. begin
  1122. Result := True;
  1123. end;
  1124. procedure TCnDockCustomTabControl.Change;
  1125. begin
  1126. if Assigned(FOnChange) then FOnChange(Self);
  1127. end;
  1128. procedure TCnDockCustomTabControl.CreateParams(var Params: TCreateParams);
  1129. const
  1130. AlignStyles: array[Boolean, TTabPosition] of DWORD =
  1131. ((0, TCS_BOTTOM, TCS_VERTICAL, TCS_VERTICAL or TCS_RIGHT),
  1132. (0, TCS_BOTTOM, TCS_VERTICAL or TCS_RIGHT, TCS_VERTICAL));
  1133. TabStyles: array[TTabStyle] of DWORD = (TCS_TABS, TCS_BUTTONS,
  1134. TCS_BUTTONS or TCS_FLATBUTTONS);
  1135. RRStyles: array[Boolean] of DWORD = (0, TCS_RAGGEDRIGHT);
  1136. begin
  1137. InitCommonControl(ICC_TAB_CLASSES);
  1138. inherited CreateParams(Params);
  1139. CreateSubClass(Params, WC_TABCONTROL);
  1140. with Params do
  1141. begin
  1142. Style := Style or WS_CLIPCHILDREN or
  1143. AlignStyles[UseRightToLeftAlignment, FTabPosition] or
  1144. TabStyles[FStyle] or RRStyles[FRaggedRight];
  1145. if not TabStop then Style := Style or TCS_FOCUSNEVER;
  1146. if FMultiLine then Style := Style or TCS_MULTILINE;
  1147. if FMultiSelect then Style := Style or TCS_MULTISELECT;
  1148. if FOwnerDraw then Style := Style or TCS_OWNERDRAWFIXED;
  1149. if FTabSize.X <> 0 then Style := Style or TCS_FIXEDWIDTH;
  1150. if FHotTrack and (not (csDesigning in ComponentState)) then
  1151. Style := Style or TCS_HOTTRACK;
  1152. if FScrollOpposite then Style := Style or TCS_SCROLLOPPOSITE;
  1153. WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW) or
  1154. CS_DBLCLKS;
  1155. end;
  1156. end;
  1157. procedure TCnDockCustomTabControl.CreateWnd;
  1158. begin
  1159. inherited CreateWnd;
  1160. if (Images <> nil) and Images.HandleAllocated then
  1161. Perform(TCM_SETIMAGELIST, 0, Images.Handle);
  1162. if Integer(FTabSize) <> 0 then UpdateTabSize;
  1163. if FSaveTabs <> nil then
  1164. begin
  1165. FTabs.Assign(FSaveTabs);
  1166. SetTabIndex(FSaveTabIndex);
  1167. FSaveTabs.Free;
  1168. FSaveTabs := nil;
  1169. end;
  1170. end;
  1171. procedure TCnDockCustomTabControl.DrawTab(TabIndex: Integer; const Rect: TRect;
  1172. Active: Boolean);
  1173. begin
  1174. if Assigned(FOnDrawTab) then
  1175. FOnDrawTab(Self, TabIndex, Rect, Active)
  1176. else
  1177. Canvas.FillRect(Rect);
  1178. end;
  1179. function TCnDockCustomTabControl.GetDisplayRect: TRect;
  1180. begin
  1181. Result := ClientRect;
  1182. SendMessage(Handle, TCM_ADJUSTRECT, 0, Integer(@Result));
  1183. if TabPosition = tpTop then
  1184. Inc(Result.Top, 2);
  1185. end;
  1186. function TCnDockCustomTabControl.GetImageIndex(TabIndex: Integer): Integer;
  1187. begin
  1188. Result := TabIndex;
  1189. if Assigned(FOnGetImageIndex) then FOnGetImageIndex(Self, TabIndex, Result);
  1190. end;
  1191. function TCnDockCustomTabControl.GetTabIndex: Integer;
  1192. begin
  1193. Result := SendMessage(Handle, TCM_GETCURSEL, 0, 0);
  1194. end;
  1195. procedure TCnDockCustomTabControl.Loaded;
  1196. begin
  1197. inherited Loaded;
  1198. if Images <> nil then UpdateTabImages;
  1199. end;
  1200. procedure TCnDockCustomTabControl.SetHotTrack(Value: Boolean);
  1201. begin
  1202. if FHotTrack <> Value then
  1203. begin
  1204. FHotTrack := Value;
  1205. RecreateWnd;
  1206. end;
  1207. end;
  1208. procedure TCnDockCustomTabControl.Notification(AComponent: TComponent;
  1209. Operation: TOperation);
  1210. begin
  1211. inherited Notification(AComponent, Operation);
  1212. if (Operation = opRemove) and (AComponent = Images) then
  1213. Images := nil;
  1214. end;
  1215. procedure TCnDockCustomTabControl.SetImages(Value: TCustomImageList);
  1216. begin
  1217. if Images <> nil then
  1218. Images.UnRegisterChanges(FImageChangeLink);
  1219. FImages := Value;
  1220. if Images <> nil then
  1221. begin
  1222. Images.RegisterChanges(FImageChangeLink);
  1223. Images.FreeNotification(Self);
  1224. Perform(TCM_SETIMAGELIST, 0, Images.Handle);
  1225. end
  1226. else Perform(TCM_SETIMAGELIST, 0, 0);
  1227. end;
  1228. procedure TCnDockCustomTabControl.ImageListChange(Sender: TObject);
  1229. begin
  1230. Perform(TCM_SETIMAGELIST, 0, TCustomImageList(Sender).Handle);
  1231. end;
  1232. function TCnDockCustomTabControl.InternalSetMultiLine(Value: Boolean): Boolean;
  1233. begin
  1234. Result := FMultiLine <> Value;
  1235. if Result then
  1236. begin
  1237. if not Value and ((TabPosition = tpLeft) or (TabPosition = tpRight)) then
  1238. TabControlError(sTabMustBeMultiLine);
  1239. FMultiLine := Value;
  1240. if not Value then FScrollOpposite := False;
  1241. end;
  1242. end;
  1243. procedure TCnDockCustomTabControl.SetMultiLine(Value: Boolean);
  1244. begin
  1245. if InternalSetMultiLine(Value) then RecreateWnd;
  1246. end;
  1247. procedure TCnDockCustomTabControl.SetMultiSelect(Value: Boolean);
  1248. begin
  1249. if FMultiSelect <> Value then
  1250. begin
  1251. FMultiSelect := Value;
  1252. RecreateWnd;
  1253. end;
  1254. end;
  1255. procedure TCnDockCustomTabControl.SetOwnerDraw(Value: Boolean);
  1256. begin
  1257. if FOwnerDraw <> Value then
  1258. begin
  1259. FOwnerDraw := Value;
  1260. RecreateWnd;
  1261. end;
  1262. end;
  1263. procedure TCnDockCustomTabControl.SetRaggedRight(Value: Boolean);
  1264. begin
  1265. if FRaggedRight <> Value then
  1266. begin
  1267. FRaggedRight := Value;
  1268. SetComCtlStyle(Self, TCS_RAGGEDRIGHT, Value);
  1269. end;
  1270. end;
  1271. procedure TCnDockCustomTabControl.SetScrollOpposite(Value: Boolean);
  1272. begin
  1273. if FScrollOpposite <> Value then
  1274. begin
  1275. FScrollOpposite := Value;
  1276. if Value then FMultiLine := Value;
  1277. RecreateWnd;
  1278. end;
  1279. end;
  1280. procedure TCnDockCustomTabControl.SetStyle(Value: TTabStyle);
  1281. begin
  1282. if FStyle <> Value then
  1283. begin
  1284. if (Value <> tsTabs) and (TabPosition <> tpTop) then
  1285. raise EInvalidOperation.Create(SInvalidTabStyle);
  1286. FStyle := Value;
  1287. RecreateWnd;
  1288. end;
  1289. end;
  1290. procedure TCnDockCustomTabControl.SetTabHeight(Value: Smallint);
  1291. begin
  1292. if FTabSize.Y <> Value then
  1293. begin
  1294. if Value < 0 then
  1295. raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);
  1296. FTabSize.Y := Value;
  1297. UpdateTabSize;
  1298. end;
  1299. end;
  1300. procedure TCnDockCustomTabControl.SetTabIndex(Value: Integer);
  1301. begin
  1302. SendMessage(Handle, TCM_SETCURSEL, Value, 0);
  1303. end;
  1304. procedure TCnDockCustomTabControl.SetTabPosition(Value: TTabPosition);
  1305. begin
  1306. if FTabPosition <> Value then
  1307. begin
  1308. if (Value <> tpTop) and (Style <> tsTabs) then
  1309. raise EInvalidOperation.Create(SInvalidTabPosition);
  1310. FTabPosition := Value;
  1311. if not MultiLine and ((Value = tpLeft) or (Value = tpRight)) then
  1312. InternalSetMultiLine(True);
  1313. RecreateWnd;
  1314. end;
  1315. end;
  1316. procedure TCnDockCustomTabControl.SetTabs(Value: TStrings);
  1317. begin
  1318. FTabs.Assign(Value);
  1319. end;
  1320. procedure TCnDockCustomTabControl.SetTabWidth(Value: Smallint);
  1321. var
  1322. OldValue: Smallint;
  1323. begin
  1324. if FTabSize.X <> Value then
  1325. begin
  1326. if Value < 0 then
  1327. raise EInvalidOperation.CreateFmt(SPropertyOutOfRange, [Self.Classname]);
  1328. OldValue := FTabSize.X;
  1329. FTabSize.X := Value;
  1330. if (OldValue = 0) or (Value = 0) then RecreateWnd
  1331. else UpdateTabSize;
  1332. end;
  1333. end;
  1334. procedure TCnDockCustomTabControl.TabsChanged;
  1335. begin
  1336. if not FUpdating then
  1337. begin
  1338. if HandleAllocated then
  1339. SendMessage(Handle, WM_SIZE, SIZE_RESTORED,
  1340. Word(Width) or Word(Height) shl 16);
  1341. Realign;
  1342. end;
  1343. end;
  1344. procedure TCnDockCustomTabControl.UpdateTabSize;
  1345. begin
  1346. SendMessage(Handle, TCM_SETITEMSIZE, 0, Integer(FTabSize));
  1347. TabsChanged;
  1348. end;
  1349. procedure TCnDockCustomTabControl.UpdateTabImages;
  1350. var
  1351. I: Integer;
  1352. TCItem: TTCItem;
  1353. begin
  1354. TCItem.mask := TCIF_IMAGE;
  1355. for I := 0 to FTabs.Count - 1 do
  1356. begin
  1357. TCItem.iImage := GetImageIndex(I);
  1358. if SendMessage(Handle, TCM_SETITEM, I,
  1359. Longint(@TCItem)) = 0 then
  1360. TabControlError(Format(sTabFailSet, [FTabs[I], I]));
  1361. end;
  1362. TabsChanged;
  1363. end;
  1364. procedure TCnDockCustomTabControl.CNDrawItem(var Message: TWMDrawItem);
  1365. var
  1366. SaveIndex: Integer;
  1367. begin
  1368. with Message.DrawItemStruct^ do
  1369. begin
  1370. SaveIndex := SaveDC(hDC);
  1371. Canvas.Lock;
  1372. try
  1373. Canvas.Handle := hDC;
  1374. Canvas.Font := Font;
  1375. Canvas.Brush := Brush;
  1376. DrawTab(itemID, rcItem, itemState and ODS_SELECTED <> 0);
  1377. finally
  1378. Canvas.Handle := 0;
  1379. Canvas.Unlock;
  1380. RestoreDC(hDC, SaveIndex);
  1381. end;
  1382. end;
  1383. Message.Result := 1;
  1384. end;
  1385. procedure TCnDockCustomTabControl.WMDestroy(var Message: TWMDestroy);
  1386. var
  1387. FocusHandle: HWnd;
  1388. begin
  1389. if (FTabs <> nil) and (FTabs.Count > 0) then
  1390. begin
  1391. FSaveTabs := TStringList.Create;
  1392. FSaveTabs.Assign(FTabs);
  1393. FSaveTabIndex := GetTabIndex;
  1394. end;
  1395. FocusHandle := GetFocus;
  1396. if (FocusHandle <> 0) and ((FocusHandle = Handle) or
  1397. IsChild(Handle, FocusHandle)) then
  1398. Windows.SetFocus(0);
  1399. inherited;
  1400. WindowHandle := 0;
  1401. end;
  1402. procedure TCnDockCustomTabControl.WMNotifyFormat(var Message: TMessage);
  1403. begin
  1404. with Message do
  1405. Result := DefWindowProc(Handle, Msg, WParam, LParam);
  1406. end;
  1407. procedure TCnDockCustomTabControl.WMSize(var Message: TMessage);
  1408. begin
  1409. inherited;
  1410. RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_ERASE);
  1411. end;
  1412. procedure TCnDockCustomTabControl.CMFontChanged(var Message);
  1413. begin
  1414. inherited;
  1415. if HandleAllocated then Perform(WM_SIZE, 0, 0);
  1416. end;
  1417. procedure TCnDockCustomTabControl.CMSysColorChange(var Message: TMessage);
  1418. begin
  1419. inherited;
  1420. if not (csLoading in ComponentState) then
  1421. begin
  1422. Message.Msg := WM_SYSCOLORCHANGE;
  1423. DefaultHandler(Message);
  1424. end;
  1425. end;
  1426. procedure TCnDockCustomTabControl.CMTabStopChanged(var Message: TMessage);
  1427. begin
  1428. if not (csDesigning in ComponentState) then RecreateWnd;
  1429. end;
  1430. procedure TCnDockCustomTabControl.CNNotify(var Message: TWMNotify);
  1431. begin
  1432. with Message do
  1433. case NMHdr^.code of
  1434. TCN_SELCHANGE:
  1435. Change;
  1436. TCN_SELCHANGING:
  1437. begin
  1438. Result := 1;
  1439. if CanChange then Result := 0;
  1440. end;
  1441. end;
  1442. end;
  1443. procedure TCnDockCustomTabControl.CMDialogChar(var Message: TCMDialogChar);
  1444. var
  1445. I: Integer;
  1446. begin
  1447. for I := 0 to FTabs.Count - 1 do
  1448. if IsAccel(Message.CharCode, FTabs[I]) and CanShowTab(I) and CanFocus then
  1449. begin
  1450. Message.Result := 1;
  1451. if CanChange then
  1452. begin
  1453. TabIndex := I;
  1454. Change;
  1455. end;
  1456. Exit;
  1457. end;
  1458. inherited;
  1459. end;
  1460. procedure TCnDockCustomTabControl.AdjustClientRect(var Rect: TRect);
  1461. begin
  1462. Rect := DisplayRect;
  1463. inherited AdjustClientRect(Rect);
  1464. end;
  1465. function TCnDockCustomTabControl.IndexOfTabAt(X, Y: Integer): Integer;
  1466. var
  1467. HitTest: TTCHitTestInfo;
  1468. begin
  1469. Result := -1;
  1470. if PtInRect(ClientRect, Point(X, Y)) then
  1471. with HitTest do
  1472. begin
  1473. pt.X := X;
  1474. pt.Y := Y;
  1475. Result := TabCtrl_HitTest(Handle, @HitTest);
  1476. end;
  1477. end;
  1478. function TCnDockCustomTabControl.GetHitTestInfoAt(X, Y: Integer): THitTests;
  1479. var
  1480. HitTest: TTCHitTestInfo;
  1481. begin
  1482. Result := [];
  1483. if PtInRect(ClientRect, Point(X, Y)) then
  1484. with HitTest do
  1485. begin
  1486. pt.X := X;
  1487. pt.Y := Y;
  1488. if TabCtrl_HitTest(Handle, @HitTest) <> -1 then
  1489. begin
  1490. if (flags and TCHT_NOWHERE) <> 0 then
  1491. Include(Result, htNowhere);
  1492. if (flags and TCHT_ONITEM) = TCHT_ONITEM then
  1493. Include(Result, htOnItem)
  1494. else
  1495. begin
  1496. if (flags and TCHT_ONITEM) <> 0 then
  1497. Include(Result, htOnItem);
  1498. if (flags and TCHT_ONITEMICON) <> 0 then
  1499. Include(Result, htOnIcon);
  1500. if (flags and TCHT_ONITEMLABEL) <> 0 then
  1501. Include(Result, htOnLabel);
  1502. end;
  1503. end
  1504. else
  1505. Result := [htNowhere];
  1506. end;
  1507. end;
  1508. function TCnDockCustomTabControl.TabRect(Index: Integer): TRect;
  1509. begin
  1510. TabCtrl_GetItemRect(Handle, Index, Result);
  1511. end;
  1512. function TCnDockCustomTabControl.RowCount: Integer;
  1513. begin
  1514. Result := TabCtrl_GetRowCount(Handle);
  1515. end;
  1516. procedure TCnDockCustomTabControl.ScrollTabs(Delta: Integer);
  1517. var
  1518. Wnd: HWND;
  1519. P: TPoint;
  1520. Rect: TRect;
  1521. I: Integer;
  1522. begin
  1523. Wnd := FindWindowEx(Handle, 0, 'msctls_updown32', nil);
  1524. if Wnd <> 0 then
  1525. begin
  1526. Windows.GetClientRect(Wnd, Rect);
  1527. if Delta < 0 then
  1528. P.X := Rect.Left + 2
  1529. else
  1530. P.X := Rect.Right - 2;
  1531. P.Y := Rect.Top + 2;
  1532. for I := 0 to Abs(Delta) - 1 do
  1533. begin
  1534. SendMessage(Wnd, WM_LBUTTONDOWN, 0, MakeLParam(P.X, P.Y));
  1535. SendMessage(Wnd, WM_LBUTTONUP, 0, MakeLParam(P.X, P.Y));
  1536. end;
  1537. end;
  1538. end;
  1539. procedure TCnDockCustomTabControl.TCMAdjustRect(var Message: TMessage);
  1540. begin
  1541. { Major hack around a problem in the Windows tab control. Don't try this
  1542. at home. The tab control (4.71) will AV when in a TCM_ADJUSTRECT message
  1543. when the height of the control is the same as the height of the tab (or the
  1544. width of the control for tpBottom). This hack will return the last value
  1545. successfully returned if an exception is encountered. This allows the
  1546. control to function but the AV is till generated and and reported by the
  1547. debugger. }
  1548. try
  1549. inherited;
  1550. if (TabPosition <> tpTop) and (Message.WParam = 0) then
  1551. FSavedAdjustRect := PRect(Message.LParam)^;
  1552. except
  1553. PRect(Message.LParam)^ := FSavedAdjustRect;
  1554. end;
  1555. end;
  1556. procedure TCnDockCustomTabControl.PaintWindow(DC: HDC);
  1557. var
  1558. Message: TMessage;
  1559. begin
  1560. if not OwnerDraw then
  1561. begin
  1562. { 如果不是自己画,就调用系统的重画事件 }
  1563. Message.Msg := WM_PAINT;
  1564. Message.WParam := DC;
  1565. Message.LParam := 0;
  1566. Message.Result := 0;
  1567. DefaultHandler(Message);
  1568. end;
  1569. inherited PaintWindow(DC);
  1570. end;
  1571. { TCnDockTabSheet }
  1572. constructor TCnDockTabSheet.Create(AOwner: TComponent);
  1573. begin
  1574. inherited Create(AOwner);
  1575. Align := alClient;
  1576. ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible];
  1577. Visible := False;
  1578. FTabVisible := True;
  1579. FHighlighted := False;
  1580. end;
  1581. destructor TCnDockTabSheet.Destroy;
  1582. begin
  1583. if FPageControl <> nil then
  1584. begin
  1585. if FPageControl.FUndockingPage = Self then FPageControl.FUndockingPage := nil;
  1586. FPageControl.RemovePage(Self);
  1587. end;
  1588. inherited Destroy;
  1589. end;
  1590. procedure TCnDockTabSheet.DoHide;
  1591. begin
  1592. if Assigned(FOnHide) then FOnHide(Self);
  1593. end;
  1594. procedure TCnDockTabSheet.DoShow;
  1595. begin
  1596. if Assigned(FOnShow) then FOnShow(Self);
  1597. end;
  1598. function TCnDockTabSheet.GetPageIndex: Integer;
  1599. begin
  1600. if (FPageControl <> nil) and (FPageControl.FPages <> nil) then
  1601. Result := FPageControl.FPages.IndexOf(Self)
  1602. else Result := -1;
  1603. end;
  1604. function TCnDockTabSheet.GetTabIndex: Integer;
  1605. var
  1606. I: Integer;
  1607. begin
  1608. Result := 0;
  1609. if not FTabShowing then Dec(Result) else
  1610. for I := 0 to PageIndex - 1 do
  1611. if TCnDockTabSheet(FPageControl.FPages[I]).FTabShowing then
  1612. Inc(Result);
  1613. end;
  1614. procedure TCnDockTabSheet.CreateParams(var Params: TCreateParams);
  1615. begin
  1616. inherited CreateParams(Params);
  1617. with Params.WindowClass do
  1618. style := style and not (CS_HREDRAW or CS_VREDRAW);
  1619. end;
  1620. procedure TCnDockTabSheet.ReadState(Reader: TReader);
  1621. begin
  1622. inherited ReadState(Reader);
  1623. if Reader.Parent is TCnDockPageControl then
  1624. PageControl := TCnDockPageControl(Reader.Parent);
  1625. end;
  1626. procedure TCnDockTabSheet.SetImageIndex(Value: TImageIndex);
  1627. begin
  1628. if FImageIndex <> Value then
  1629. begin
  1630. FImageIndex := Value;
  1631. if FTabShowing then FPageControl.UpdateTab(Self);
  1632. end;
  1633. end;
  1634. procedure TCnDockTabSheet.SetPageControl(APageControl: TCnDockPageControl);
  1635. begin
  1636. if FPageControl <> APageControl then
  1637. begin
  1638. if FPageControl <> nil then FPageControl.RemovePage(Self);
  1639. Parent := APageControl;
  1640. if APageControl <> nil then APageControl.InsertPage(Self);
  1641. end;
  1642. end;
  1643. procedure TCnDockTabSheet.SetPageIndex(Value: Integer);
  1644. var
  1645. I, MaxPageIndex: Integer;
  1646. begin
  1647. if (FPageControl <> nil) and (FPageControl.FPages <> nil) then
  1648. begin
  1649. MaxPageIndex := FPageControl.FPages.Count - 1;
  1650. if Value > MaxPageIndex then
  1651. raise EListError.CreateResFmt(@SPageIndexError, [Value, MaxPageIndex]);
  1652. I := TabIndex;
  1653. FPageControl.FPages.Move(PageIndex, Value);
  1654. if I >= 0 then FPageControl.MoveTab(I, TabIndex);
  1655. end;
  1656. end;
  1657. procedure TCnDockTabSheet.SetTabShowing(Value: Boolean);
  1658. var
  1659. Index: Integer;
  1660. begin
  1661. if FTabShowing <> Value then
  1662. if Value then
  1663. begin
  1664. FTabShowing := True;
  1665. FPageControl.InsertTab(Self);
  1666. end else
  1667. begin
  1668. Index := TabIndex;
  1669. FTabShowing := False;
  1670. FPageControl.DeleteTab(Self, Index);
  1671. end;
  1672. end;
  1673. procedure TCnDockTabSheet.SetTabVisible(Value: Boolean);
  1674. begin
  1675. if FTabVisible <> Value then
  1676. begin
  1677. FTabVisible := Value;
  1678. UpdateTabShowing;
  1679. end;
  1680. end;
  1681. procedure TCnDockTabSheet.UpdateTabShowing;
  1682. begin
  1683. SetTabShowing((FPageControl <> nil) and FTabVisible);
  1684. end;
  1685. procedure TCnDockTabSheet.CMTextChanged(var Message: TMessage);
  1686. begin
  1687. if FTabShowing then FPageControl.UpdateTab(Self);
  1688. end;
  1689. procedure TCnDockTabSheet.CMShowingChanged(var Message: TMessage);
  1690. begin
  1691. inherited;
  1692. if Showing then
  1693. begin
  1694. try
  1695. DoShow
  1696. except
  1697. Application.HandleException(Self);
  1698. end;
  1699. end else if not Showing then
  1700. begin
  1701. try
  1702. DoHide;
  1703. except
  1704. Application.HandleException(Self);
  1705. end;
  1706. end;
  1707. end;
  1708. procedure TCnDockTabSheet.SetHighlighted(Value: Boolean);
  1709. begin
  1710. if not (csReading in ComponentState) then
  1711. SendMessage(PageControl.Handle, TCM_HIGHLIGHTITEM, TabIndex,
  1712. MakeLong(Word(Value), 0));
  1713. FHighlighted := Value;
  1714. end;
  1715. { TCnDockPageControl }
  1716. constructor TCnDockPageControl.Create(AOwner: TComponent);
  1717. begin
  1718. inherited Create(AOwner);
  1719. ControlStyle := [csDoubleClicks, csOpaque];
  1720. FPages := TList.Create;
  1721. FCnDockTabSheetClass := TCnDockTabSheet;
  1722. end;
  1723. destructor TCnDockPageControl.Destroy;
  1724. var
  1725. I: Integer;
  1726. begin
  1727. for I := 0 to FPages.Count - 1 do TCnDockTabSheet(FPages[I]).FPageControl := nil;
  1728. FPages.Free;
  1729. inherited Destroy;
  1730. end;
  1731. procedure TCnDockPageControl.UpdateTabHighlights;
  1732. var
  1733. I: Integer;
  1734. begin
  1735. for I := 0 to PageCount - 1 do
  1736. Pages[I].SetHighlighted(Pages[I].FHighlighted);
  1737. end;
  1738. procedure TCnDockPageControl.Loaded;
  1739. begin
  1740. inherited Loaded;
  1741. UpdateTabHighlights;
  1742. end;
  1743. function TCnDockPageControl.CanShowTab(TabIndex: Integer): Boolean;
  1744. begin
  1745. Result := TCnDockTabSheet(FPages[TabIndex]).Enabled;
  1746. end;
  1747. procedure TCnDockPageControl.Change;
  1748. var
  1749. Form: TCustomForm;
  1750. begin
  1751. if TabIndex >= 0 then
  1752. UpdateActivePage;
  1753. if csDesigning in ComponentState then
  1754. begin
  1755. Form := GetParentForm(Self);
  1756. if (Form <> nil) and (Form.Designer <> nil) then Form.Designer.Modified;
  1757. end;
  1758. inherited Change;
  1759. end;
  1760. procedure TCnDockPageControl.ChangeActivePage(Page: TCnDockTabSheet);
  1761. var
  1762. ParentForm: TCustomForm;
  1763. begin
  1764. if FActivePage <> Page then
  1765. begin
  1766. ParentForm := GetParentForm(Self);
  1767. if (ParentForm <> nil) and (FActivePage <> nil) and
  1768. FActivePage.ContainsControl(ParentForm.ActiveControl) then
  1769. begin
  1770. ParentForm.ActiveControl := FActivePage;
  1771. if ParentForm.ActiveControl <> FActivePage then
  1772. begin
  1773. TabIndex := FActivePage.TabIndex;
  1774. Exit;
  1775. end;
  1776. end;
  1777. if Page <> nil then
  1778. begin
  1779. Page.BringToFront;
  1780. Page.Visible := True;
  1781. if (ParentForm <> nil) and (FActivePage <> nil) and
  1782. (ParentForm.ActiveControl = FActivePage) then
  1783. if Page.CanFocus then
  1784. ParentForm.ActiveControl := Page else
  1785. ParentForm.ActiveControl := Self;
  1786. end;
  1787. if FActivePage <> nil then FActivePage.Visible := False;
  1788. FActivePage := Page;
  1789. if (ParentForm <> nil) and (FActivePage <> nil) and
  1790. (ParentForm.ActiveControl = FActivePage) then
  1791. FActivePage.SelectFirst;
  1792. end;
  1793. end;
  1794. procedure TCnDockPageControl.DeleteTab(Page: TCnDockTabSheet; Index: Integer);
  1795. var
  1796. UpdateIndex: Boolean;
  1797. begin
  1798. UpdateIndex := Page = ActivePage;
  1799. Tabs.Delete(Index);
  1800. if UpdateIndex then
  1801. begin
  1802. if Index >= Tabs.Count then
  1803. Index := Tabs.Count - 1;
  1804. TabIndex := Index;
  1805. end;
  1806. UpdateActivePage;
  1807. end;
  1808. procedure TCnDockPageControl.DoAddDockClient(Client: TControl; const ARect: TRect);
  1809. begin
  1810. if FNewDockSheet <> nil then Client.Parent := FNewDockSheet;
  1811. end;
  1812. procedure TCnDockPageControl.DockOver(Source: TDragDockObject; X, Y: Integer;
  1813. State: TDragState; var Accept: Boolean);
  1814. var
  1815. R: TRect;
  1816. begin
  1817. GetWindowRect(Handle, R);
  1818. Source.DockRect := R;
  1819. DoDockOver(Source, X, Y, State, Accept);
  1820. end;
  1821. procedure TCnDockPageControl.DoRemoveDockClient(Client: TControl);
  1822. begin
  1823. if (FUndockingPage <> nil) and not (csDestroying in ComponentState) then
  1824. begin
  1825. SelectNextPage(True);
  1826. FUndockingPage.Free;
  1827. FUndockingPage := nil;
  1828. end;
  1829. end;
  1830. function TCnDockPageControl.FindNextPage(CurPage: TCnDockTabSheet;
  1831. GoForward, CheckTabVisible: Boolean): TCnDockTabSheet;
  1832. var
  1833. I, StartIndex: Integer;
  1834. begin
  1835. if FPages.Count <> 0 then
  1836. begin
  1837. StartIndex := FPages.IndexOf(CurPage);
  1838. if StartIndex = -1 then
  1839. if GoForward then StartIndex := FPages.Count - 1 else StartIndex := 0;
  1840. I := StartIndex;
  1841. repeat
  1842. if GoForward then
  1843. begin
  1844. Inc(I);
  1845. if I = FPages.Count then I := 0;
  1846. end else
  1847. begin
  1848. if I = 0 then I := FPages.Count;
  1849. Dec(I);
  1850. end;
  1851. Result := FPages[I];
  1852. if not CheckTabVisible or Result.TabVisible then Exit;
  1853. until I = StartIndex;
  1854. end;
  1855. Result := nil;
  1856. end;
  1857. procedure TCnDockPageControl.GetChildren(Proc: TGetChildProc; Root: TComponent);
  1858. var
  1859. I: Integer;
  1860. begin
  1861. for I := 0 to FPages.Count - 1 do Proc(TComponent(FPages[I]));
  1862. end;
  1863. function TCnDockPageControl.GetImageIndex(TabIndex: Integer): Integer;
  1864. var
  1865. I,
  1866. Visible,
  1867. NotVisible: Integer;
  1868. begin
  1869. if Assigned(FOnGetImageIndex) then
  1870. Result := inherited GetImageIndex(TabIndex) else
  1871. begin
  1872. { For a PageControl, TabIndex refers to visible tabs only. The control
  1873. doesn't store }
  1874. Visible := 0;
  1875. NotVisible := 0;
  1876. for I := 0 to FPages.Count - 1 do
  1877. begin
  1878. if not GetPage(I).TabVisible then Inc(NotVisible)
  1879. else Inc(Visible);
  1880. if Visible = TabIndex + 1 then Break;
  1881. end;
  1882. // Result := 0;
  1883. // if TabIndex + NotVisible >= PageCount then Exit;
  1884. Result := GetPage(TabIndex + NotVisible).ImageIndex;
  1885. end;
  1886. end;
  1887. function TCnDockPageControl.GetPageFromDockClient(Client: TControl): TCnDockTabSheet;
  1888. var
  1889. I: Integer;
  1890. begin
  1891. Result := nil;
  1892. for I := 0 to PageCount - 1 do
  1893. begin
  1894. if (Client.Parent = Pages[I]) and (Client.HostDockSite = Self) then
  1895. begin
  1896. Result := Pages[I];
  1897. Exit;
  1898. end;
  1899. end;
  1900. end;
  1901. function TCnDockPageControl.GetPage(Index: Integer): TCnDockTabSheet;
  1902. begin
  1903. Result := FPages[Index];
  1904. end;
  1905. function TCnDockPageControl.GetPageCount: Integer;
  1906. begin
  1907. Result := FPages.Count;
  1908. end;
  1909. procedure TCnDockPageControl.GetSiteInfo(Client: TControl; var InfluenceRect: TRect;
  1910. MousePos: TPoint; var CanDock: Boolean);
  1911. begin
  1912. CanDock := GetPageFromDockClient(Client) = nil;
  1913. inherited GetSiteInfo(Client, InfluenceRect, MousePos, CanDock);
  1914. end;
  1915. procedure TCnDockPageControl.InsertPage(Page: TCnDockTabSheet);
  1916. begin
  1917. FPages.Add(Page);
  1918. Page.FPageControl := Self;
  1919. Page.UpdateTabShowing;
  1920. end;
  1921. procedure TCnDockPageControl.InsertTab(Page: TCnDockTabSheet);
  1922. begin
  1923. Tabs.InsertObject(Page.TabIndex, Page.Caption, Page);
  1924. UpdateActivePage;
  1925. end;
  1926. procedure TCnDockPageControl.MoveTab(CurIndex, NewIndex: Integer);
  1927. begin
  1928. Tabs.Move(CurIndex, NewIndex);
  1929. end;
  1930. procedure TCnDockPageControl.RemovePage(Page: TCnDockTabSheet);
  1931. var
  1932. NextSheet: TCnDockTabSheet;
  1933. begin
  1934. NextSheet := FindNextPage(Page, True, not (csDesigning in ComponentState));
  1935. if NextSheet = Page then NextSheet := nil;
  1936. Page.SetTabShowing(False);
  1937. Page.FPageControl := nil;
  1938. FPages.Remove(Page);
  1939. SetActivePage(NextSheet);
  1940. end;
  1941. procedure TCnDockPageControl.SelectNextPage(GoForward: Boolean; CheckTabVisible: Boolean = True);
  1942. var
  1943. Page: TCnDockTabSheet;
  1944. begin
  1945. Page := FindNextPage(ActivePage, GoForward, CheckTabVisible);
  1946. if (Page <> nil) and (Page <> ActivePage) and CanChange then
  1947. begin
  1948. SetActivePage(Page);
  1949. Change;
  1950. end;
  1951. end;
  1952. procedure TCnDockPageControl.SetActivePage(Page: TCnDockTabSheet);
  1953. begin
  1954. if (Page <> nil) and (Page.PageControl <> Self) then Exit;
  1955. ChangeActivePage(Page);
  1956. if Page = nil then
  1957. TabIndex := -1
  1958. else if Page = FActivePage then
  1959. TabIndex := Page.TabIndex;
  1960. end;
  1961. procedure TCnDockPageControl.SetChildOrder(Child: TComponent; Order: Integer);
  1962. begin
  1963. TCnDockTabSheet(Child).PageIndex := Order;
  1964. end;
  1965. procedure TCnDockPageControl.ShowControl(AControl: TControl);
  1966. begin
  1967. if (AControl is TCnDockTabSheet) and (TCnDockTabSheet(AControl).PageControl = Self) then
  1968. SetActivePage(TCnDockTabSheet(AControl));
  1969. inherited ShowControl(AControl);
  1970. end;
  1971. procedure TCnDockPageControl.UpdateTab(Page: TCnDockTabSheet);
  1972. begin
  1973. Tabs[Page.TabIndex] := Page.Caption;
  1974. end;
  1975. procedure TCnDockPageControl.UpdateActivePage;
  1976. begin
  1977. if TabIndex >= 0 then
  1978. SetActivePage(TCnDockTabSheet(Tabs.Objects[TabIndex]))
  1979. else
  1980. SetActivePage(nil);
  1981. end;
  1982. procedure TCnDockPageControl.CMDesignHitTest(var Message: TCMDesignHitTest);
  1983. var
  1984. HitIndex: Integer;
  1985. HitTestInfo: TTCHitTestInfo;
  1986. begin
  1987. HitTestInfo.pt := SmallPointToPoint(Message.Pos);
  1988. HitIndex := SendMessage(Handle, TCM_HITTEST, 0, Longint(@HitTestInfo));
  1989. if (HitIndex >= 0) and (HitIndex <> TabIndex) then Message.Result := 1;
  1990. end;
  1991. procedure TCnDockPageControl.CMDialogKey(var Message: TCMDialogKey);
  1992. begin
  1993. if (Focused or Windows.IsChild(Handle, Windows.GetFocus)) and
  1994. (Message.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
  1995. begin
  1996. SelectNextPage(GetKeyState(VK_SHIFT) >= 0);
  1997. Message.Result := 1;
  1998. end else
  1999. inherited;
  2000. end;
  2001. procedure TCnDockPageControl.CMDockClient(var Message: TCMDockClient);
  2002. var
  2003. IsVisible: Boolean;
  2004. DockCtl: TControl;
  2005. begin
  2006. Message.Result := 0;
  2007. if FCnDockTabSheetClass <> nil then
  2008. FNewDockSheet := FCnDockTabSheetClass.Create(Self)
  2009. else FNewDockSheet := TCnDockTabSheet.Create(Self);
  2010. try
  2011. try
  2012. DockCtl := Message.DockSource.Control;
  2013. FNewDockSheet.PageControl := Self;
  2014. if DockCtl is TCustomForm then
  2015. FNewDockSheet.Caption := TCustomForm(DockCtl).Caption;
  2016. DockCtl.Dock(Self, Message.DockSource.DockRect);
  2017. except
  2018. FNewDockSheet.Free;
  2019. raise;
  2020. end;
  2021. IsVisible := DockCtl.Visible;
  2022. FNewDockSheet.TabVisible := IsVisible;
  2023. if IsVisible then ActivePage := FNewDockSheet;
  2024. DockCtl.Align := alClient;
  2025. finally
  2026. FNewDockSheet := nil;
  2027. end;
  2028. end;
  2029. procedure TCnDockPageControl.CMDockNotification(var Message: TCMDockNotification);
  2030. var
  2031. I: Integer;
  2032. S: string;
  2033. Page: TCnDockTabSheet;
  2034. begin
  2035. Page := GetPageFromDockClient(Message.Client);
  2036. if Page <> nil then
  2037. case Message.NotifyRec.ClientMsg of
  2038. WM_SETTEXT:
  2039. begin
  2040. S := PChar(Message.NotifyRec.MsgLParam);
  2041. { Search for first CR/LF and end string there }
  2042. for I := 1 to Length(S) do
  2043. if {$IFDEF UNICODE}CharInSet(S[i], [#13, #10]){$ELSE}S[I] in [#13, #10]{$ENDIF} then
  2044. begin
  2045. SetLength(S, I - 1);
  2046. Break;
  2047. end;
  2048. Page.Caption := S;
  2049. end;
  2050. CM_VISIBLECHANGED:
  2051. Page.TabVisible := Boolean(Message.NotifyRec.MsgWParam);
  2052. end;
  2053. inherited;
  2054. end;
  2055. procedure TCnDockPageControl.CMUnDockClient(var Message: TCMUnDockClient);
  2056. var
  2057. Page: TCnDockTabSheet;
  2058. begin
  2059. Message.Result := 0;
  2060. Page := GetPageFromDockClient(Message.Client);
  2061. if Page <> nil then
  2062. begin
  2063. FUndockingPage := Page;
  2064. Message.Client.Align := alNone;
  2065. end;
  2066. end;
  2067. function TCnDockPageControl.GetDockClientFromMousePos(MousePos: TPoint): TControl;
  2068. var
  2069. i, HitIndex: Integer;
  2070. HitTestInfo: TTCHitTestInfo;
  2071. Page: TCnDockTabSheet;
  2072. begin
  2073. Result := nil;
  2074. if DockSite then
  2075. begin
  2076. HitTestInfo.pt := MousePos;
  2077. HitIndex := SendMessage(Handle, TCM_HITTEST, 0, Longint(@HitTestInfo));
  2078. if HitIndex >= 0 then
  2079. begin
  2080. Page := nil;
  2081. for i := 0 to HitIndex do
  2082. Page := FindNextPage(Page, True, True);
  2083. if (Page <> nil) and (Page.ControlCount > 0) then
  2084. begin
  2085. Result := Page.Controls[0];
  2086. if Result.HostDockSite <> Self then Result := nil;
  2087. end;
  2088. end;
  2089. end;
  2090. end;
  2091. procedure TCnDockPageControl.WMLButtonDown(var Message: TWMLButtonDown);
  2092. var
  2093. DockCtl: TControl;
  2094. begin
  2095. inherited;
  2096. if GlobalDockClient <> nil then
  2097. DockCtl := ButtonEvent(Self, Message, mbLeft, msTabPage, GlobalDockClient.DoNCButtonDown)
  2098. else DockCtl := nil;
  2099. if (DockCtl <> nil) and (Style = tsTabs) then
  2100. { 如果条件都满足,就调用CnGlobalDockPresident的BeginDrag方法,开始停靠操作 }
  2101. CnGlobalDockPresident.BeginDrag(DockCtl, False);
  2102. end;
  2103. procedure TCnDockPageControl.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  2104. var
  2105. DockCtl: TControl;
  2106. begin
  2107. inherited;
  2108. if GlobalDockClient <> nil then
  2109. DockCtl := ButtonEvent(Self, Message, mbLeft, msTabPage, GlobalDockClient.DoNCButtonDblClk)
  2110. else DockCtl := nil;
  2111. if (DockCtl <> nil) and (GlobalDockClient.CanFloat) then
  2112. DockCtl.ManualDock(nil, nil, alNone);
  2113. end;
  2114. function TCnDockPageControl.GetActivePageIndex: Integer;
  2115. begin
  2116. if ActivePage <> nil then
  2117. Result := ActivePage.GetPageIndex
  2118. else
  2119. Result := -1;
  2120. end;
  2121. procedure TCnDockPageControl.SetActivePageIndex(const Value: Integer);
  2122. begin
  2123. if (Value > -1) and (Value < PageCount) then
  2124. ActivePage := Pages[Value]
  2125. else
  2126. ActivePage := nil;
  2127. end;
  2128. { TTabStrings }
  2129. procedure TCnDockTabStrings.Clear;
  2130. begin
  2131. if SendMessage(FTabControl.Handle, TCM_DELETEALLITEMS, 0, 0) = 0 then
  2132. TabControlError(sTabFailClear);
  2133. FTabControl.TabsChanged;
  2134. end;
  2135. procedure TCnDockTabStrings.Delete(Index: Integer);
  2136. begin
  2137. if SendMessage(FTabControl.Handle, TCM_DELETEITEM, Index, 0) = 0 then
  2138. TabControlError(Format(sTabFailDelete, [Index]));
  2139. FTabControl.TabsChanged;
  2140. end;
  2141. function TCnDockTabStrings.Get(Index: Integer): string;
  2142. const
  2143. RTL: array[Boolean] of LongInt = (0, TCIF_RTLREADING);
  2144. var
  2145. TCItem: TTCItem;
  2146. Buffer: array[0..4095] of Char;
  2147. begin
  2148. TCItem.mask := TCIF_TEXT or RTL[FTabControl.UseRightToLeftReading];
  2149. TCItem.pszText := Buffer;
  2150. TCItem.cchTextMax := SizeOf(Buffer);
  2151. if SendMessage(FTabControl.Handle, TCM_GETITEM, Index,
  2152. Longint(@TCItem)) = 0 then
  2153. TabControlError(Format(sTabFailRetrieve, [Index]));
  2154. Result := Buffer;
  2155. end;
  2156. function TCnDockTabStrings.GetCount: Integer;
  2157. begin
  2158. Result := SendMessage(FTabControl.Handle, TCM_GETITEMCOUNT, 0, 0);
  2159. end;
  2160. function TCnDockTabStrings.GetObject(Index: Integer): TObject;
  2161. var
  2162. TCItem: TTCItem;
  2163. begin
  2164. TCItem.mask := TCIF_PARAM;
  2165. if SendMessage(FTabControl.Handle, TCM_GETITEM, Index,
  2166. Longint(@TCItem)) = 0 then
  2167. TabControlError(Format(sTabFailGetObject, [Index]));
  2168. Result := TObject(TCItem.lParam);
  2169. end;
  2170. procedure TCnDockTabStrings.Put(Index: Integer; const S: string);
  2171. const
  2172. RTL: array[Boolean] of LongInt = (0, TCIF_RTLREADING);
  2173. var
  2174. TCItem: TTCItem;
  2175. begin
  2176. TCItem.mask := TCIF_TEXT or RTL[FTabControl.UseRightToLeftReading] or
  2177. TCIF_IMAGE;
  2178. TCItem.pszText := PChar(S);
  2179. TCItem.iImage := FTabControl.GetImageIndex(Index);
  2180. if SendMessage(FTabControl.Handle, TCM_SETITEM, Index,
  2181. Longint(@TCItem)) = 0 then
  2182. TabControlError(Format(sTabFailSet, [S, Index]));
  2183. FTabControl.TabsChanged;
  2184. end;
  2185. procedure TCnDockTabStrings.PutObject(Index: Integer; AObject: TObject);
  2186. var
  2187. TCItem: TTCItem;
  2188. begin
  2189. TCItem.mask := TCIF_PARAM;
  2190. TCItem.lParam := Longint(AObject);
  2191. if SendMessage(FTabControl.Handle, TCM_SETITEM, Index,
  2192. Longint(@TCItem)) = 0 then
  2193. TabControlError(Format(sTabFailSetObject, [Index]));
  2194. end;
  2195. procedure TCnDockTabStrings.Insert(Index: Integer; const S: string);
  2196. const
  2197. RTL: array[Boolean] of LongInt = (0, TCIF_RTLREADING);
  2198. var
  2199. TCItem: TTCItem;
  2200. begin
  2201. TCItem.mask := TCIF_TEXT or RTL[FTabControl.UseRightToLeftReading] or
  2202. TCIF_IMAGE;
  2203. TCItem.pszText := PChar(S);
  2204. TCItem.iImage := FTabControl.GetImageIndex(Index);
  2205. if SendMessage(FTabControl.Handle, TCM_INSERTITEM, Index,
  2206. Longint(@TCItem)) < 0 then
  2207. TabControlError(Format(sTabFailSet, [S, Index]));
  2208. FTabControl.TabsChanged;
  2209. end;
  2210. procedure TCnDockTabStrings.SetUpdateState(Updating: Boolean);
  2211. begin
  2212. FTabControl.FUpdating := Updating;
  2213. SendMessage(FTabControl.Handle, WM_SETREDRAW, Ord(not Updating), 0);
  2214. if not Updating then
  2215. begin
  2216. FTabControl.Invalidate;
  2217. FTabControl.TabsChanged;
  2218. end;
  2219. end;
  2220. function TCnDockPageControl.DoMouseEvent(var Message: TWMMouse;
  2221. Control: TControl): TWMNCHitMessage;
  2222. begin
  2223. Result := Cn_CreateNCMessage(Control, Message.Msg + WM_NCMOUSEFIRST - WM_MOUSEFIRST,
  2224. HTCAPTION, SmallPointToPoint(Message.Pos));
  2225. end;
  2226. procedure TCnDockPageControl.WMLButtonUp(var Message: TWMLButtonUp);
  2227. begin
  2228. inherited;
  2229. if GlobalDockClient <> nil then
  2230. ButtonEvent(Self, Message, mbLeft, msTabPage, GlobalDockClient.DoNCButtonUp);
  2231. end;
  2232. procedure TCnDockPageControl.WMMButtonDblClk(
  2233. var Message: TWMMButtonDblClk);
  2234. begin
  2235. inherited;
  2236. if GlobalDockClient <> nil then
  2237. ButtonEvent(Self, Message, mbMiddle, msTabPage, GlobalDockClient.DoNCButtonDblClk);
  2238. end;
  2239. procedure TCnDockPageControl.WMMButtonDown(var Message: TWMMButtonDown);
  2240. begin
  2241. inherited;
  2242. if GlobalDockClient <> nil then
  2243. ButtonEvent(Self, Message, mbMiddle, msTabPage, GlobalDockClient.DoNCButtonDown);
  2244. end;
  2245. procedure TCnDockPageControl.WMMButtonUp(var Message: TWMMButtonUp);
  2246. begin
  2247. inherited;
  2248. if GlobalDockClient <> nil then
  2249. ButtonEvent(Self, Message, mbMiddle, msTabPage, GlobalDockClient.DoNCButtonUp);
  2250. end;
  2251. procedure TCnDockPageControl.WMRButtonDblClk(
  2252. var Message: TWMRButtonDblClk);
  2253. begin
  2254. inherited;
  2255. if GlobalDockClient <> nil then
  2256. ButtonEvent(Self, Message, mbRight, msTabPage, GlobalDockClient.DoNCButtonDblClk);
  2257. end;
  2258. procedure TCnDockPageControl.WMRButtonDown(var Message: TWMRButtonDown);
  2259. begin
  2260. { 欺骗系统以为是鼠标左键按下 }
  2261. Message.Msg := WM_LBUTTONDOWN;
  2262. inherited;
  2263. if GlobalDockClient <> nil then
  2264. ButtonEvent(Self, Message, mbRight, msTabPage, GlobalDockClient.DoNCButtonDown);
  2265. end;
  2266. procedure TCnDockPageControl.WMRButtonUp(var Message: TWMRButtonUp);
  2267. begin
  2268. inherited;
  2269. if GlobalDockClient <> nil then
  2270. ButtonEvent(Self, Message, mbRight, msTabPage, GlobalDockClient.DoNCButtonUp);
  2271. end;
  2272. { TCnDockPresident }
  2273. constructor TCnDockPresident.Create;
  2274. begin
  2275. { 创建列表和Hash表 }
  2276. FDockServersList := TList.Create;
  2277. FDockClientsList := TList.Create;
  2278. FDockServersHash := TCnDockControlHashTable.Create(10, False);
  2279. FDockClientsHash := TCnDockControlHashTable.Create(30, False);
  2280. FDockableFormList := TList.Create;
  2281. DockSiteList := TList.Create;
  2282. end;
  2283. destructor TCnDockPresident.Destroy;
  2284. begin
  2285. { 删除列表和Hash表 }
  2286. FDockableFormList.Free;
  2287. FDockServersList.Free;
  2288. FDockClientsList.Free;
  2289. FDockServersHash.Free;
  2290. FDockClientsHash.Free;
  2291. DockSiteList.Free;
  2292. inherited Destroy;
  2293. end;
  2294. function TCnDockPresident.FindDockClientForm(AName: string): TControl;
  2295. var i: Integer;
  2296. begin
  2297. Result := nil;
  2298. for i := 0 to FDockServersList.Count - 1 do
  2299. begin
  2300. if TControl(FDockServersList[i]).Name = AName then
  2301. begin
  2302. Result := TControl(FDockServersList[i]);
  2303. Exit;
  2304. end;
  2305. end;
  2306. end;
  2307. function TCnDockPresident.FindDockServerForm(AName: string): TControl;
  2308. var i: Integer;
  2309. begin
  2310. Result := nil;
  2311. for i := 0 to FDockClientsList.Count - 1 do
  2312. begin
  2313. if TControl(FDockClientsList[i]).Name = AName then
  2314. begin
  2315. Result := TControl(FDockClientsList[i]);
  2316. Exit;
  2317. end;
  2318. end;
  2319. end;
  2320. function TCnDockPresident.FindDockControlForm(AName: string): TControl;
  2321. begin
  2322. Result := FindDockServerForm(AName);
  2323. if Result = nil then
  2324. FindDockClientForm(AName);
  2325. end;
  2326. function TCnDockPresident.GetFormVisible(DockWindow: TWinControl): Boolean;
  2327. begin
  2328. Result := CnDockFormControl.GetFormVisible(DockWindow);
  2329. end;
  2330. procedure TCnDockPresident.HideDockForm(DockWindow: TControl);
  2331. begin
  2332. CnDockFormControl.HideDockForm(DockWindow);
  2333. end;
  2334. procedure TCnDockPresident.LoadDockTreeFromFile(FileName: string);
  2335. begin
  2336. BeginLoad;
  2337. try
  2338. CnDockFormControl.LoadDockTreeFromFile(FileName);
  2339. finally
  2340. EndLoad;
  2341. end;
  2342. end;
  2343. procedure TCnDockPresident.LoadDockTreeFromReg(RootKey: DWORD;
  2344. RegPath: string);
  2345. begin
  2346. BeginLoad;
  2347. try
  2348. CnDockFormControl.LoadDockTreeFromReg(RootKey, RegPath);
  2349. finally
  2350. EndLoad;
  2351. end;
  2352. end;
  2353. procedure TCnDockPresident.SaveDockTreeToFile(FileName: string);
  2354. begin
  2355. BeginSave;
  2356. try
  2357. CnDockFormControl.SaveDockTreeToFile(FileName);
  2358. finally
  2359. EndSave;
  2360. end;
  2361. end;
  2362. procedure TCnDockPresident.SaveDockTreeToReg(RootKey: DWORD;
  2363. RegPath: string);
  2364. begin
  2365. BeginSave;
  2366. try
  2367. CnDockFormControl.SaveDockTreeToReg(RootKey, RegPath);
  2368. finally
  2369. EndSave;
  2370. end;
  2371. end;
  2372. procedure TCnDockPresident.SetConjoinDockHostBorderStyle(
  2373. Value: TFormBorderStyle);
  2374. begin
  2375. CnDockFormControl.SetConjoinDockHostBorderStyle(Value);
  2376. end;
  2377. procedure TCnDockPresident.SetTabDockHostBorderStyle(
  2378. Value: TFormBorderStyle);
  2379. begin
  2380. CnDockFormControl.SetTabDockHostBorderStyle(Value);
  2381. end;
  2382. procedure TCnDockPresident.ShowDockForm(DockWindow: TWinControl);
  2383. begin
  2384. CnDockFormControl.ShowDockForm(DockWindow);
  2385. end;
  2386. procedure TCnDockPresident.BeginLoad;
  2387. var i: Integer;
  2388. begin
  2389. Inc(FLoadCount);
  2390. if FLoadCount = 1 then
  2391. begin
  2392. FDockServersHash.MakeEmpty;
  2393. for i := 0 to FDockServersList.Count - 1 do
  2394. FDockServersHash.Insert(TControl(FDockServersList[i]).Name, FDockServersList[i]);
  2395. FDockClientsHash.MakeEmpty;
  2396. for i := 0 to FDockClientsList.Count - 1 do
  2397. FDockClientsHash.Insert(TControl(FDockClientsList[i]).Name, FDockClientsList[i]);
  2398. end;
  2399. end;
  2400. procedure TCnDockPresident.EndLoad;
  2401. begin
  2402. Dec(FLoadCount);
  2403. if FLoadCount <= 0 then
  2404. begin
  2405. FLoadCount := 0;
  2406. FDockServersHash.MakeEmpty;
  2407. FDockClientsHash.MakeEmpty;
  2408. end;
  2409. end;
  2410. function TCnDockPresident.IsLoading: Boolean;
  2411. begin
  2412. Result := FLoadCount > 0;
  2413. end;
  2414. procedure TCnDockPresident.BeginSave;
  2415. begin
  2416. Inc(FSaveCount);
  2417. end;
  2418. procedure TCnDockPresident.EndSave;
  2419. begin
  2420. Dec(FSaveCount);
  2421. if FSaveCount <= 0 then
  2422. FSaveCount := 0;
  2423. end;
  2424. function TCnDockPresident.IsSaving: Boolean;
  2425. begin
  2426. Result := FSaveCount > 0;
  2427. end;
  2428. procedure TCnDockPresident.AddDockClientToDockManager(
  2429. AControl: TControl);
  2430. begin
  2431. FDockClientsList.Add(AControl);
  2432. FDockClientsHash.Insert(AControl.Name, AControl);
  2433. end;
  2434. procedure TCnDockPresident.AddDockServerToDockManager(
  2435. AControl: TControl);
  2436. begin
  2437. FDockServersList.Add(AControl);
  2438. FDockServersHash.Insert(AControl.Name, AControl);
  2439. end;
  2440. procedure TCnDockPresident.RemoveDockClientFromDockManager(
  2441. AControl: TControl);
  2442. begin
  2443. FDockClientsList.Remove(AControl);
  2444. FDockClientsHash.Remove(AControl.Name);
  2445. end;
  2446. procedure TCnDockPresident.RemoveDockServerFromDockManager(
  2447. AControl: TControl);
  2448. begin
  2449. FDockServersList.Remove(AControl);
  2450. FDockServersHash.Remove(AControl.Name);
  2451. end;
  2452. procedure TCnDockPresident.BeginDrag(Control: TControl; Immediate: Boolean; Threshold: Integer);
  2453. var
  2454. P: TPoint;
  2455. begin
  2456. if (TCnControlAccess(Control).DragKind <> dkDock) then
  2457. { 如果Control的DragKind属性不是dkDock,就推出 }
  2458. Exit;
  2459. // raise EInvalidOperation.CreateRes(@SCannotDragForm);
  2460. CalcDockSizes(Control);
  2461. if (DragControl = nil) or (DragControl = Pointer($FFFFFFFF)) then
  2462. begin
  2463. DragControl := nil;
  2464. if csLButtonDown in Control.ControlState then
  2465. begin
  2466. GetCursorPos(P);
  2467. P := Control.ScreenToClient(P);
  2468. Control.Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
  2469. end;
  2470. { 当Threshold<0的时候,使用默认的值Mouse.DragThreshold }
  2471. if Threshold < 0 then
  2472. Threshold := Mouse.DragThreshold;
  2473. { 防止在BeginDrag里面调用EndDrag }
  2474. if DragControl <> Pointer($FFFFFFFF) then
  2475. DragInitControl(Control, Immediate, Threshold);
  2476. end;
  2477. end;
  2478. procedure TCnDockPresident.DragInitControl(Control: TControl;
  2479. Immediate: Boolean; Threshold: Integer);
  2480. var
  2481. // ADragObject: TCnDragDockObject;
  2482. ARect: TRect;
  2483. procedure DoStartDock;
  2484. begin
  2485. if Assigned(GlobalDockClient) then
  2486. GlobalDockClient.FormStartDock(DragObject);
  2487. if DragObject = nil then
  2488. begin
  2489. DragObject := TCnDragDockObject.Create(Control);
  2490. DragFreeObject := True;
  2491. end;
  2492. end;
  2493. begin
  2494. DragControl := Control;
  2495. try
  2496. DragObject := nil;
  2497. DragFreeObject := False;
  2498. { 调用StartDock事件 }
  2499. DoStartDock;
  2500. if DragControl = nil then Exit;
  2501. with DragObject do
  2502. begin
  2503. if Control.HostDockSite is TCnCustomDockPanel then
  2504. ARect := TCnCustomDockPanel(Control.HostDockSite).CnDockManager.GetFrameRectEx(Control)
  2505. else GetWindowRect(TWinControl(Control).Handle, ARect);
  2506. DockRect := ARect;
  2507. EraseDockRect := DockRect;
  2508. end;
  2509. DragInit(DragObject, Immediate, Threshold);
  2510. except
  2511. DragControl := nil;
  2512. raise;
  2513. end;
  2514. end;
  2515. procedure TCnDockPresident.DragInit(ADragObject: TCnDragDockObject;
  2516. Immediate: Boolean; Threshold: Integer);
  2517. begin
  2518. DragObject := ADragObject;
  2519. DragObject.DragTarget := nil;
  2520. GetCursorPos(DragStartPos);
  2521. DragObject.DragPos := DragStartPos;
  2522. DragSaveCursor := Windows.GetCursor;
  2523. DragCapture := DragObject.Capture;
  2524. DragThreshold := Threshold;
  2525. with ADragObject, DockRect do
  2526. begin
  2527. if Right - Left > 0 then
  2528. MouseDeltaX := (DragPos.x - Left) / (Right - Left) else
  2529. MouseDeltaX := 0;
  2530. if Bottom - Top > 0 then
  2531. MouseDeltaY := (DragPos.y - Top) / (Bottom - Top) else
  2532. MouseDeltaY := 0;
  2533. if Immediate then
  2534. begin
  2535. ActiveDrag := dopDock;
  2536. DrawDragDockImage;
  2537. end
  2538. else ActiveDrag := dopNone;
  2539. end;
  2540. DragImageList := DragObject.GetDragImages;
  2541. if DragImageList <> nil then
  2542. with DragStartPos do DragImageList.BeginDrag(GetDeskTopWindow, X, Y);
  2543. QualifyingSites := TSiteList.Create;
  2544. if ActiveDrag <> dopNone then DragTo(DragStartPos);
  2545. end;
  2546. procedure TCnDockPresident.DragTo(const Pos: TPoint);
  2547. var
  2548. DragCursor: TCursor;
  2549. Target: TControl;
  2550. TargetHandle: HWND;
  2551. DoErase: Boolean;
  2552. TempAlign: TAlign;
  2553. // CanDock: Boolean;
  2554. // R: TRect;
  2555. begin
  2556. if {(ActiveDrag <> dopNone) or }(Abs(DragStartPos.X - Pos.X) >= DragThreshold) or
  2557. (Abs(DragStartPos.Y - Pos.Y) >= DragThreshold) then
  2558. begin
  2559. { 查找到停靠目标 }
  2560. Target := DragFindTarget(Pos, TargetHandle, TCnControlAccess(DragControl).DragKind, DragControl);
  2561. if (ActiveDrag = dopNone) and (DragImageList <> nil) then
  2562. with DragStartPos do DragImageList.BeginDrag(GetDeskTopWindow, X, Y);
  2563. DoErase := ActiveDrag <> dopNone;
  2564. ActiveDrag := dopDock;
  2565. if DragObject.CanLeave(TWinControl(Target)) then
  2566. begin
  2567. DoDockOver(dsDragLeave);
  2568. if DragObject = nil then Exit;
  2569. DragObject.DragTarget := Target;
  2570. DragObject.DragHandle := TargetHandle;
  2571. DragObject.DragPos := Pos;
  2572. DoDockOver(dsDragEnter);
  2573. if DragObject = nil then Exit;
  2574. end;
  2575. DragObject.DragPos := Pos;
  2576. if DragObject.DragTarget <> nil then
  2577. DragObject.DragTargetPos := TControl(DragObject.DragTarget).ScreenToClient(Pos);
  2578. DragCursor := DragObject.GetDragCursor(DoDockOver(dsDragMove), Pos.X, Pos.Y);
  2579. if DragImageList <> nil then
  2580. begin
  2581. if (Target = nil) or (csDisplayDragImage in Target.ControlStyle) then
  2582. begin
  2583. DragImageList.DragCursor := DragCursor;
  2584. if not DragImageList.Dragging then
  2585. DragImageList.BeginDrag(GetDeskTopWindow, Pos.X, Pos.Y)
  2586. else DragImageList.DragMove(Pos.X, Pos.Y);
  2587. end
  2588. else begin
  2589. DragImageList.EndDrag;
  2590. Windows.SetCursor(Screen.Cursors[DragCursor]);
  2591. end;
  2592. end;
  2593. // if Target = nil then DragObject.DropOnControl := nil;
  2594. ResetCursor;
  2595. if ActiveDrag = dopDock then
  2596. begin
  2597. with DragObject do
  2598. begin
  2599. { DoGetSiteInfo(Target, Control, R, Pos, CanDock);
  2600. if not CanDock then
  2601. begin
  2602. Target := nil;
  2603. DropOnControl := nil;
  2604. end;}
  2605. if Target = nil then
  2606. begin
  2607. if Assigned(GlobalDockClient) then
  2608. GlobalDockClient.FormPositionDockRect(DragObject);
  2609. end
  2610. else begin
  2611. { 获得DropOnControl }
  2612. DropOnControl := GetDropCtl;
  2613. TempAlign := DropAlign;
  2614. if DropOnControl = nil then
  2615. DoGetDockEdge(TargetControl, DragTargetPos, TempAlign)
  2616. else
  2617. DoGetDockEdge(DropOnControl, DropOnControl.ScreenToClient(Pos), TempAlign);
  2618. // if TempAlign <> DropAlign then
  2619. DropAlign := TempAlign;
  2620. end;
  2621. end;
  2622. if DragObject <> nil then
  2623. DragObject.DrawDragRect(DoErase);
  2624. end;
  2625. end;
  2626. end;
  2627. function TCnDockPresident.DragFindTarget(const Pos: TPoint; var Handle: HWND;
  2628. DragKind: TDragKind; Client: TControl): Pointer;
  2629. begin
  2630. Result := GetDockSiteAtPos(Pos, Client);
  2631. if Result <> nil then
  2632. Handle := TWinControl(Result).Handle;
  2633. end;
  2634. function TCnDockPresident.DoDockOver(DragState: TDragState): Boolean;
  2635. var Target: TControl;
  2636. DockClient: TCnDockClient;
  2637. begin
  2638. Result := True;
  2639. if DragObject.DragTarget <> nil then
  2640. begin
  2641. Target := TControl(DragObject.DragTarget);
  2642. with Target.ScreenToClient(DragObject.DragPos) do
  2643. if Target is TCnCustomDockControl then
  2644. TCnCustomDockControl(Target).CustomDockOver(DragObject, X, Y, DragState, Result)
  2645. else if Target is TForm then
  2646. begin
  2647. DockClient := FindDockClient(Target);
  2648. if DockClient <> nil then
  2649. DockClient.FormDockOver(DragObject, X, Y, DragState, Result);
  2650. end;
  2651. end;
  2652. end;
  2653. function TCnDockPresident.DragFindWindow(const Pos: TPoint): HWND;
  2654. begin
  2655. Result := DragObject.DragFindWindow(Pos);
  2656. end;
  2657. function TCnDockPresident.GetDockSiteAtPos(MousePos: TPoint;
  2658. Client: TControl): TWinControl;
  2659. var
  2660. I: Integer;
  2661. R: TRect;
  2662. Site: TWinControl;
  2663. CanDock, ControlKeyDown: Boolean;
  2664. function ValidDockTarget(Target: TWinControl): Boolean;
  2665. var
  2666. Info: TCheckTargetInfo;
  2667. Control: TWinControl;
  2668. R1, R2: TRect;
  2669. begin
  2670. Result := True;
  2671. { Find handle for topmost container of current }
  2672. Info.CurrentWnd := DragFindWindow(MousePos);
  2673. if Info.CurrentWnd = 0 then Exit;
  2674. if (GetWindow(Info.CurrentWnd, GW_OWNER) <> Application.Handle) then
  2675. begin
  2676. Control := FindControl(Info.CurrentWnd);
  2677. if Control = nil then Exit;
  2678. while Control.Parent <> nil do Control := Control.Parent;
  2679. Info.CurrentWnd := Control.Handle;
  2680. end;
  2681. { Find handle for topmost container of target }
  2682. Control := Target;
  2683. while Control.Parent <> nil do Control := Control.Parent;
  2684. Info.TargetWnd := Control.Handle;
  2685. if Info.CurrentWnd = Info.TargetWnd then Exit;
  2686. { Find handle for topmost container of client }
  2687. if Client.Parent <> nil then
  2688. begin
  2689. Control := Client.Parent;
  2690. while Control.Parent <> nil do Control := Control.Parent;
  2691. Info.ClientWnd := Control.Handle;
  2692. end
  2693. else if Client is TWinControl then
  2694. Info.ClientWnd := TWinControl(Client).Handle
  2695. else
  2696. Info.ClientWnd := 0;
  2697. Info.Found := False;
  2698. Info.MousePos := MousePos;
  2699. EnumThreadWindows(GetCurrentThreadID, @IsBeforeTargetWindow, Longint(@Info));
  2700. { CurrentWnd is in front of TargetWnd, so check whether they're overlapped. }
  2701. if Info.Found then
  2702. begin
  2703. GetWindowRect(Info.CurrentWnd, R1);
  2704. DoGetSiteInfo(Target, Client, R2, MousePos, CanDock);
  2705. // TCnWinControlAccess(Target).GetSiteInfo(Client, R2, MousePos, CanDock);
  2706. { Docking control's host shouldn't count as an overlapped window }
  2707. if (DragObject.Control.HostDockSite <> nil)
  2708. and (DragObject.Control.HostDockSite.Handle = Info.CurrentWnd) then
  2709. Exit;
  2710. if IntersectRect(R1, R1, R2) then
  2711. Result := False;
  2712. end;
  2713. end;
  2714. function IsSiteChildOfClient: Boolean;
  2715. begin
  2716. if Client is TWinControl then
  2717. Result := IsChild(TWinControl(Client).Handle, Site.Handle)
  2718. else
  2719. Result := False;
  2720. end;
  2721. begin
  2722. Result := nil;
  2723. ControlKeyDown := (GetKeyState(VK_CONTROL) and not $7FFF) <> 0;
  2724. if (DockSiteList = nil) or ControlKeyDown then Exit;
  2725. QualifyingSites.Clear;
  2726. for I := 0 to DockSiteList.Count - 1 do
  2727. begin
  2728. Site := TWinControl(DockSiteList[I]);
  2729. if (Site <> Client) and Site.Showing and Site.Enabled and
  2730. IsWindowVisible(Site.Handle) and (not IsSiteChildOfClient) //and
  2731. {((Client.HostDockSite <> Site) or (Site.VisibleDockClientCount > 1)) }then
  2732. begin
  2733. CanDock := True;
  2734. DoGetSiteInfo(Site, Client, R, MousePos, CanDock);
  2735. if CanDock and PtInRect(R, MousePos) then
  2736. QualifyingSites.AddSite(Site);
  2737. end;
  2738. end;
  2739. if QualifyingSites.Count > 0 then
  2740. Result := QualifyingSites.GetTopSite;
  2741. if (Result <> nil) and not ValidDockTarget(Result) then
  2742. Result := nil;
  2743. { if Result <> nil then
  2744. begin
  2745. DoGetSiteInfo(Site, Client, R, MousePos, CanDock);
  2746. if not CanDock then
  2747. Result := nil;
  2748. end;}
  2749. end;
  2750. procedure TCnDockPresident.DragDone(Drop: Boolean);
  2751. function CheckUndock: Boolean;
  2752. begin
  2753. Result := DragObject.DragTarget <> nil;
  2754. with DragControl do
  2755. if Drop and (ActiveDrag = dopDock) then
  2756. if Floating or (HostDockSite = nil) then
  2757. Result := True
  2758. else
  2759. Result := DoUnDock(DragObject, DragObject.DragTarget, DragControl);
  2760. end;
  2761. procedure DoFloatForm(Control: TControl);
  2762. var
  2763. WasVisible: Boolean;
  2764. begin
  2765. if (Control.FloatingDockSiteClass = Control.ClassType) then
  2766. begin
  2767. WasVisible := Control.Visible;
  2768. try
  2769. Control.Dock(nil, DragObject.DockRect);
  2770. if (Control.Left <> DragObject.DockRect.Left) or (Control.Top <> DragObject.DockRect.Top) then
  2771. begin
  2772. Control.Left := DragObject.DockRect.Left;
  2773. Control.Top := DragObject.DockRect.Top;
  2774. end;
  2775. finally
  2776. if WasVisible then Control.BringToFront;
  2777. end;
  2778. end;
  2779. end;
  2780. var
  2781. DragSave: TCnDragDockObject;
  2782. DockObject: TCnDragDockObject;
  2783. Accepted: Boolean;
  2784. TargetPos: TPoint;
  2785. ParentForm: TCustomForm;
  2786. begin
  2787. DockObject := nil;
  2788. DragSave := nil;
  2789. Accepted := False;
  2790. if (DragObject = nil) or DragObject.Cancelling then Exit; // recursion control
  2791. try
  2792. DragSave := DragObject;
  2793. try
  2794. DragObject.Cancelling := True;
  2795. DragObject.ReleaseCapture(DragCapture);
  2796. if ActiveDrag = dopDock then
  2797. begin
  2798. DockObject := DragObject;
  2799. DockObject.EraseDragDockImage;
  2800. DockObject.Floating := DockObject.DragTarget = nil;
  2801. end;
  2802. if (DragObject.DragTarget <> nil) and
  2803. (TObject(DragObject.DragTarget) is TControl) then
  2804. TargetPos := DragObject.DragTargetPos
  2805. else
  2806. TargetPos := DragObject.DragPos;
  2807. Accepted := CheckUndock and
  2808. {(((ActiveDrag = dopDock) and DockObject.Floating) or
  2809. ((ActiveDrag <> dopNone) and DoDockOver(dsDragLeave))) and}
  2810. Drop;
  2811. if ActiveDrag = dopDock then
  2812. begin
  2813. if Accepted and DockObject.Floating then
  2814. begin
  2815. ParentForm := GetParentForm(DockObject.Control);
  2816. if (ParentForm <> nil) and
  2817. (ParentForm.ActiveControl = DockObject.Control) then
  2818. ParentForm.ActiveControl := nil;
  2819. DoFloatForm(DragControl);
  2820. end;
  2821. end
  2822. else begin
  2823. if DragImageList <> nil then DragImageList.EndDrag
  2824. else Windows.SetCursor(DragSaveCursor);
  2825. end;
  2826. DragControl := nil;
  2827. if DragSave.DragTarget <> nil then
  2828. begin
  2829. if not Accepted then
  2830. begin
  2831. DragSave.DragPos := Point(0, 0);
  2832. TargetPos.X := 0;
  2833. TargetPos.Y := 0;
  2834. end else
  2835. // if Drop then
  2836. DoDockDrop(DragSave, DragSave.DragPos);
  2837. end;
  2838. DragObject := nil;
  2839. finally
  2840. QualifyingSites.Free;
  2841. QualifyingSites := nil;
  2842. DragSave.Cancelling := False;
  2843. DragSave.Finished(DragSave.DragTarget, TargetPos.X, TargetPos.Y, Accepted);
  2844. DragObject := nil;
  2845. end;
  2846. finally
  2847. DragControl := nil;
  2848. // if DragFreeObject then
  2849. DragSave.Free;
  2850. end;
  2851. end;
  2852. procedure TCnDockPresident.RegisterDockSite(Site: TWinControl;
  2853. DoRegister: Boolean);
  2854. var
  2855. Index: Integer;
  2856. begin
  2857. if (Site <> nil) then
  2858. begin
  2859. if DockSiteList = nil then DockSiteList := TList.Create;
  2860. Index := DockSiteList.IndexOf(Pointer(Site));
  2861. if DoRegister then
  2862. begin
  2863. if Index = -1 then DockSiteList.Add(Pointer(Site));
  2864. end
  2865. else begin
  2866. if Index <> -1 then DockSiteList.Delete(Index);
  2867. end;
  2868. end;
  2869. end;
  2870. procedure TCnDockPresident.DoGetSiteInfo(Target, Client: TControl;
  2871. var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);
  2872. var DockClient: TCnDockClient;
  2873. begin
  2874. if Target is TCnCustomDockControl then
  2875. TCnCustomDockControl(Target).CustomGetSiteInfo(DragObject, Client, InfluenceRect, MousePos, CanDock)
  2876. else if Target is TForm then
  2877. begin
  2878. DockClient := FindDockClient(Target);
  2879. if DockClient <> nil then
  2880. DockClient.FormGetSiteInfo(DragObject, Client, InfluenceRect, MousePos, CanDock);
  2881. end
  2882. else CanDock := False;
  2883. end;
  2884. procedure TCnDockPresident.DoDockDrop(Source: TCnDragDockObject; Pos: TPoint);
  2885. var Target: TWinControl;
  2886. DockClient: TCnDockClient;
  2887. begin
  2888. if Source.DragTarget <> nil then
  2889. begin
  2890. Target := Source.TargetControl;
  2891. with Target.ScreenToClient(Pos) do
  2892. if Target is TCnCustomDockControl then
  2893. TCnCustomDockControl(Target).CustomDockDrop(Source, X, Y)
  2894. else if Target is TForm then
  2895. begin
  2896. DockClient := FindDockClient(Target);
  2897. if DockClient <> nil then
  2898. DockClient.FormDockDrop(Source, X, Y);
  2899. end;
  2900. end;
  2901. end;
  2902. function TCnDockPresident.DoUnDock(Source: TCnDragDockObject; Target: TWinControl; Client: TControl): Boolean;
  2903. begin
  2904. if Client.HostDockSite is TCnCustomDockControl then
  2905. Result := TCnCustomDockControl(Client.HostDockSite).CustomUnDock(Source, Target, Client)
  2906. else Result := False;
  2907. end;
  2908. procedure TCnDockPresident.DoEndDrag(Target: TObject; X, Y: Integer);
  2909. var DockClient: TCnDockClient;
  2910. begin
  2911. if Target is TCnCustomDockControl then
  2912. TCnCustomDockControl(Target).CustomEndDock(Target, X, Y)
  2913. else if Target is TForm then
  2914. begin
  2915. DockClient := FindDockClient(TControl(Target));
  2916. if DockClient <> nil then
  2917. DockClient.FormEndDock(Target, X, Y);
  2918. end;
  2919. end;
  2920. procedure TCnDockPresident.CalcDockSizes(Control: TControl);
  2921. var //BorderWidth: Integer;
  2922. Rect: TRect;
  2923. begin
  2924. with Control do
  2925. if Floating then
  2926. begin
  2927. UndockHeight := Height;
  2928. UndockWidth := Width;
  2929. end
  2930. else if HostDockSite is TCnCustomDockPanel then
  2931. begin
  2932. //BorderWidth := TCnCustomDockPanel(HostDockSite).CnDockManager.BorderWidth;
  2933. Rect := TCnCustomDockPanel(HostDockSite).CnDockManager.GetFrameRect(Control);
  2934. if (HostDockSite.Align in [alTop, alBottom]) then
  2935. TBDockHeight := Rect.Bottom - Rect.Top//Height + 2*BorderWidth
  2936. else if (HostDockSite.Align in [alLeft, alRight]) then
  2937. LRDockWidth := Rect.Right - Rect.Left;//Width + 2*BorderWidth;
  2938. end;
  2939. end;
  2940. procedure TCnDockPresident.CancelDrag;
  2941. begin
  2942. if DragObject <> nil then DragDone(False);
  2943. DragControl := nil;
  2944. end;
  2945. procedure TCnDockPresident.DoGetDockEdge(Target: TControl; MousePos: TPoint; var DropAlign: TAlign);
  2946. var DockClient: TCnDockClient;
  2947. begin
  2948. if Target is TCnCustomDockControl then
  2949. TCnCustomDockControl(Target).CustomGetDockEdge(DragObject, MousePos, DropAlign)
  2950. else if Target is TForm then
  2951. begin
  2952. DockClient := FindDockClient(Target);
  2953. if DockClient <> nil then
  2954. DockClient.FormGetDockEdge(DragObject, MousePos, DropAlign);
  2955. end;
  2956. end;
  2957. procedure TCnDockPresident.ResetCursor;
  2958. begin
  2959. if (GlobalDockClient <> nil) and (GlobalDockClient.DockStyle <> nil) then
  2960. GlobalDockClient.DockStyle.ResetCursor(DragObject);
  2961. end;
  2962. { TSiteList }
  2963. procedure TSiteList.AddSite(ASite: TWinControl);
  2964. function GetTopParent: HWND;
  2965. var
  2966. NextParent: HWND;
  2967. begin
  2968. NextParent := ASite.Handle;
  2969. Result := NextParent;
  2970. while NextParent <> 0 do
  2971. begin
  2972. Result := NextParent;
  2973. NextParent := GetParent(NextParent);
  2974. end;
  2975. end;
  2976. var
  2977. SI: PSiteInfoRec;
  2978. Index: Integer;
  2979. begin
  2980. New(SI);
  2981. SI.Site := ASite;
  2982. SI.TopParent := GetTopParent;
  2983. if Find(SI.TopParent, Index) then
  2984. Insert(Index, SI) else
  2985. Add(SI);
  2986. end;
  2987. procedure TSiteList.Clear;
  2988. var
  2989. I: Integer;
  2990. begin
  2991. for I := 0 to Count - 1 do
  2992. Dispose(PSiteInfoRec(Items[I]));
  2993. inherited Clear;
  2994. end;
  2995. function TSiteList.Find(ParentWnd: Hwnd; var Index: Integer): Boolean;
  2996. begin
  2997. Index := 0;
  2998. Result := False;
  2999. while Index < Count do
  3000. begin
  3001. Result := (PSiteInfoRec(Items[Index]).TopParent = ParentWnd);
  3002. if Result then Exit;
  3003. Inc(Index);
  3004. end;
  3005. end;
  3006. function TSiteList.GetTopSite: TWinControl;
  3007. var
  3008. Index: Integer;
  3009. DesktopWnd, CurrentWnd: HWND;
  3010. begin
  3011. Result := nil;
  3012. if Count = 0 then Exit
  3013. else if Count = 1 then Result := PSiteInfoRec(Items[0]).Site
  3014. else begin
  3015. DesktopWnd := GetDesktopWindow;
  3016. CurrentWnd := GetTopWindow(DesktopWnd);
  3017. while (Result = nil) and (CurrentWnd <> 0) do
  3018. begin
  3019. if Find(CurrentWnd, Index) then
  3020. Result := PSiteInfoRec(List[Index])^.Site
  3021. else
  3022. CurrentWnd := GetNextWindow(CurrentWnd, GW_HWNDNEXT);
  3023. end;
  3024. end;
  3025. end;
  3026. { TCustomDockPanelSplitter }
  3027. constructor TCustomDockPanelSplitter.Create(AOwner: TComponent);
  3028. begin
  3029. inherited Create(AOwner);
  3030. FAutoSnap := True;
  3031. Align := alLeft;
  3032. Width := 3;
  3033. Cursor := crHSplit;
  3034. FMinSize := 30;
  3035. FResizeStyle := rsPattern;
  3036. FOldSize := -1;
  3037. end;
  3038. destructor TCustomDockPanelSplitter.Destroy;
  3039. begin
  3040. FBrush.Free;
  3041. inherited Destroy;
  3042. end;
  3043. procedure TCustomDockPanelSplitter.AllocateLineDC;
  3044. begin
  3045. FLineDC := GetDCEx(Parent.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS
  3046. or DCX_LOCKWINDOWUPDATE);
  3047. if ResizeStyle = rsPattern then
  3048. begin
  3049. if FBrush = nil then
  3050. begin
  3051. FBrush := TBrush.Create;
  3052. FBrush.Bitmap := AllocPatternBitmap(clBlack, clWhite);
  3053. end;
  3054. FPrevBrush := SelectObject(FLineDC, FBrush.Handle);
  3055. end;
  3056. end;
  3057. procedure TCustomDockPanelSplitter.DrawLine;
  3058. var
  3059. P: TPoint;
  3060. begin
  3061. FLineVisible := not FLineVisible;
  3062. P := Point(Left, Top);
  3063. if Align in [alLeft, alRight] then
  3064. P.X := Left + FSplit else
  3065. P.Y := Top + FSplit;
  3066. with P do PatBlt(FLineDC, X, Y, Width, Height, PATINVERT);
  3067. end;
  3068. procedure TCustomDockPanelSplitter.ReleaseLineDC;
  3069. begin
  3070. if FPrevBrush <> 0 then
  3071. SelectObject(FLineDC, FPrevBrush);
  3072. ReleaseDC(Parent.Handle, FLineDC);
  3073. if FBrush <> nil then
  3074. begin
  3075. FBrush.Free;
  3076. FBrush := nil;
  3077. end;
  3078. end;
  3079. function TCustomDockPanelSplitter.FindControl: TControl;
  3080. var
  3081. P: TPoint;
  3082. I: Integer;
  3083. R: TRect;
  3084. begin
  3085. Result := nil;
  3086. P := Point(Left, Top);
  3087. case Align of
  3088. alLeft: Dec(P.X);
  3089. alRight: Inc(P.X, Width);
  3090. alTop: Dec(P.Y);
  3091. alBottom: Inc(P.Y, Height);
  3092. else
  3093. Exit;
  3094. end;
  3095. for I := 0 to Parent.ControlCount - 1 do
  3096. begin
  3097. Result := Parent.Controls[I];
  3098. if Result.Visible and Result.Enabled then
  3099. begin
  3100. R := Result.BoundsRect;
  3101. if (R.Right - R.Left) = 0 then
  3102. if Align in [alTop, alLeft] then
  3103. Dec(R.Left)
  3104. else
  3105. Inc(R.Right);
  3106. if (R.Bottom - R.Top) = 0 then
  3107. if Align in [alTop, alLeft] then
  3108. Dec(R.Top)
  3109. else
  3110. Inc(R.Bottom);
  3111. if PtInRect(R, P) then Exit;
  3112. end;
  3113. end;
  3114. Result := nil;
  3115. end;
  3116. procedure TCustomDockPanelSplitter.RequestAlign;
  3117. begin
  3118. inherited RequestAlign;
  3119. if (Cursor <> crVSplit) and (Cursor <> crHSplit) then Exit;
  3120. if Align in [alBottom, alTop] then
  3121. Cursor := crVSplit
  3122. else
  3123. Cursor := crHSplit;
  3124. end;
  3125. procedure TCustomDockPanelSplitter.Paint;
  3126. const
  3127. XorColor = $00FFD8CE;
  3128. var
  3129. FrameBrush: HBRUSH;
  3130. R: TRect;
  3131. begin
  3132. R := ClientRect;
  3133. Canvas.Brush.Color := Color;
  3134. Canvas.FillRect(ClientRect);
  3135. if Beveled then
  3136. begin
  3137. if Align in [alLeft, alRight] then
  3138. InflateRect(R, -1, 2) else
  3139. InflateRect(R, 2, -1);
  3140. OffsetRect(R, 1, 1);
  3141. FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight));
  3142. FrameRect(Canvas.Handle, R, FrameBrush);
  3143. DeleteObject(FrameBrush);
  3144. OffsetRect(R, -2, -2);
  3145. FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow));
  3146. FrameRect(Canvas.Handle, R, FrameBrush);
  3147. DeleteObject(FrameBrush);
  3148. end;
  3149. if csDesigning in ComponentState then
  3150. { Draw outline }
  3151. with Canvas do
  3152. begin
  3153. Pen.Style := psDot;
  3154. Pen.Mode := pmXor;
  3155. Pen.Color := XorColor;
  3156. Brush.Style := bsClear;
  3157. Rectangle(0, 0, ClientWidth, ClientHeight);
  3158. end;
  3159. if Assigned(FOnPaint) then FOnPaint(Self);
  3160. end;
  3161. function TCustomDockPanelSplitter.DoCanResize(var NewSize: Integer): Boolean;
  3162. begin
  3163. Result := CanResize(NewSize);
  3164. if Result and (NewSize <= MinSize) and FAutoSnap then
  3165. NewSize := 0;
  3166. end;
  3167. function TCustomDockPanelSplitter.CanResize(var NewSize: Integer): Boolean;
  3168. begin
  3169. Result := True;
  3170. if Assigned(FOnCanResize) then FOnCanResize(Self, NewSize, Result);
  3171. end;
  3172. procedure TCustomDockPanelSplitter.MouseDown(Button: TMouseButton; Shift: TShiftState;
  3173. X, Y: Integer);
  3174. var
  3175. I: Integer;
  3176. begin
  3177. inherited MouseDown(Button, Shift, X, Y);
  3178. if Button = mbLeft then
  3179. begin
  3180. FControl := FindControl;
  3181. FDownPos := Point(X, Y);
  3182. if Assigned(FControl) then
  3183. begin
  3184. if Align in [alLeft, alRight] then
  3185. begin
  3186. FMaxSize := Parent.ClientWidth - FMinSize;
  3187. for I := 0 to Parent.ControlCount - 1 do
  3188. with Parent.Controls[I] do
  3189. if Visible and (Align in [alLeft, alRight]) then Dec(FMaxSize, Width);
  3190. Inc(FMaxSize, FControl.Width);
  3191. end
  3192. else
  3193. begin
  3194. FMaxSize := Parent.ClientHeight - FMinSize;
  3195. for I := 0 to Parent.ControlCount - 1 do
  3196. with Parent.Controls[I] do
  3197. if Align in [alTop, alBottom] then Dec(FMaxSize, Height);
  3198. Inc(FMaxSize, FControl.Height);
  3199. end;
  3200. UpdateSize(X, Y);
  3201. AllocateLineDC;
  3202. with ValidParentForm(Self) do
  3203. if ActiveControl <> nil then
  3204. begin
  3205. FActiveControl := ActiveControl;
  3206. FOldKeyDown := TCnWinControlAccess(FActiveControl).OnKeyDown;
  3207. TCnWinControlAccess(FActiveControl).OnKeyDown := FocusKeyDown;
  3208. end;
  3209. if ResizeStyle in [rsLine, rsPattern] then DrawLine;
  3210. end;
  3211. end;
  3212. end;
  3213. procedure TCustomDockPanelSplitter.UpdateControlSize;
  3214. begin
  3215. if FNewSize <> FOldSize then
  3216. begin
  3217. case Align of
  3218. alLeft: FControl.Width := FNewSize;
  3219. alTop: FControl.Height := FNewSize;
  3220. alRight:
  3221. begin
  3222. Parent.DisableAlign;
  3223. try
  3224. FControl.Left := FControl.Left + (FControl.Width - FNewSize);
  3225. FControl.Width := FNewSize;
  3226. finally
  3227. Parent.EnableAlign;
  3228. end;
  3229. end;
  3230. alBottom:
  3231. begin
  3232. Parent.DisableAlign;
  3233. try
  3234. FControl.Top := FControl.Top + (FControl.Height - FNewSize);
  3235. FControl.Height := FNewSize;
  3236. finally
  3237. Parent.EnableAlign;
  3238. end;
  3239. end;
  3240. end;
  3241. TCnControlAccess(FControl).Resize;
  3242. Update;
  3243. if Assigned(FOnMoved) then FOnMoved(Self);
  3244. FOldSize := FNewSize;
  3245. // Canvas.FillRect(GetClientRect);
  3246. end;
  3247. end;
  3248. procedure TCustomDockPanelSplitter.CalcSplitSize(X, Y: Integer; var NewSize, Split: Integer);
  3249. var
  3250. S: Integer;
  3251. begin
  3252. if Align in [alLeft, alRight] then
  3253. Split := X - FDownPos.X
  3254. else
  3255. Split := Y - FDownPos.Y;
  3256. S := 0;
  3257. case Align of
  3258. alLeft: S := FControl.Width + Split;
  3259. alRight: S := FControl.Width - Split;
  3260. alTop: S := FControl.Height + Split;
  3261. alBottom: S := FControl.Height - Split;
  3262. end;
  3263. NewSize := S;
  3264. if S < FMinSize then
  3265. NewSize := FMinSize
  3266. else if S > FMaxSize then
  3267. NewSize := FMaxSize;
  3268. if S <> NewSize then
  3269. begin
  3270. if Align in [alRight, alBottom] then
  3271. S := S - NewSize else
  3272. S := NewSize - S;
  3273. Inc(Split, S);
  3274. end;
  3275. end;
  3276. procedure TCustomDockPanelSplitter.UpdateSize(X, Y: Integer);
  3277. begin
  3278. CalcSplitSize(X, Y, FNewSize, FSplit);
  3279. end;
  3280. procedure TCustomDockPanelSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
  3281. var
  3282. NewSize, Split: Integer;
  3283. begin
  3284. inherited;
  3285. if (ssLeft in Shift) and Assigned(FControl) then
  3286. begin
  3287. CalcSplitSize(X, Y, NewSize, Split);
  3288. if (DoCanResize(NewSize) and (FNewSize <> NewSize)) then
  3289. begin
  3290. if ResizeStyle in [rsLine, rsPattern] then DrawLine;
  3291. FNewSize := NewSize;
  3292. FSplit := Split;
  3293. if ResizeStyle = rsUpdate then UpdateControlSize;
  3294. if ResizeStyle in [rsLine, rsPattern] then DrawLine;
  3295. end;
  3296. end;
  3297. end;
  3298. procedure TCustomDockPanelSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState;
  3299. X, Y: Integer);
  3300. begin
  3301. inherited;
  3302. if Assigned(FControl) then
  3303. begin
  3304. if ResizeStyle in [rsLine, rsPattern] then DrawLine;
  3305. UpdateControlSize;
  3306. StopSizing;
  3307. end;
  3308. end;
  3309. procedure TCustomDockPanelSplitter.FocusKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  3310. begin
  3311. if Key = VK_ESCAPE then
  3312. StopSizing
  3313. else if Assigned(FOldKeyDown) then
  3314. FOldKeyDown(Sender, Key, Shift);
  3315. end;
  3316. procedure TCustomDockPanelSplitter.SetBeveled(Value: Boolean);
  3317. begin
  3318. FBeveled := Value;
  3319. Repaint;
  3320. end;
  3321. procedure TCustomDockPanelSplitter.StopSizing;
  3322. begin
  3323. if Assigned(FControl) then
  3324. begin
  3325. if FLineVisible then DrawLine;
  3326. FControl := nil;
  3327. ReleaseLineDC;
  3328. if Assigned(FActiveControl) then
  3329. begin
  3330. TCnWinControlAccess(FActiveControl).OnKeyDown := FOldKeyDown;
  3331. FActiveControl := nil;
  3332. end;
  3333. end;
  3334. if Assigned(FOnMoved) then
  3335. FOnMoved(Self);
  3336. end;
  3337. end.