MdiClient.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
  21. //
  22. // Authors:
  23. // Peter Bartok [email protected]
  24. //
  25. //
  26. // NOT COMPLETE
  27. using System.Collections;
  28. using System.ComponentModel;
  29. using System.Drawing;
  30. namespace System.Windows.Forms {
  31. [DesignTimeVisible(false)]
  32. [ToolboxItem(false)]
  33. public sealed class MdiClient : Control {
  34. #region Local Variables
  35. private int mdi_created;
  36. private HScrollBar hbar;
  37. private VScrollBar vbar;
  38. private SizeGrip sizegrip;
  39. private int hbar_value;
  40. private int vbar_value;
  41. private bool lock_sizing;
  42. private int prev_bottom;
  43. private LayoutEventHandler initial_layout_handler;
  44. private bool setting_windowstates = false;
  45. internal ArrayList mdi_child_list;
  46. private string form_text;
  47. private bool setting_form_text;
  48. #endregion // Local Variables
  49. #region Public Classes
  50. public new class ControlCollection : Control.ControlCollection {
  51. private MdiClient owner;
  52. public ControlCollection(MdiClient owner) : base(owner) {
  53. this.owner = owner;
  54. owner.mdi_child_list = new ArrayList ();
  55. }
  56. public override void Add(Control value) {
  57. if ((value is Form) == false || !(((Form)value).IsMdiChild)) {
  58. throw new ArgumentException("Form must be MdiChild");
  59. }
  60. owner.mdi_child_list.Add (value);
  61. base.Add (value);
  62. // newest member is the active one
  63. Form form = (Form) value;
  64. owner.ActiveMdiChild = form;
  65. }
  66. public override void Remove(Control value)
  67. {
  68. Form form = value as Form;
  69. if (form != null) {
  70. MdiWindowManager wm = form.WindowManager as MdiWindowManager;
  71. if (wm != null) {
  72. form.Closed -= wm.form_closed_handler;
  73. }
  74. }
  75. owner.mdi_child_list.Remove (value);
  76. base.Remove (value);
  77. }
  78. }
  79. #endregion // Public Classes
  80. #region Public Constructors
  81. public MdiClient()
  82. {
  83. BackColor = SystemColors.AppWorkspace;
  84. Dock = DockStyle.Fill;
  85. SetStyle (ControlStyles.Selectable, false);
  86. }
  87. #endregion // Public Constructors
  88. internal void SetParentText(bool text_changed)
  89. {
  90. if (setting_form_text)
  91. return;
  92. setting_form_text = true;
  93. if (text_changed)
  94. form_text = ParentForm.Text;
  95. if (ParentForm.ActiveMaximizedMdiChild == null)
  96. {
  97. ParentForm.Text = form_text;
  98. }
  99. else
  100. {
  101. string childText = ParentForm.ActiveMaximizedMdiChild.form.Text;
  102. if (childText.Length > 0) {
  103. ParentForm.Text = form_text + " - [" + ParentForm.ActiveMaximizedMdiChild.form.Text + "]";
  104. } else {
  105. ParentForm.Text = form_text;
  106. }
  107. }
  108. setting_form_text = false;
  109. }
  110. internal override void OnPaintBackgroundInternal (PaintEventArgs pe)
  111. {
  112. if (BackgroundImage != null)
  113. return;
  114. if (Parent == null || Parent.BackgroundImage == null)
  115. return;
  116. Parent.PaintControlBackground (pe);
  117. }
  118. internal Form ParentForm {
  119. get { return (Form) Parent; }
  120. }
  121. protected override Control.ControlCollection CreateControlsInstance ()
  122. {
  123. return new MdiClient.ControlCollection (this);
  124. }
  125. protected override void WndProc(ref Message m) {
  126. /*
  127. switch ((Msg) m.Msg) {
  128. case Msg.WM_PAINT: {
  129. Console.WriteLine ("ignoring paint");
  130. return;
  131. }
  132. }
  133. */
  134. base.WndProc (ref m);
  135. }
  136. protected override void OnResize (EventArgs e)
  137. {
  138. base.OnResize (e);
  139. // Should probably make this into one loop
  140. SizeScrollBars ();
  141. ArrangeWindows ();
  142. }
  143. protected override void ScaleCore (float dx, float dy)
  144. {
  145. base.ScaleCore (dx, dy);
  146. }
  147. protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
  148. {
  149. base.SetBoundsCore (x, y, width, height, specified);
  150. }
  151. #region Public Instance Properties
  152. [Localizable(true)]
  153. public override System.Drawing.Image BackgroundImage {
  154. get {
  155. return base.BackgroundImage;
  156. }
  157. set {
  158. base.BackgroundImage = value;
  159. }
  160. }
  161. public Form [] MdiChildren {
  162. get {
  163. if (mdi_child_list == null)
  164. return new Form [0];
  165. return (Form []) mdi_child_list.ToArray (typeof (Form));
  166. }
  167. }
  168. #endregion // Public Instance Properties
  169. #region Protected Instance Properties
  170. protected override CreateParams CreateParams {
  171. get {
  172. return base.CreateParams;
  173. }
  174. }
  175. #endregion // Protected Instance Properties
  176. #region Public Instance Methods
  177. public void LayoutMdi (MdiLayout value) {
  178. int max_width = Int32.MaxValue;
  179. int max_height = Int32.MaxValue;
  180. if (Parent != null) {
  181. max_width = Parent.Width;
  182. max_height = Parent.Height;
  183. }
  184. switch (value) {
  185. case MdiLayout.Cascade:
  186. int i = 0;
  187. for (int c = Controls.Count - 1; c >= 0; c--) {
  188. Form form = (Form) Controls [c];
  189. int l = 22 * i;
  190. int t = 22 * i;
  191. if (i != 0 && (l + form.Width > max_width || t + form.Height > max_height)) {
  192. i = 0;
  193. l = 22 * i;
  194. t = 22 * i;
  195. }
  196. form.Left = l;
  197. form.Top = t;
  198. i++;
  199. }
  200. break;
  201. default:
  202. throw new NotImplementedException();
  203. }
  204. }
  205. #endregion // Public Instance Methods
  206. #region Protected Instance Methods
  207. #endregion // Protected Instance Methods
  208. internal void SizeScrollBars ()
  209. {
  210. if (lock_sizing)
  211. return;
  212. if (Controls.Count == 0 || ((Form) Controls [0]).WindowState == FormWindowState.Maximized) {
  213. if (hbar != null)
  214. hbar.Visible = false;
  215. if (vbar != null)
  216. vbar.Visible = false;
  217. return;
  218. }
  219. bool hbar_required = false;
  220. bool vbar_required = false;
  221. int right = 0;
  222. int left = 0;
  223. int top = 0;
  224. int bottom = 0;
  225. foreach (Form child in Controls) {
  226. if (!child.Visible)
  227. continue;
  228. if (child.Right > right)
  229. right = child.Right;
  230. if (child.Left < left) {
  231. hbar_required = true;
  232. left = child.Left;
  233. }
  234. if (child.Bottom > bottom)
  235. bottom = child.Bottom;
  236. if (child.Top < 0) {
  237. vbar_required = true;
  238. top = child.Top;
  239. }
  240. }
  241. int first_right = Width;
  242. int first_bottom = Height;
  243. int right_edge = first_right;
  244. int bottom_edge = first_bottom;
  245. int prev_right_edge;
  246. int prev_bottom_edge;
  247. bool need_hbar = false;
  248. bool need_vbar = false;
  249. do {
  250. prev_right_edge = right_edge;
  251. prev_bottom_edge = bottom_edge;
  252. if (hbar_required || right > right_edge) {
  253. need_hbar = true;
  254. bottom_edge = first_bottom - SystemInformation.HorizontalScrollBarHeight;
  255. } else {
  256. need_hbar = false;
  257. bottom_edge = first_bottom;
  258. }
  259. if (vbar_required || bottom > bottom_edge) {
  260. need_vbar = true;
  261. right_edge = first_right - SystemInformation.VerticalScrollBarWidth;
  262. } else {
  263. need_vbar = false;
  264. right_edge = first_right;
  265. }
  266. } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge);
  267. if (need_hbar) {
  268. if (hbar == null) {
  269. hbar = new HScrollBar ();
  270. Controls.AddImplicit (hbar);
  271. }
  272. hbar.Visible = true;
  273. CalcHBar (left, right, right_edge, need_vbar);
  274. } else if (hbar != null)
  275. hbar.Visible = false;
  276. if (need_vbar) {
  277. if (vbar == null) {
  278. vbar = new VScrollBar ();
  279. Controls.AddImplicit (vbar);
  280. }
  281. vbar.Visible = true;
  282. CalcVBar (top, bottom, bottom_edge, need_hbar);
  283. } else if (vbar != null)
  284. vbar.Visible = false;
  285. if (need_hbar && need_vbar) {
  286. if (sizegrip == null) {
  287. sizegrip = new SizeGrip ();
  288. Controls.AddImplicit (sizegrip);
  289. }
  290. sizegrip.Location = new Point (hbar.Right, vbar.Bottom);
  291. sizegrip.Width = vbar.Width;
  292. sizegrip.Height = hbar.Height;
  293. sizegrip.Visible = true;
  294. } else if (sizegrip != null) {
  295. sizegrip.Visible = false;
  296. }
  297. }
  298. private void CalcHBar (int left, int right, int right_edge, bool vert_vis)
  299. {
  300. int virtual_left = Math.Min (left, 0);
  301. int virtual_right = Math.Max (right, right_edge);
  302. int diff = (virtual_right - virtual_left) - right_edge;
  303. hbar.Left = 0;
  304. hbar.Top = Height - hbar.Height;
  305. hbar.Width = Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
  306. hbar.LargeChange = 50;
  307. hbar.Maximum = diff + 51;
  308. hbar.Value = -virtual_left;
  309. hbar.ValueChanged += new EventHandler (HBarValueChanged);
  310. }
  311. private void CalcVBar (int top, int bottom, int bottom_edge, bool horz_vis)
  312. {
  313. int virtual_top = Math.Min (top, 0);
  314. int virtual_bottom = Math.Max (bottom, bottom_edge);
  315. int diff = (virtual_bottom - virtual_top) - bottom_edge;
  316. vbar.Top = 0;
  317. vbar.Left = Width - vbar.Width;
  318. vbar.Height = Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
  319. vbar.LargeChange = 50;
  320. vbar.Maximum = diff + 51;
  321. vbar.Value = -virtual_top;
  322. vbar.ValueChanged += new EventHandler (VBarValueChanged);
  323. }
  324. private void HBarValueChanged (object sender, EventArgs e)
  325. {
  326. if (hbar.Value == hbar_value)
  327. return;
  328. lock_sizing = true;
  329. try {
  330. foreach (Form child in Controls) {
  331. child.Left += hbar_value - hbar.Value;
  332. }
  333. } finally {
  334. lock_sizing = false;
  335. }
  336. hbar_value = hbar.Value;
  337. lock_sizing = false;
  338. }
  339. private void VBarValueChanged (object sender, EventArgs e)
  340. {
  341. if (vbar.Value == vbar_value)
  342. return;
  343. lock_sizing = true;
  344. try {
  345. foreach (Form child in Controls) {
  346. child.Top += vbar_value - vbar.Value;
  347. }
  348. } finally {
  349. lock_sizing = false;
  350. }
  351. vbar_value = vbar.Value;
  352. lock_sizing = false;
  353. }
  354. private void ArrangeWindows ()
  355. {
  356. int change = 0;
  357. if (prev_bottom != -1)
  358. change = Bottom - prev_bottom;
  359. foreach (Control c in Controls) {
  360. Form child = c as Form;
  361. if (c == null || !child.Visible)
  362. continue;
  363. MdiWindowManager wm = child.WindowManager as MdiWindowManager;
  364. if (wm.GetWindowState () == FormWindowState.Maximized)
  365. wm.SizeMaximized ();
  366. if (wm.GetWindowState () == FormWindowState.Minimized) {
  367. child.Top += change;
  368. }
  369. }
  370. prev_bottom = Bottom;
  371. }
  372. private void FormLocationChanged (object sender, EventArgs e)
  373. {
  374. SizeScrollBars ();
  375. }
  376. private int iconic_x = -1;
  377. private int iconic_y = -1;
  378. internal void ArrangeIconicWindows ()
  379. {
  380. int xspacing = 160;
  381. int yspacing = 25;
  382. if (iconic_x == -1 && iconic_y == -1) {
  383. iconic_x = Left;
  384. iconic_y = Bottom - yspacing;
  385. }
  386. lock_sizing = true;
  387. foreach (Form form in Controls) {
  388. if (form.WindowState != FormWindowState.Minimized)
  389. continue;
  390. MdiWindowManager wm = (MdiWindowManager) form.WindowManager;
  391. // Need to get the width in the loop cause some themes might have
  392. // different widths for different styles
  393. int bw = ThemeEngine.Current.ManagedWindowBorderWidth (wm);
  394. if (wm.IconicBounds != Rectangle.Empty) {
  395. form.Bounds = wm.IconicBounds;
  396. continue;
  397. }
  398. // The extra one pixel is a cheap hack for now until we
  399. // handle 0 client sizes properly in the driver
  400. int height = wm.TitleBarHeight + (bw * 2) + 1;
  401. // The extra one pixel here is to avoid scrollbars
  402. Rectangle rect = new Rectangle (iconic_x, iconic_y - 1, xspacing, height);
  403. form.Bounds = wm.IconicBounds = rect;
  404. iconic_x += xspacing;
  405. if (iconic_x >= Right) {
  406. iconic_x = Left;
  407. iconic_y -= height;
  408. }
  409. }
  410. lock_sizing = false;
  411. }
  412. internal void CloseChildForm (Form form)
  413. {
  414. if (Controls.Count > 1) {
  415. Form next = (Form) Controls [1];
  416. if (form.WindowState == FormWindowState.Maximized)
  417. next.WindowState = FormWindowState.Maximized;
  418. ActivateChild (next);
  419. }
  420. Controls.Remove (form);
  421. form.Close ();
  422. }
  423. internal void ActivateNextChild ()
  424. {
  425. if (Controls.Count < 1)
  426. return;
  427. Form front = (Form) Controls [0];
  428. Form form = (Form) Controls [1];
  429. front.SendToBack ();
  430. ActivateChild (form);
  431. }
  432. internal void ActivateChild (Form form)
  433. {
  434. if (Controls.Count < 1)
  435. return;
  436. Form current = (Form) Controls [0];
  437. form.BringToFront ();
  438. if (current != form) {
  439. Message m = new Message ();
  440. m.Msg = (int) Msg.WM_NCPAINT;
  441. m.HWnd = current.Handle;
  442. m.LParam = IntPtr.Zero;
  443. m.WParam = new IntPtr (1);
  444. XplatUI.SendMessage (ref m);
  445. m.HWnd = form.Handle;
  446. XplatUI.SendMessage (ref m);
  447. this.SetWindowStates ((MdiWindowManager) form.window_manager, form.WindowState);
  448. }
  449. }
  450. internal bool SetWindowStates (MdiWindowManager wm, FormWindowState window_state)
  451. {
  452. /*
  453. MDI WindowState behaviour:
  454. - If the active window is maximized, all other maximized windows are normalized.
  455. - If a normal window gets focus and the original active window was maximized,
  456. the normal window gets maximized and the original window gets normalized.
  457. - If a minimized window gets focus and the original window was maximized,
  458. the minimzed window gets maximized and the original window gets normalized.
  459. If the ex-minimized window gets deactivated, it will be normalized.
  460. */
  461. Form form = wm.form;
  462. if (setting_windowstates) {
  463. return false;
  464. }
  465. if (!form.Visible)
  466. return false;
  467. bool is_active = wm.IsActive();
  468. bool maximize_this = false;
  469. if (!is_active){
  470. return false;
  471. }
  472. setting_windowstates = true;
  473. foreach (Form frm in mdi_child_list) {
  474. if (frm == form) {
  475. continue;
  476. } else if (!frm.Visible){
  477. continue;
  478. }
  479. if (frm.WindowState == FormWindowState.Maximized && is_active) {
  480. if (!maximize_this && is_active)
  481. maximize_this = true;
  482. frm.WindowState = FormWindowState.Normal;
  483. }
  484. }
  485. if (maximize_this) {
  486. form.WindowState = FormWindowState.Maximized;
  487. }
  488. SetParentText(false);
  489. SizeScrollBars();
  490. XplatUI.RequestNCRecalc(ParentForm.Handle);
  491. setting_windowstates = false;
  492. return maximize_this;
  493. }
  494. internal int ChildrenCreated {
  495. get { return mdi_created; }
  496. set { mdi_created = value; }
  497. }
  498. internal Form ActiveMdiChild {
  499. get {
  500. if (Controls.Count < 1)
  501. return null;
  502. return (Form) Controls [0];
  503. }
  504. set {
  505. ActivateChild (value);
  506. }
  507. }
  508. }
  509. }