TabControl.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. }
  52. public TabAlignment Alignment {
  53. get { return alignment; }
  54. set {
  55. if (alignment == value)
  56. return;
  57. alignment = value;
  58. if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  59. multiline = true;
  60. Refresh ();
  61. }
  62. }
  63. public TabAppearance Appearance {
  64. get { return appearance; }
  65. set {
  66. if (appearance == value)
  67. return;
  68. appearance = value;
  69. Refresh ();
  70. }
  71. }
  72. public override Color BackColor {
  73. get { return base.BackColor; }
  74. set { /* nothing happens on set on MS */ }
  75. }
  76. public override Image BackgroundImage {
  77. get { return base.BackgroundImage; }
  78. set { base.BackgroundImage = value; }
  79. }
  80. public override Rectangle DisplayRectangle {
  81. get {
  82. return ThemeEngine.Current.GetTabControlDisplayRectangle (this);
  83. }
  84. }
  85. public TabDrawMode DrawMode {
  86. get { return draw_mode; }
  87. set {
  88. if (draw_mode == value)
  89. return;
  90. draw_mode = value;
  91. Refresh ();
  92. }
  93. }
  94. public override Color ForeColor {
  95. get { return base.ForeColor; }
  96. set { base.ForeColor = value; }
  97. }
  98. public bool HotTrack {
  99. get { return hottrack; }
  100. set {
  101. if (hottrack == value)
  102. return;
  103. hottrack = value;
  104. Refresh ();
  105. }
  106. }
  107. public ImageList ImageList {
  108. get { return image_list; }
  109. set { image_list = value; }
  110. }
  111. public Size ItemSize {
  112. get {
  113. return item_size;
  114. }
  115. set {
  116. if (value.Height < 0 || value.Width < 0)
  117. throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
  118. item_size = value;
  119. Refresh ();
  120. }
  121. }
  122. public bool Multiline {
  123. get { return multiline; }
  124. set {
  125. if (multiline == value)
  126. return;
  127. multiline = value;
  128. if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  129. alignment = TabAlignment.Top;
  130. Refresh ();
  131. }
  132. }
  133. public Point Padding {
  134. get { return padding; }
  135. set {
  136. if (value.X < 0 || value.Y < 0)
  137. throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
  138. if (padding == value)
  139. return;
  140. padding = value;
  141. Refresh ();
  142. }
  143. }
  144. public int RowCount {
  145. get { return row_count; }
  146. }
  147. public int SelectedIndex {
  148. get { return selected_index; }
  149. set {
  150. if (selected_index == value)
  151. return;
  152. if (selected_index < -1) {
  153. throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
  154. "'value' must be greater than or equal to -1.");
  155. }
  156. SuspendLayout ();
  157. if (selected_index != -1)
  158. Controls [selected_index].Visible = false;
  159. selected_index = value;
  160. Console.WriteLine ("selected index: " + selected_index);
  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 EventHandler 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. internal void UpdateTabpage (TabPage page)
  314. {
  315. }
  316. internal int IndexForTabPage (TabPage page)
  317. {
  318. for (int i = 0; i < tab_pages.Count; i++) {
  319. if (page == tab_pages [i])
  320. return i;
  321. }
  322. return -1;
  323. }
  324. private void ResizeTabPages ()
  325. {
  326. SizeTabs (Width);
  327. Rectangle r = DisplayRectangle;
  328. foreach (TabPage page in Controls) {
  329. page.Bounds = r;
  330. }
  331. }
  332. private int MinimumTabWidth {
  333. get {
  334. return ThemeEngine.Current.TabControlMinimumTabWidth;
  335. }
  336. }
  337. private Size TabSpacing {
  338. get {
  339. return ThemeEngine.Current.TabControlGetSpacing (this);
  340. }
  341. }
  342. private void SizeTabs (int row_width)
  343. {
  344. int xpos = 4;
  345. int ypos = 1;
  346. row_count = 1;
  347. Size spacing = TabSpacing;
  348. for (int i = 0; i < TabPages.Count; i++) {
  349. TabPage page = TabPages [i];
  350. int width;
  351. if (SizeMode == TabSizeMode.Fixed) {
  352. width = item_size.Width;
  353. } else {
  354. width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
  355. }
  356. if (width < MinimumTabWidth)
  357. width = MinimumTabWidth;
  358. if (xpos + width > row_width && multiline) {
  359. xpos = 4;
  360. // Move everything
  361. for (int j = 0; j < i; j++) {
  362. TabPages [j].TabBounds = new Rectangle (
  363. TabPages [j].TabBounds.X,
  364. TabPages [j].TabBounds.Y + item_size.Height + spacing.Height,
  365. TabPages [j].TabBounds.Width,
  366. TabPages [j].TabBounds.Height);
  367. }
  368. row_count++;
  369. }
  370. page.TabBounds = new Rectangle (xpos, ypos, width, item_size.Height);
  371. xpos += width + 1 + spacing.Width;
  372. if (i == SelectedIndex) {
  373. ExpandSelected (page, xpos == 4, row_width);
  374. }
  375. }
  376. }
  377. private void ExpandSelected (TabPage page, bool edge, int row_width)
  378. {
  379. int wexpand = (edge ? 2 : 4);
  380. if (Appearance != TabAppearance.Normal)
  381. return;
  382. if (Alignment == TabAlignment.Top || Alignment == TabAlignment.Bottom) {
  383. int x, y, w, h;
  384. x = page.TabBounds.X - wexpand;
  385. y = page.TabBounds.Y;
  386. w = page.TabBounds.Width + (wexpand * 2);
  387. h = page.TabBounds.Height + 2;
  388. if (Alignment == TabAlignment.Top)
  389. y -= 1;
  390. page.TabBounds = new Rectangle (x, y, w, h);
  391. } else {
  392. // TODO: left and right
  393. }
  394. }
  395. private void PaintInternal (PaintEventArgs pe)
  396. {
  397. if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
  398. return;
  399. Draw ();
  400. pe.Graphics.DrawImageUnscaled (ImageBuffer, 0, 0);
  401. ImageBuffer.Save ("ImageBuffer.bmp");
  402. // On MS the Paint event never seems to be raised
  403. }
  404. private void Redraw (bool recalculate)
  405. {
  406. if (recalculate) {
  407. }
  408. redraw = true;
  409. Refresh ();
  410. }
  411. private void Draw ()
  412. {
  413. ThemeEngine.Current.DrawTabControl (DeviceContext, ClientRectangle, this);
  414. redraw = false;
  415. }
  416. private TabPage GetTab (int index)
  417. {
  418. return Controls [index] as TabPage;
  419. }
  420. private void SetTab (int index, TabPage value)
  421. {
  422. ((IList) Controls).Insert (index, value);
  423. Refresh ();
  424. }
  425. public class ControlCollection : System.Windows.Forms.Control.ControlCollection {
  426. private TabControl owner;
  427. private ArrayList list = new ArrayList ();
  428. public ControlCollection (TabControl owner) : base (owner)
  429. {
  430. this.owner = owner;
  431. }
  432. public override void Add (Control value)
  433. {
  434. if (!(value is TabPage))
  435. throw new ArgumentException ("Cannot add " +
  436. value.GetType ().Name + " to TabControl. " +
  437. "Only TabPages can be directly added to TabControls.");
  438. base.Add (value);
  439. if (Count == 0)
  440. owner.SelectedIndex = 0;
  441. }
  442. }
  443. public class TabPageCollection : IList, ICollection, IEnumerable {
  444. private TabControl owner;
  445. private IList controls;
  446. public TabPageCollection (TabControl owner)
  447. {
  448. if (owner == null)
  449. throw new ArgumentNullException ("Value cannot be null.");
  450. this.owner = owner;
  451. controls = owner.Controls;
  452. }
  453. public virtual int Count {
  454. get { return owner.Controls.Count; }
  455. }
  456. public virtual bool IsReadOnly {
  457. get { return false; }
  458. }
  459. public virtual TabPage this [int index] {
  460. get {
  461. return owner.GetTab (index);
  462. }
  463. set {
  464. owner.SetTab (index, value);
  465. }
  466. }
  467. bool ICollection.IsSynchronized {
  468. get { return false; }
  469. }
  470. object ICollection.SyncRoot {
  471. get { return this; }
  472. }
  473. bool IList.IsFixedSize {
  474. get { return false; }
  475. }
  476. object IList.this [int index] {
  477. get {
  478. return owner.GetTab (index);
  479. }
  480. set {
  481. owner.SetTab (index, (TabPage) value);
  482. }
  483. }
  484. public void Add (TabPage page)
  485. {
  486. if (page == null)
  487. throw new ArgumentNullException ("Value cannot be null.");
  488. owner.Controls.Add (page);
  489. }
  490. public void AddRange (TabPage [] pages)
  491. {
  492. if (pages == null)
  493. throw new ArgumentNullException ("Value cannot be null.");
  494. owner.Controls.AddRange (pages);
  495. }
  496. public virtual void Clear ()
  497. {
  498. owner.Controls.Clear ();
  499. }
  500. public bool Contains (TabPage page)
  501. {
  502. if (page == null)
  503. throw new ArgumentNullException ("Value cannot be null.");
  504. return owner.Controls.Contains (page);
  505. }
  506. public virtual IEnumerator GetEnumerator ()
  507. {
  508. return owner.Controls.GetEnumerator ();
  509. }
  510. public int IndexOf (TabPage page)
  511. {
  512. return owner.Controls.IndexOf (page);
  513. }
  514. public void Remove (TabPage page)
  515. {
  516. owner.Controls.Remove (page);
  517. }
  518. public virtual void RemoveAt (int index)
  519. {
  520. owner.Controls.RemoveAt (index);
  521. }
  522. void ICollection.CopyTo (Array dest, int index)
  523. {
  524. owner.Controls.CopyTo (dest, index);
  525. }
  526. int IList.Add (object value)
  527. {
  528. // return owner.Controls.Add ((TabPage) value);
  529. return -1;
  530. }
  531. bool IList.Contains (object page)
  532. {
  533. return Contains ((TabPage) page);
  534. }
  535. int IList.IndexOf (object page)
  536. {
  537. return IndexOf ((TabPage) page);
  538. }
  539. void IList.Insert (int index, object value)
  540. {
  541. controls.Insert (index, (TabPage) value);
  542. }
  543. void IList.Remove (object value)
  544. {
  545. Remove ((TabPage) value);
  546. }
  547. }
  548. }
  549. }