FloatWindow.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*******************************************************************************
  2. * Copyright(c) 2014 DongkeSoft All rights reserved. / Confidential
  3. * 类的信息:
  4. * 1.程序名称:FloatWindow.cs
  5. * 2.功能描述:类文件
  6. * 编辑履历:
  7. * 作者 日期 版本 修改内容
  8. * 陈晓野 2014/09/01 1.00 新建
  9. *******************************************************************************/
  10. using System;
  11. using System.Diagnostics.CodeAnalysis;
  12. using System.Drawing;
  13. using System.Security.Permissions;
  14. using System.Windows.Forms;
  15. namespace Dongke.IBOSS.PRD.Basics.DockPanel
  16. {
  17. public class FloatWindow : Form, INestedPanesContainer, IDockDragSource
  18. {
  19. private NestedPaneCollection m_nestedPanes;
  20. internal const int WM_CHECKDISPOSE = (int)(Win32.Msgs.WM_USER + 1);
  21. internal protected FloatWindow(DockPanel dockPanel, DockPane pane)
  22. {
  23. InternalConstruct(dockPanel, pane, false, Rectangle.Empty);
  24. }
  25. internal protected FloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
  26. {
  27. InternalConstruct(dockPanel, pane, true, bounds);
  28. }
  29. private void InternalConstruct(DockPanel dockPanel, DockPane pane, bool boundsSpecified, Rectangle bounds)
  30. {
  31. if (dockPanel == null)
  32. throw (new ArgumentNullException(Strings.FloatWindow_Constructor_NullDockPanel));
  33. m_nestedPanes = new NestedPaneCollection(this);
  34. FormBorderStyle = FormBorderStyle.SizableToolWindow;
  35. ShowInTaskbar = false;
  36. if (dockPanel.RightToLeft != RightToLeft)
  37. RightToLeft = dockPanel.RightToLeft;
  38. if (RightToLeftLayout != dockPanel.RightToLeftLayout)
  39. RightToLeftLayout = dockPanel.RightToLeftLayout;
  40. SuspendLayout();
  41. if (boundsSpecified)
  42. {
  43. Bounds = bounds;
  44. StartPosition = FormStartPosition.Manual;
  45. }
  46. else
  47. {
  48. StartPosition = FormStartPosition.WindowsDefaultLocation;
  49. Size = dockPanel.DefaultFloatWindowSize;
  50. }
  51. m_dockPanel = dockPanel;
  52. Owner = DockPanel.FindForm();
  53. DockPanel.AddFloatWindow(this);
  54. if (pane != null)
  55. pane.FloatWindow = this;
  56. ResumeLayout();
  57. }
  58. protected override void Dispose(bool disposing)
  59. {
  60. if (disposing)
  61. {
  62. if (DockPanel != null)
  63. DockPanel.RemoveFloatWindow(this);
  64. m_dockPanel = null;
  65. }
  66. base.Dispose(disposing);
  67. }
  68. private bool m_allowEndUserDocking = true;
  69. public bool AllowEndUserDocking
  70. {
  71. get
  72. {
  73. return m_allowEndUserDocking;
  74. }
  75. set
  76. {
  77. m_allowEndUserDocking = value;
  78. }
  79. }
  80. public NestedPaneCollection NestedPanes
  81. {
  82. get
  83. {
  84. return m_nestedPanes;
  85. }
  86. }
  87. public VisibleNestedPaneCollection VisibleNestedPanes
  88. {
  89. get
  90. {
  91. return NestedPanes.VisibleNestedPanes;
  92. }
  93. }
  94. private DockPanel m_dockPanel;
  95. public DockPanel DockPanel
  96. {
  97. get
  98. {
  99. return m_dockPanel;
  100. }
  101. }
  102. public DockState DockState
  103. {
  104. get
  105. {
  106. return DockState.Float;
  107. }
  108. }
  109. public bool IsFloat
  110. {
  111. get
  112. {
  113. return DockState == DockState.Float;
  114. }
  115. }
  116. internal bool IsDockStateValid(DockState dockState)
  117. {
  118. foreach (DockPane pane in NestedPanes)
  119. foreach (IDockContent content in pane.Contents)
  120. if (!DockHelper.IsDockStateValid(dockState, content.DockHandler.DockAreas))
  121. return false;
  122. return true;
  123. }
  124. protected override void OnActivated(EventArgs e)
  125. {
  126. DockPanel.FloatWindows.BringWindowToFront(this);
  127. base.OnActivated(e);
  128. // Propagate the Activated event to the visible panes content objects
  129. foreach (DockPane pane in VisibleNestedPanes)
  130. foreach (IDockContent content in pane.Contents)
  131. content.OnActivated(e);
  132. }
  133. protected override void OnDeactivate(EventArgs e)
  134. {
  135. base.OnDeactivate(e);
  136. // Propagate the Deactivate event to the visible panes content objects
  137. foreach (DockPane pane in VisibleNestedPanes)
  138. foreach (IDockContent content in pane.Contents)
  139. content.OnDeactivate(e);
  140. }
  141. protected override void OnLayout(LayoutEventArgs levent)
  142. {
  143. VisibleNestedPanes.Refresh();
  144. RefreshChanges();
  145. Visible = (VisibleNestedPanes.Count > 0);
  146. SetText();
  147. base.OnLayout(levent);
  148. }
  149. [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.Windows.Forms.Control.set_Text(System.String)")]
  150. internal void SetText()
  151. {
  152. DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null;
  153. if (theOnlyPane == null || theOnlyPane.ActiveContent == null)
  154. {
  155. Text = " "; // use " " instead of string.Empty because the whole title bar will disappear when ControlBox is set to false.
  156. Icon = null;
  157. }
  158. else
  159. {
  160. Text = theOnlyPane.ActiveContent.DockHandler.TabText;
  161. Icon = theOnlyPane.ActiveContent.DockHandler.Icon;
  162. }
  163. }
  164. protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
  165. {
  166. Rectangle rectWorkArea = SystemInformation.VirtualScreen;
  167. if (y + height > rectWorkArea.Bottom)
  168. y -= (y + height) - rectWorkArea.Bottom;
  169. if (y < rectWorkArea.Top)
  170. y += rectWorkArea.Top - y;
  171. base.SetBoundsCore(x, y, width, height, specified);
  172. }
  173. [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  174. protected override void WndProc(ref Message m)
  175. {
  176. if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDOWN)
  177. {
  178. if (IsDisposed)
  179. return;
  180. uint result = Win32Helper.IsRunningOnMono ? 0 : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
  181. if (result == 2 && DockPanel.AllowEndUserDocking && this.AllowEndUserDocking) // HITTEST_CAPTION
  182. {
  183. Activate();
  184. m_dockPanel.BeginDrag(this);
  185. }
  186. else
  187. base.WndProc(ref m);
  188. return;
  189. }
  190. else if (m.Msg == (int)Win32.Msgs.WM_NCRBUTTONDOWN)
  191. {
  192. uint result = Win32Helper.IsRunningOnMono ? 0 : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
  193. if (result == 2) // HITTEST_CAPTION
  194. {
  195. DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null;
  196. if (theOnlyPane != null && theOnlyPane.ActiveContent != null)
  197. {
  198. theOnlyPane.ShowTabPageContextMenu(this, PointToClient(Control.MousePosition));
  199. return;
  200. }
  201. }
  202. base.WndProc(ref m);
  203. return;
  204. }
  205. else if (m.Msg == (int)Win32.Msgs.WM_CLOSE)
  206. {
  207. if (NestedPanes.Count == 0)
  208. {
  209. base.WndProc(ref m);
  210. return;
  211. }
  212. for (int i = NestedPanes.Count - 1; i >= 0; i--)
  213. {
  214. DockContentCollection contents = NestedPanes[i].Contents;
  215. for (int j = contents.Count - 1; j >= 0; j--)
  216. {
  217. IDockContent content = contents[j];
  218. if (content.DockHandler.DockState != DockState.Float)
  219. continue;
  220. if (!content.DockHandler.CloseButton)
  221. continue;
  222. if (content.DockHandler.HideOnClose)
  223. content.DockHandler.Hide();
  224. else
  225. content.DockHandler.Close();
  226. }
  227. }
  228. return;
  229. }
  230. else if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDBLCLK)
  231. {
  232. uint result = Win32Helper.IsRunningOnMono ? 0 : NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
  233. if (result != 2) // HITTEST_CAPTION
  234. {
  235. base.WndProc(ref m);
  236. return;
  237. }
  238. DockPanel.SuspendLayout(true);
  239. // Restore to panel
  240. foreach (DockPane pane in NestedPanes)
  241. {
  242. if (pane.DockState != DockState.Float)
  243. continue;
  244. pane.RestoreToPanel();
  245. }
  246. DockPanel.ResumeLayout(true, true);
  247. return;
  248. }
  249. else if (m.Msg == WM_CHECKDISPOSE)
  250. {
  251. if (NestedPanes.Count == 0)
  252. Dispose();
  253. return;
  254. }
  255. base.WndProc(ref m);
  256. }
  257. internal void RefreshChanges()
  258. {
  259. if (IsDisposed)
  260. return;
  261. if (VisibleNestedPanes.Count == 0)
  262. {
  263. ControlBox = true;
  264. return;
  265. }
  266. for (int i = VisibleNestedPanes.Count - 1; i >= 0; i--)
  267. {
  268. DockContentCollection contents = VisibleNestedPanes[i].Contents;
  269. for (int j = contents.Count - 1; j >= 0; j--)
  270. {
  271. IDockContent content = contents[j];
  272. if (content.DockHandler.DockState != DockState.Float)
  273. continue;
  274. if (content.DockHandler.CloseButton && content.DockHandler.CloseButtonVisible)
  275. {
  276. ControlBox = true;
  277. return;
  278. }
  279. }
  280. }
  281. //Only if there is a ControlBox do we turn it off
  282. //old code caused a flash of the window.
  283. if (ControlBox)
  284. ControlBox = false;
  285. }
  286. public virtual Rectangle DisplayingRectangle
  287. {
  288. get
  289. {
  290. return ClientRectangle;
  291. }
  292. }
  293. internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline)
  294. {
  295. if (VisibleNestedPanes.Count == 1)
  296. {
  297. DockPane pane = VisibleNestedPanes[0];
  298. if (!dragSource.CanDockTo(pane))
  299. return;
  300. Point ptMouse = Control.MousePosition;
  301. uint lParam = Win32Helper.MakeLong(ptMouse.X, ptMouse.Y);
  302. if (!Win32Helper.IsRunningOnMono)
  303. if (NativeMethods.SendMessage(Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, lParam) == (uint)Win32.HitTest.HTCAPTION)
  304. dockOutline.Show(VisibleNestedPanes[0], -1);
  305. }
  306. }
  307. #region IDockDragSource Members
  308. #region IDragSource Members
  309. Control IDragSource.DragControl
  310. {
  311. get
  312. {
  313. return this;
  314. }
  315. }
  316. #endregion
  317. bool IDockDragSource.IsDockStateValid(DockState dockState)
  318. {
  319. return IsDockStateValid(dockState);
  320. }
  321. bool IDockDragSource.CanDockTo(DockPane pane)
  322. {
  323. if (!IsDockStateValid(pane.DockState))
  324. return false;
  325. if (pane.FloatWindow == this)
  326. return false;
  327. return true;
  328. }
  329. private int m_preDragExStyle;
  330. Rectangle IDockDragSource.BeginDrag(Point ptMouse)
  331. {
  332. m_preDragExStyle = NativeMethods.GetWindowLong(this.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE);
  333. NativeMethods.SetWindowLong(this.Handle,
  334. (int)Win32.GetWindowLongIndex.GWL_EXSTYLE,
  335. m_preDragExStyle | (int)(Win32.WindowExStyles.WS_EX_TRANSPARENT | Win32.WindowExStyles.WS_EX_LAYERED));
  336. return Bounds;
  337. }
  338. void IDockDragSource.EndDrag()
  339. {
  340. NativeMethods.SetWindowLong(this.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, m_preDragExStyle);
  341. Invalidate(true);
  342. NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCPAINT, 1, 0);
  343. }
  344. public void FloatAt(Rectangle floatWindowBounds)
  345. {
  346. Bounds = floatWindowBounds;
  347. }
  348. public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex)
  349. {
  350. if (dockStyle == DockStyle.Fill)
  351. {
  352. for (int i = NestedPanes.Count - 1; i >= 0; i--)
  353. {
  354. DockPane paneFrom = NestedPanes[i];
  355. for (int j = paneFrom.Contents.Count - 1; j >= 0; j--)
  356. {
  357. IDockContent c = paneFrom.Contents[j];
  358. c.DockHandler.Pane = pane;
  359. if (contentIndex != -1)
  360. pane.SetContentIndex(c, contentIndex);
  361. c.DockHandler.Activate();
  362. }
  363. }
  364. }
  365. else
  366. {
  367. DockAlignment alignment = DockAlignment.Left;
  368. if (dockStyle == DockStyle.Left)
  369. alignment = DockAlignment.Left;
  370. else if (dockStyle == DockStyle.Right)
  371. alignment = DockAlignment.Right;
  372. else if (dockStyle == DockStyle.Top)
  373. alignment = DockAlignment.Top;
  374. else if (dockStyle == DockStyle.Bottom)
  375. alignment = DockAlignment.Bottom;
  376. MergeNestedPanes(VisibleNestedPanes, pane.NestedPanesContainer.NestedPanes, pane, alignment, 0.5);
  377. }
  378. }
  379. public void DockTo(DockPanel panel, DockStyle dockStyle)
  380. {
  381. if (panel != DockPanel)
  382. throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel");
  383. NestedPaneCollection nestedPanesTo = null;
  384. if (dockStyle == DockStyle.Top)
  385. nestedPanesTo = DockPanel.DockWindows[DockState.DockTop].NestedPanes;
  386. else if (dockStyle == DockStyle.Bottom)
  387. nestedPanesTo = DockPanel.DockWindows[DockState.DockBottom].NestedPanes;
  388. else if (dockStyle == DockStyle.Left)
  389. nestedPanesTo = DockPanel.DockWindows[DockState.DockLeft].NestedPanes;
  390. else if (dockStyle == DockStyle.Right)
  391. nestedPanesTo = DockPanel.DockWindows[DockState.DockRight].NestedPanes;
  392. else if (dockStyle == DockStyle.Fill)
  393. nestedPanesTo = DockPanel.DockWindows[DockState.Document].NestedPanes;
  394. DockPane prevPane = null;
  395. for (int i = nestedPanesTo.Count - 1; i >= 0; i--)
  396. if (nestedPanesTo[i] != VisibleNestedPanes[0])
  397. prevPane = nestedPanesTo[i];
  398. MergeNestedPanes(VisibleNestedPanes, nestedPanesTo, prevPane, DockAlignment.Left, 0.5);
  399. }
  400. private static void MergeNestedPanes(VisibleNestedPaneCollection nestedPanesFrom, NestedPaneCollection nestedPanesTo, DockPane prevPane, DockAlignment alignment, double proportion)
  401. {
  402. if (nestedPanesFrom.Count == 0)
  403. return;
  404. int count = nestedPanesFrom.Count;
  405. DockPane[] panes = new DockPane[count];
  406. DockPane[] prevPanes = new DockPane[count];
  407. DockAlignment[] alignments = new DockAlignment[count];
  408. double[] proportions = new double[count];
  409. for (int i = 0; i < count; i++)
  410. {
  411. panes[i] = nestedPanesFrom[i];
  412. prevPanes[i] = nestedPanesFrom[i].NestedDockingStatus.PreviousPane;
  413. alignments[i] = nestedPanesFrom[i].NestedDockingStatus.Alignment;
  414. proportions[i] = nestedPanesFrom[i].NestedDockingStatus.Proportion;
  415. }
  416. DockPane pane = panes[0].DockTo(nestedPanesTo.Container, prevPane, alignment, proportion);
  417. panes[0].DockState = nestedPanesTo.DockState;
  418. for (int i = 1; i < count; i++)
  419. {
  420. for (int j = i; j < count; j++)
  421. {
  422. if (prevPanes[j] == panes[i - 1])
  423. prevPanes[j] = pane;
  424. }
  425. pane = panes[i].DockTo(nestedPanesTo.Container, prevPanes[i], alignments[i], proportions[i]);
  426. panes[i].DockState = nestedPanesTo.DockState;
  427. }
  428. }
  429. #endregion
  430. }
  431. }