TabControl.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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) 2004 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jackson Harper ([email protected])
  24. using System;
  25. using System.Drawing;
  26. using System.Collections;
  27. namespace System.Windows.Forms {
  28. public class TabControl : Control {
  29. private int selected_index = -1;
  30. private TabAlignment alignment;
  31. private TabAppearance appearance;
  32. private TabDrawMode draw_mode;
  33. private bool multiline;
  34. private ImageList image_list;
  35. private Size item_size = Size.Empty;
  36. private Point padding;
  37. private int row_count = 1;
  38. private bool hottrack;
  39. private TabPageCollection tab_pages;
  40. private bool show_tool_tips;
  41. private TabSizeMode size_mode;
  42. private bool redraw;
  43. private Rectangle display_rect;
  44. public TabControl ()
  45. {
  46. tab_pages = new TabPageCollection (this);
  47. SetStyle (ControlStyles.UserPaint, true);
  48. padding = ThemeEngine.Current.TabControlDefaultPadding;
  49. item_size = ThemeEngine.Current.TabControlDefaultItemSize;
  50. MouseDown += new MouseEventHandler (MouseDownHandler);
  51. SizeChanged += new EventHandler (SizeChangedHandler);
  52. }
  53. public TabAlignment Alignment {
  54. get { return alignment; }
  55. set {
  56. if (alignment == value)
  57. return;
  58. alignment = value;
  59. if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  60. multiline = true;
  61. Refresh ();
  62. }
  63. }
  64. public TabAppearance Appearance {
  65. get { return appearance; }
  66. set {
  67. if (appearance == value)
  68. return;
  69. appearance = value;
  70. Refresh ();
  71. }
  72. }
  73. public override Color BackColor {
  74. get { return base.BackColor; }
  75. set { /* nothing happens on set on MS */ }
  76. }
  77. public override Image BackgroundImage {
  78. get { return base.BackgroundImage; }
  79. set { base.BackgroundImage = value; }
  80. }
  81. public override Rectangle DisplayRectangle {
  82. get {
  83. return ThemeEngine.Current.GetTabControlDisplayRectangle (this);
  84. }
  85. }
  86. public TabDrawMode DrawMode {
  87. get { return draw_mode; }
  88. set {
  89. if (draw_mode == value)
  90. return;
  91. draw_mode = value;
  92. Refresh ();
  93. }
  94. }
  95. public override Color ForeColor {
  96. get { return base.ForeColor; }
  97. set { base.ForeColor = value; }
  98. }
  99. public bool HotTrack {
  100. get { return hottrack; }
  101. set {
  102. if (hottrack == value)
  103. return;
  104. hottrack = value;
  105. Refresh ();
  106. }
  107. }
  108. public ImageList ImageList {
  109. get { return image_list; }
  110. set { image_list = value; }
  111. }
  112. public Size ItemSize {
  113. get {
  114. return item_size;
  115. }
  116. set {
  117. if (value.Height < 0 || value.Width < 0)
  118. throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
  119. item_size = value;
  120. Refresh ();
  121. }
  122. }
  123. public bool Multiline {
  124. get { return multiline; }
  125. set {
  126. if (multiline == value)
  127. return;
  128. multiline = value;
  129. if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  130. alignment = TabAlignment.Top;
  131. Refresh ();
  132. }
  133. }
  134. public Point Padding {
  135. get { return padding; }
  136. set {
  137. if (value.X < 0 || value.Y < 0)
  138. throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
  139. if (padding == value)
  140. return;
  141. padding = value;
  142. Refresh ();
  143. }
  144. }
  145. public int RowCount {
  146. get { return row_count; }
  147. }
  148. public int SelectedIndex {
  149. get { return selected_index; }
  150. set {
  151. if (selected_index == value)
  152. return;
  153. if (selected_index < -1) {
  154. throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
  155. "'value' must be greater than or equal to -1.");
  156. }
  157. SuspendLayout ();
  158. if (selected_index != -1)
  159. Controls [selected_index].Visible = false;
  160. selected_index = value;
  161. if (selected_index != -1)
  162. Controls [selected_index].Visible = true;
  163. ResumeLayout ();
  164. SizeTabs (Width);
  165. Refresh ();
  166. }
  167. }
  168. public TabPage SelectedTab {
  169. get {
  170. if (selected_index == -1)
  171. return null;
  172. return tab_pages [selected_index];
  173. }
  174. set {
  175. int index = IndexForTabPage (value);
  176. if (index == selected_index)
  177. return;
  178. selected_index = index;
  179. Refresh ();
  180. }
  181. }
  182. public bool ShowToolTips {
  183. get { return show_tool_tips; }
  184. set {
  185. if (show_tool_tips == value)
  186. return;
  187. show_tool_tips = value;
  188. Refresh ();
  189. }
  190. }
  191. public TabSizeMode SizeMode {
  192. get { return size_mode; }
  193. set {
  194. if (size_mode == value)
  195. return;
  196. size_mode = value;
  197. Refresh ();
  198. }
  199. }
  200. public int TabCount {
  201. get {
  202. return tab_pages.Count;
  203. }
  204. }
  205. public TabPageCollection TabPages {
  206. get { return tab_pages; }
  207. }
  208. public override string Text {
  209. get { return base.Text; }
  210. set { base.Text = value; }
  211. }
  212. [MonoTODO ("Anything special need to be done?")]
  213. protected override CreateParams CreateParams {
  214. get {
  215. CreateParams c = base.CreateParams;
  216. // Do we need to do anything here?
  217. return c;
  218. }
  219. }
  220. protected override Size DefaultSize {
  221. get { return new Size (200, 100); }
  222. }
  223. private Size DefaultItemSize {
  224. get {
  225. return ThemeEngine.Current.TabControlDefaultItemSize;
  226. }
  227. }
  228. public new event EventHandler BackColorChanged {
  229. add { base.BackColorChanged += value; }
  230. remove { base.BackColorChanged -= value; }
  231. }
  232. public new event EventHandler BackgroundImageChanged {
  233. add { base.BackgroundImageChanged += value; }
  234. remove { base.BackgroundImageChanged -= value; }
  235. }
  236. public new event EventHandler ForeColorChanged {
  237. add { base.ForeColorChanged += value; }
  238. remove { base.ForeColorChanged -= value; }
  239. }
  240. public new event PaintEventHandler Paint {
  241. add { base.Paint += value; }
  242. remove { base.Paint -= value; }
  243. }
  244. public new event EventHandler TextChanged {
  245. add { base.TextChanged += value; }
  246. remove { base.TextChanged -= value; }
  247. }
  248. public event DrawItemEventHandler DrawItem;
  249. public event EventHandler SelectedIndexChanged;
  250. public Rectangle GetTabRect (int index)
  251. {
  252. TabPage page = GetTab (index);
  253. return page.TabBounds;
  254. }
  255. public Control GetControl (int index)
  256. {
  257. return GetTab (index);
  258. }
  259. protected override Control.ControlCollection CreateControlsInstance ()
  260. {
  261. return new TabControl.ControlCollection (this);
  262. }
  263. protected override void CreateHandle ()
  264. {
  265. ResizeTabPages ();
  266. base.CreateHandle ();
  267. }
  268. protected override void Dispose (bool disposing)
  269. {
  270. base.Dispose (disposing);
  271. }
  272. protected virtual object [] GetItems ()
  273. {
  274. TabPage [] pages = new TabPage [Controls.Count];
  275. Controls.CopyTo (pages, 0);
  276. return pages;
  277. }
  278. protected virtual object [] GetItems (Type type)
  279. {
  280. object [] pages = (object []) Array.CreateInstance (type, Controls.Count);
  281. Controls.CopyTo (pages, 0);
  282. return pages;
  283. }
  284. protected string GetToolTipText (object item)
  285. {
  286. TabPage page = (TabPage) item;
  287. return page.ToolTipText;
  288. }
  289. protected override void WndProc (ref Message m)
  290. {
  291. switch ((Msg) m.Msg) {
  292. case Msg.WM_PAINT:
  293. PaintEventArgs paint_event;
  294. paint_event = XplatUI.PaintEventStart (Handle);
  295. PaintInternal (paint_event);
  296. XplatUI.PaintEventEnd (Handle);
  297. break;
  298. default:
  299. base.WndProc (ref m);
  300. break;
  301. }
  302. }
  303. private void MouseDownHandler (object sender, MouseEventArgs e)
  304. {
  305. int count = Controls.Count;
  306. for (int i = 0; i<count; i++) {
  307. if (!GetTabRect (i).Contains (e.X, e.Y))
  308. continue;
  309. SelectedIndex = i;
  310. break;
  311. }
  312. }
  313. private void SizeChangedHandler (object sender, EventArgs e)
  314. {
  315. ResizeTabPages ();
  316. }
  317. internal void UpdateTabpage (TabPage page)
  318. {
  319. }
  320. internal int IndexForTabPage (TabPage page)
  321. {
  322. for (int i = 0; i < tab_pages.Count; i++) {
  323. if (page == tab_pages [i])
  324. return i;
  325. }
  326. return -1;
  327. }
  328. private void ResizeTabPages ()
  329. {
  330. SizeTabs (Width);
  331. Rectangle r = DisplayRectangle;
  332. foreach (TabPage page in Controls) {
  333. page.Bounds = r;
  334. }
  335. }
  336. private int MinimumTabWidth {
  337. get {
  338. return ThemeEngine.Current.TabControlMinimumTabWidth;
  339. }
  340. }
  341. private Size TabSpacing {
  342. get {
  343. return ThemeEngine.Current.TabControlGetSpacing (this);
  344. }
  345. }
  346. private void CalcTabRows (int row_width)
  347. {
  348. int xpos = 4;
  349. Size spacing = TabSpacing;
  350. row_count = 1;
  351. for (int i = 0; i < TabPages.Count; i++) {
  352. TabPage page = TabPages [i];
  353. int width;
  354. page.Row = 1;
  355. if (!multiline)
  356. continue;
  357. if (SizeMode == TabSizeMode.Fixed) {
  358. width = item_size.Width;
  359. } else {
  360. width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
  361. }
  362. if (width < MinimumTabWidth)
  363. width = MinimumTabWidth;
  364. if (xpos + width > row_width && multiline) {
  365. xpos = 4;
  366. for (int j = 0; j < i; j++) {
  367. TabPages [j].Row++;
  368. }
  369. row_count++;
  370. }
  371. xpos += width + 1 + spacing.Width;
  372. }
  373. if (SelectedIndex != -1 && TabPages [SelectedIndex].Row != 1)
  374. DropRow (TabPages [SelectedIndex].Row);
  375. }
  376. private void DropRow (int row)
  377. {
  378. foreach (TabPage page in TabPages) {
  379. if (page.Row == row) {
  380. page.Row = 1;
  381. } else {
  382. page.Row++;
  383. }
  384. }
  385. }
  386. private void SizeTabs (int row_width)
  387. {
  388. int xpos = 4;
  389. int ypos = 1;
  390. int prev_row = 1;
  391. Size spacing = TabSpacing;
  392. CalcTabRows (row_width);
  393. for (int i = 0; i < TabPages.Count; i++) {
  394. TabPage page = TabPages [i];
  395. int width;
  396. if (SizeMode == TabSizeMode.Fixed) {
  397. width = item_size.Width;
  398. } else {
  399. width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
  400. }
  401. if (width < MinimumTabWidth)
  402. width = MinimumTabWidth;
  403. if (page.Row != prev_row) {
  404. xpos = 4;
  405. }
  406. page.TabBounds = new Rectangle (xpos,
  407. ypos + (row_count - page.Row) * (item_size.Height + spacing.Height),
  408. width, item_size.Height);
  409. if (i == SelectedIndex)
  410. ExpandSelected (page, xpos == 4 || xpos == row_width, row_width);
  411. xpos += width + 1 + spacing.Width;
  412. prev_row = page.Row;
  413. }
  414. }
  415. private void ExpandSelected (TabPage page, bool edge, int row_width)
  416. {
  417. int wexpand = (edge ? 2 : 4);
  418. if (Appearance != TabAppearance.Normal)
  419. return;
  420. if (Alignment == TabAlignment.Top || Alignment == TabAlignment.Bottom) {
  421. int x, y, w, h;
  422. x = page.TabBounds.X - wexpand;
  423. y = page.TabBounds.Y;
  424. w = page.TabBounds.Width + (wexpand * 2);
  425. h = page.TabBounds.Height + 2;
  426. if (Alignment == TabAlignment.Top)
  427. y -= 1;
  428. page.TabBounds = new Rectangle (x, y, w, h);
  429. } else {
  430. // TODO: left and right
  431. }
  432. }
  433. private void PaintInternal (PaintEventArgs pe)
  434. {
  435. if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
  436. return;
  437. Draw ();
  438. pe.Graphics.DrawImageUnscaled (ImageBuffer, 0, 0);
  439. ImageBuffer.Save ("ImageBuffer.bmp");
  440. // On MS the Paint event never seems to be raised
  441. }
  442. private void Redraw (bool recalculate)
  443. {
  444. if (recalculate) {
  445. }
  446. redraw = true;
  447. Refresh ();
  448. }
  449. private void Draw ()
  450. {
  451. ThemeEngine.Current.DrawTabControl (DeviceContext, ClientRectangle, this);
  452. redraw = false;
  453. }
  454. private TabPage GetTab (int index)
  455. {
  456. return Controls [index] as TabPage;
  457. }
  458. private void SetTab (int index, TabPage value)
  459. {
  460. ((IList) Controls).Insert (index, value);
  461. Refresh ();
  462. }
  463. public class ControlCollection : System.Windows.Forms.Control.ControlCollection {
  464. private TabControl owner;
  465. private ArrayList list = new ArrayList ();
  466. public ControlCollection (TabControl owner) : base (owner)
  467. {
  468. this.owner = owner;
  469. }
  470. public override void Add (Control value)
  471. {
  472. if (!(value is TabPage))
  473. throw new ArgumentException ("Cannot add " +
  474. value.GetType ().Name + " to TabControl. " +
  475. "Only TabPages can be directly added to TabControls.");
  476. base.Add (value);
  477. if (Count == 0)
  478. owner.SelectedIndex = 0;
  479. }
  480. }
  481. public class TabPageCollection : IList, ICollection, IEnumerable {
  482. private TabControl owner;
  483. private IList controls;
  484. public TabPageCollection (TabControl owner)
  485. {
  486. if (owner == null)
  487. throw new ArgumentNullException ("Value cannot be null.");
  488. this.owner = owner;
  489. controls = owner.Controls;
  490. }
  491. public virtual int Count {
  492. get { return owner.Controls.Count; }
  493. }
  494. public virtual bool IsReadOnly {
  495. get { return false; }
  496. }
  497. public virtual TabPage this [int index] {
  498. get {
  499. return owner.GetTab (index);
  500. }
  501. set {
  502. owner.SetTab (index, value);
  503. }
  504. }
  505. bool ICollection.IsSynchronized {
  506. get { return false; }
  507. }
  508. object ICollection.SyncRoot {
  509. get { return this; }
  510. }
  511. bool IList.IsFixedSize {
  512. get { return false; }
  513. }
  514. object IList.this [int index] {
  515. get {
  516. return owner.GetTab (index);
  517. }
  518. set {
  519. owner.SetTab (index, (TabPage) value);
  520. }
  521. }
  522. public void Add (TabPage page)
  523. {
  524. if (page == null)
  525. throw new ArgumentNullException ("Value cannot be null.");
  526. owner.Controls.Add (page);
  527. }
  528. public void AddRange (TabPage [] pages)
  529. {
  530. if (pages == null)
  531. throw new ArgumentNullException ("Value cannot be null.");
  532. owner.Controls.AddRange (pages);
  533. }
  534. public virtual void Clear ()
  535. {
  536. owner.Controls.Clear ();
  537. }
  538. public bool Contains (TabPage page)
  539. {
  540. if (page == null)
  541. throw new ArgumentNullException ("Value cannot be null.");
  542. return owner.Controls.Contains (page);
  543. }
  544. public virtual IEnumerator GetEnumerator ()
  545. {
  546. return owner.Controls.GetEnumerator ();
  547. }
  548. public int IndexOf (TabPage page)
  549. {
  550. return owner.Controls.IndexOf (page);
  551. }
  552. public void Remove (TabPage page)
  553. {
  554. owner.Controls.Remove (page);
  555. }
  556. public virtual void RemoveAt (int index)
  557. {
  558. owner.Controls.RemoveAt (index);
  559. }
  560. void ICollection.CopyTo (Array dest, int index)
  561. {
  562. owner.Controls.CopyTo (dest, index);
  563. }
  564. int IList.Add (object value)
  565. {
  566. // return owner.Controls.Add ((TabPage) value);
  567. return -1;
  568. }
  569. bool IList.Contains (object page)
  570. {
  571. return Contains ((TabPage) page);
  572. }
  573. int IList.IndexOf (object page)
  574. {
  575. return IndexOf ((TabPage) page);
  576. }
  577. void IList.Insert (int index, object value)
  578. {
  579. controls.Insert (index, (TabPage) value);
  580. }
  581. void IList.Remove (object value)
  582. {
  583. Remove ((TabPage) value);
  584. }
  585. }
  586. }
  587. }