TabControl.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732
  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-2005 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jackson Harper ([email protected])
  24. using System;
  25. using System.Collections;
  26. using System.ComponentModel;
  27. using System.ComponentModel.Design;
  28. using System.Drawing;
  29. using System.Runtime.InteropServices;
  30. namespace System.Windows.Forms {
  31. #if NET_2_0
  32. [ComVisibleAttribute (true)]
  33. [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)]
  34. #endif
  35. [DefaultEvent("SelectedIndexChanged")]
  36. [DefaultProperty("TabPages")]
  37. [Designer("System.Windows.Forms.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  38. public class TabControl : Control {
  39. #region Fields
  40. private int selected_index = -1;
  41. private TabAlignment alignment;
  42. private TabAppearance appearance;
  43. private TabDrawMode draw_mode;
  44. private bool multiline;
  45. private ImageList image_list;
  46. private Size item_size = Size.Empty;
  47. private Point padding;
  48. private int row_count = 0;
  49. private bool hottrack;
  50. private TabPageCollection tab_pages;
  51. private bool show_tool_tips;
  52. private TabSizeMode size_mode;
  53. private bool show_slider = false;
  54. private ButtonState right_slider_state;
  55. private ButtonState left_slider_state;
  56. private int slider_pos = 0;
  57. #if NET_2_0
  58. private bool rightToLeftLayout;
  59. #endif
  60. #endregion // Fields
  61. #region Public Constructors
  62. public TabControl ()
  63. {
  64. tab_pages = new TabPageCollection (this);
  65. SetStyle (ControlStyles.UserPaint, false);
  66. padding = ThemeEngine.Current.TabControlDefaultPadding;
  67. item_size = ThemeEngine.Current.TabControlDefaultItemSize;
  68. MouseDown += new MouseEventHandler (MouseDownHandler);
  69. MouseUp += new MouseEventHandler (MouseUpHandler);
  70. SizeChanged += new EventHandler (SizeChangedHandler);
  71. }
  72. #endregion // Public Constructors
  73. #region Public Instance Properties
  74. [DefaultValue(TabAlignment.Top)]
  75. [Localizable(true)]
  76. [RefreshProperties(RefreshProperties.All)]
  77. public TabAlignment Alignment {
  78. get { return alignment; }
  79. set {
  80. if (alignment == value)
  81. return;
  82. alignment = value;
  83. if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  84. multiline = true;
  85. Redraw ();
  86. }
  87. }
  88. [DefaultValue(TabAppearance.Normal)]
  89. [Localizable(true)]
  90. public TabAppearance Appearance {
  91. get { return appearance; }
  92. set {
  93. if (appearance == value)
  94. return;
  95. appearance = value;
  96. Redraw ();
  97. }
  98. }
  99. [Browsable(false)]
  100. [EditorBrowsable(EditorBrowsableState.Never)]
  101. public override Color BackColor {
  102. get { return ThemeEngine.Current.ColorControl; }
  103. set { /* nothing happens on set on MS */ }
  104. }
  105. [Browsable(false)]
  106. [EditorBrowsable(EditorBrowsableState.Never)]
  107. public override Image BackgroundImage {
  108. get { return base.BackgroundImage; }
  109. set { base.BackgroundImage = value; }
  110. }
  111. #if NET_2_0
  112. [Browsable (false)]
  113. [EditorBrowsable (EditorBrowsableState.Never)]
  114. public override ImageLayout BackgroundImageLayout {
  115. get { return base.BackgroundImageLayout; }
  116. set { base.BackgroundImageLayout = value; }
  117. }
  118. #endif
  119. public override Rectangle DisplayRectangle {
  120. get {
  121. return ThemeEngine.Current.TabControlGetDisplayRectangle (this);
  122. }
  123. }
  124. #if NET_2_0
  125. [EditorBrowsable (EditorBrowsableState.Never)]
  126. protected override bool DoubleBuffered {
  127. get { return base.DoubleBuffered; }
  128. set { base.DoubleBuffered = value; }
  129. }
  130. #endif
  131. [DefaultValue(TabDrawMode.Normal)]
  132. public TabDrawMode DrawMode {
  133. get { return draw_mode; }
  134. set {
  135. if (draw_mode == value)
  136. return;
  137. draw_mode = value;
  138. Redraw ();
  139. }
  140. }
  141. [Browsable(false)]
  142. [EditorBrowsable(EditorBrowsableState.Never)]
  143. public override Color ForeColor {
  144. get { return base.ForeColor; }
  145. set { base.ForeColor = value; }
  146. }
  147. [DefaultValue(false)]
  148. public bool HotTrack {
  149. get { return hottrack; }
  150. set {
  151. if (hottrack == value)
  152. return;
  153. hottrack = value;
  154. Redraw ();
  155. }
  156. }
  157. #if NET_2_0
  158. [RefreshProperties (RefreshProperties.Repaint)]
  159. #endif
  160. [DefaultValue(null)]
  161. public ImageList ImageList {
  162. get { return image_list; }
  163. set { image_list = value; }
  164. }
  165. [Localizable(true)]
  166. public Size ItemSize {
  167. get {
  168. return item_size;
  169. }
  170. set {
  171. if (value.Height < 0 || value.Width < 0)
  172. throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
  173. item_size = value;
  174. Redraw ();
  175. }
  176. }
  177. [DefaultValue(false)]
  178. public bool Multiline {
  179. get { return multiline; }
  180. set {
  181. if (multiline == value)
  182. return;
  183. multiline = value;
  184. if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
  185. alignment = TabAlignment.Top;
  186. Redraw ();
  187. }
  188. }
  189. [Localizable(true)]
  190. public new Point Padding {
  191. get { return padding; }
  192. set {
  193. if (value.X < 0 || value.Y < 0)
  194. throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
  195. if (padding == value)
  196. return;
  197. padding = value;
  198. Redraw ();
  199. }
  200. }
  201. #if NET_2_0
  202. [MonoTODO ("Saves the value and raises event, but needs actual implementation call")]
  203. [Localizable (true)]
  204. [DefaultValue (false)]
  205. public virtual bool RightToLeftLayout {
  206. get { return this.rightToLeftLayout; }
  207. set {
  208. if (value != this.rightToLeftLayout) {
  209. this.rightToLeftLayout = value;
  210. this.OnRightToLeftLayoutChanged (EventArgs.Empty);
  211. }
  212. }
  213. }
  214. #endif
  215. [Browsable(false)]
  216. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  217. public int RowCount {
  218. get { return row_count; }
  219. }
  220. [DefaultValue(-1)]
  221. [Browsable(false)]
  222. public int SelectedIndex {
  223. get { return selected_index; }
  224. set {
  225. if (value < -1) {
  226. #if NET_2_0
  227. throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " +
  228. "'SelectedIndex' must be greater than or equal to -1.");
  229. #else
  230. throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
  231. "'value' must be greater than or equal to -1.");
  232. #endif
  233. }
  234. if (!this.IsHandleCreated) {
  235. if (selected_index != value) {
  236. selected_index = value;
  237. #if !NET_2_0
  238. OnSelectedIndexChanged (EventArgs.Empty);
  239. #endif
  240. }
  241. return;
  242. }
  243. if (value >= TabCount) {
  244. if (value != selected_index)
  245. OnSelectedIndexChanged (EventArgs.Empty);
  246. return;
  247. }
  248. if (value == selected_index) {
  249. if (selected_index > -1)
  250. Invalidate(GetTabRect (selected_index));
  251. return;
  252. }
  253. #if NET_2_0
  254. TabControlCancelEventArgs ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Deselecting);
  255. OnDeselecting (ret);
  256. if (ret.Cancel)
  257. return;
  258. #endif
  259. int old_index = selected_index;
  260. int new_index = value;
  261. selected_index = new_index;
  262. #if NET_2_0
  263. ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Selecting);
  264. OnSelecting (ret);
  265. if (ret.Cancel) {
  266. selected_index = old_index;
  267. return;
  268. }
  269. #endif
  270. SuspendLayout ();
  271. Rectangle invalid = Rectangle.Empty;
  272. bool refresh = false;
  273. if (new_index != -1 && show_slider && new_index < slider_pos) {
  274. slider_pos = new_index;
  275. refresh = true;
  276. }
  277. if (new_index != -1) {
  278. int le = TabPages[new_index].TabBounds.Right;
  279. int re = ThemeEngine.Current.TabControlGetLeftScrollRect (this).Left;
  280. if (show_slider && le > re) {
  281. int i = 0;
  282. for (i = 0; i < new_index - 1; i++) {
  283. if (TabPages [i].TabBounds.Left < 0) // tab scrolled off the visible area, ignore
  284. continue;
  285. if (TabPages [new_index].TabBounds.Right - TabPages[i].TabBounds.Right < re) {
  286. i++;
  287. break;
  288. }
  289. }
  290. slider_pos = i;
  291. refresh = true;
  292. }
  293. }
  294. if (old_index != -1 && new_index != -1) {
  295. if (!refresh)
  296. invalid = GetTabRect (old_index);
  297. ((TabPage) Controls[old_index]).SetVisible (false);
  298. }
  299. TabPage selected = null;
  300. if (new_index != -1) {
  301. selected = (TabPage) Controls[new_index];
  302. invalid = Rectangle.Union (invalid, GetTabRect (new_index));
  303. selected.SetVisible (true);
  304. }
  305. OnSelectedIndexChanged (EventArgs.Empty);
  306. ResumeLayout ();
  307. if (refresh) {
  308. SizeTabs ();
  309. Refresh ();
  310. } else if (new_index != -1 && selected.Row != BottomRow) {
  311. DropRow (TabPages[new_index].Row);
  312. // calculating what to invalidate here seems to be slower then just
  313. // refreshing the whole thing
  314. SizeTabs ();
  315. Refresh ();
  316. } else {
  317. SizeTabs ();
  318. // The lines are drawn on the edges of the tabs so the invalid area should
  319. // needs to include the extra pixels of line width.
  320. if (appearance == TabAppearance.Normal) {
  321. invalid.Inflate (6, 4);
  322. }
  323. Invalidate (invalid);
  324. }
  325. }
  326. }
  327. [Browsable(false)]
  328. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  329. public TabPage SelectedTab {
  330. get {
  331. if (selected_index == -1)
  332. return null;
  333. return tab_pages [selected_index];
  334. }
  335. set {
  336. int index = IndexForTabPage (value);
  337. if (index == selected_index)
  338. return;
  339. SelectedIndex = index;
  340. }
  341. }
  342. [DefaultValue(false)]
  343. [Localizable(true)]
  344. public bool ShowToolTips {
  345. get { return show_tool_tips; }
  346. set {
  347. if (show_tool_tips == value)
  348. return;
  349. show_tool_tips = value;
  350. Redraw ();
  351. }
  352. }
  353. [DefaultValue(TabSizeMode.Normal)]
  354. [RefreshProperties(RefreshProperties.Repaint)]
  355. public TabSizeMode SizeMode {
  356. get { return size_mode; }
  357. set {
  358. if (size_mode == value)
  359. return;
  360. size_mode = value;
  361. Redraw ();
  362. }
  363. }
  364. [Browsable(false)]
  365. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  366. public int TabCount {
  367. get {
  368. return tab_pages.Count;
  369. }
  370. }
  371. #if NET_2_0
  372. [Editor ("System.Windows.Forms.Design.TabPageCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
  373. #else
  374. [DefaultValue(null)]
  375. #endif
  376. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  377. [MergableProperty(false)]
  378. public TabPageCollection TabPages {
  379. get { return tab_pages; }
  380. }
  381. [Browsable(false)]
  382. [Bindable(false)]
  383. [EditorBrowsable(EditorBrowsableState.Never)]
  384. public override string Text {
  385. get { return base.Text; }
  386. set { base.Text = value; }
  387. }
  388. #endregion // Public Instance Properties
  389. #region Internal Properties
  390. internal bool ShowSlider {
  391. get { return show_slider; }
  392. set { show_slider = value; }
  393. }
  394. internal int SliderPos {
  395. get { return slider_pos; }
  396. }
  397. internal ButtonState RightSliderState {
  398. get { return right_slider_state; }
  399. }
  400. internal ButtonState LeftSliderState {
  401. get { return left_slider_state; }
  402. }
  403. #endregion // Internal Properties
  404. #region Protected Instance Properties
  405. protected override CreateParams CreateParams {
  406. get {
  407. CreateParams c = base.CreateParams;
  408. return c;
  409. }
  410. }
  411. protected override Size DefaultSize {
  412. get { return new Size (200, 100); }
  413. }
  414. #endregion // Protected Instance Properties
  415. #region Public Instance Methods
  416. public Rectangle GetTabRect (int index)
  417. {
  418. TabPage page = GetTab (index);
  419. return page.TabBounds;
  420. }
  421. public Control GetControl (int index)
  422. {
  423. return GetTab (index);
  424. }
  425. #if NET_2_0
  426. public void SelectTab (TabPage tabPage)
  427. {
  428. if (tabPage == null)
  429. throw new ArgumentNullException ("tabPage");
  430. SelectTab (this.tab_pages [tabPage]);
  431. }
  432. public void SelectTab (string tabPageName)
  433. {
  434. if (tabPageName == null)
  435. throw new ArgumentNullException ("tabPageName");
  436. SelectTab (this.tab_pages [tabPageName]);
  437. }
  438. public void SelectTab (int index)
  439. {
  440. if (index < 0 || index > this.tab_pages.Count - 1)
  441. throw new ArgumentOutOfRangeException ("index");
  442. SelectedIndex = index;
  443. }
  444. public void DeselectTab (TabPage tabPage)
  445. {
  446. if (tabPage == null)
  447. throw new ArgumentNullException ("tabPage");
  448. DeselectTab (this.tab_pages [tabPage]);
  449. }
  450. public void DeselectTab (string key)
  451. {
  452. if (key == null)
  453. throw new ArgumentNullException ("tabPageName");
  454. DeselectTab (this.tab_pages [key]);
  455. }
  456. public void DeselectTab (int index)
  457. {
  458. if (index == SelectedIndex) {
  459. if (index >= 0 && index < this.tab_pages.Count - 1)
  460. SelectedIndex = ++index;
  461. else
  462. SelectedIndex = 0;
  463. }
  464. }
  465. #endif
  466. public override string ToString ()
  467. {
  468. string res = String.Concat (base.ToString (),
  469. ", TabPages.Count: ",
  470. TabCount);
  471. if (TabCount > 0)
  472. res = String.Concat (res, ", TabPages[0]: ",
  473. TabPages [0]);
  474. return res;
  475. }
  476. #endregion // Public Instance Methods
  477. #region Protected Instance Methods
  478. #region Handles
  479. protected override Control.ControlCollection CreateControlsInstance ()
  480. {
  481. return new TabControl.ControlCollection (this);
  482. }
  483. protected override void CreateHandle ()
  484. {
  485. base.CreateHandle ();
  486. selected_index = (selected_index >= TabCount ? (TabCount > 0 ? 0 : -1) : selected_index);
  487. if (TabCount > 0) {
  488. if (selected_index > -1)
  489. this.SelectedTab.SetVisible(true);
  490. else
  491. tab_pages[0].SetVisible(true);
  492. }
  493. ResizeTabPages ();
  494. }
  495. protected override void OnHandleCreated (EventArgs e)
  496. {
  497. base.OnHandleCreated (e);
  498. }
  499. protected override void OnHandleDestroyed (EventArgs e)
  500. {
  501. base.OnHandleDestroyed (e);
  502. }
  503. protected override void Dispose (bool disposing)
  504. {
  505. base.Dispose (disposing);
  506. }
  507. #endregion
  508. #region Events
  509. protected virtual void OnDrawItem (DrawItemEventArgs e)
  510. {
  511. if (DrawMode != TabDrawMode.OwnerDrawFixed)
  512. return;
  513. DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
  514. if (eh != null)
  515. eh (this, e);
  516. }
  517. internal void OnDrawItemInternal (DrawItemEventArgs e)
  518. {
  519. OnDrawItem (e);
  520. }
  521. protected override void OnFontChanged (EventArgs e)
  522. {
  523. base.OnFontChanged (e);
  524. ResizeTabPages ();
  525. }
  526. protected override void OnResize (EventArgs e)
  527. {
  528. base.OnResize (e);
  529. }
  530. protected override void OnStyleChanged (EventArgs e)
  531. {
  532. base.OnStyleChanged (e);
  533. }
  534. protected virtual void OnSelectedIndexChanged (EventArgs e)
  535. {
  536. EventHandler eh = (EventHandler) (Events[SelectedIndexChangedEvent]);
  537. if (eh != null)
  538. eh (this, e);
  539. }
  540. internal override void OnPaintInternal (PaintEventArgs pe)
  541. {
  542. Draw (pe.Graphics, pe.ClipRectangle);
  543. pe.Handled = true;
  544. }
  545. #if NET_2_0
  546. protected override void OnEnter (EventArgs e)
  547. {
  548. base.OnEnter (e);
  549. if (SelectedTab != null)
  550. SelectedTab.FireEnter ();
  551. }
  552. protected override void OnLeave (EventArgs e)
  553. {
  554. if (SelectedTab != null)
  555. SelectedTab.FireLeave ();
  556. base.OnLeave (e);
  557. }
  558. [EditorBrowsable (EditorBrowsableState.Advanced)]
  559. protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
  560. {
  561. EventHandler eh = (EventHandler) (Events[RightToLeftLayoutChangedEvent]);
  562. if (eh != null)
  563. eh (this, e);
  564. }
  565. [EditorBrowsable (EditorBrowsableState.Never)]
  566. protected override void ScaleCore (float dx, float dy)
  567. {
  568. base.ScaleCore (dx, dy);
  569. }
  570. protected virtual void OnDeselecting (TabControlCancelEventArgs e)
  571. {
  572. TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[DeselectingEvent]);
  573. if (eh != null)
  574. eh (this, e);
  575. if (!e.Cancel)
  576. OnDeselected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Deselected));
  577. }
  578. protected virtual void OnDeselected (TabControlEventArgs e)
  579. {
  580. TabControlEventHandler eh = (TabControlEventHandler) (Events[DeselectedEvent]);
  581. if (eh != null)
  582. eh (this, e);
  583. if (this.SelectedTab != null)
  584. this.SelectedTab.FireLeave ();
  585. }
  586. protected virtual void OnSelecting (TabControlCancelEventArgs e)
  587. {
  588. TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[SelectingEvent]);
  589. if (eh != null)
  590. eh (this, e);
  591. if (!e.Cancel)
  592. OnSelected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Selected));
  593. }
  594. protected virtual void OnSelected (TabControlEventArgs e)
  595. {
  596. TabControlEventHandler eh = (TabControlEventHandler) (Events[SelectedEvent]);
  597. if (eh != null)
  598. eh (this, e);
  599. if (this.SelectedTab != null)
  600. this.SelectedTab.FireEnter ();
  601. }
  602. #endif
  603. #endregion
  604. #region Keys
  605. protected override bool ProcessKeyPreview (ref Message m)
  606. {
  607. return base.ProcessKeyPreview (ref m);
  608. }
  609. protected override void OnKeyDown (KeyEventArgs e)
  610. {
  611. if (e.KeyCode == Keys.Tab && (e.KeyData & Keys.Control) != 0) {
  612. if ((e.KeyData & Keys.Shift) == 0)
  613. SelectedIndex = (SelectedIndex + 1) % TabCount;
  614. else
  615. SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount;
  616. e.Handled = true;
  617. } else if (e.KeyCode == Keys.Home) {
  618. SelectedIndex = 0;
  619. e.Handled = true;
  620. } else if (e.KeyCode == Keys.End) {
  621. SelectedIndex = TabCount - 1;
  622. e.Handled = true;
  623. } else if (e.KeyCode == Keys.Left && SelectedIndex > 0) {
  624. SelectedIndex--;
  625. e.Handled = true;
  626. } else if (e.KeyCode == Keys.Right && SelectedIndex < TabCount - 1) {
  627. SelectedIndex++;
  628. e.Handled = true;
  629. }
  630. base.OnKeyDown (e);
  631. }
  632. protected override bool IsInputKey (Keys key)
  633. {
  634. switch (key & Keys.KeyCode) {
  635. case Keys.Home:
  636. case Keys.End:
  637. case Keys.Left:
  638. case Keys.Right:
  639. return true;
  640. }
  641. return base.IsInputKey (key);
  642. }
  643. #endregion
  644. #region Pages Collection
  645. protected void RemoveAll ()
  646. {
  647. Controls.Clear ();
  648. }
  649. protected virtual object [] GetItems ()
  650. {
  651. TabPage [] pages = new TabPage [Controls.Count];
  652. Controls.CopyTo (pages, 0);
  653. return pages;
  654. }
  655. protected virtual object [] GetItems (Type type)
  656. {
  657. object [] pages = (object []) Array.CreateInstance (type, Controls.Count);
  658. Controls.CopyTo (pages, 0);
  659. return pages;
  660. }
  661. #endregion
  662. protected void UpdateTabSelection (bool uiselected)
  663. {
  664. ResizeTabPages ();
  665. }
  666. protected string GetToolTipText (object item)
  667. {
  668. TabPage page = (TabPage) item;
  669. return page.ToolTipText;
  670. }
  671. protected override void WndProc (ref Message m)
  672. {
  673. switch ((Msg)m.Msg) {
  674. case Msg.WM_SETFOCUS:
  675. if (selected_index == -1 && this.TabCount > 0)
  676. this.SelectedIndex = 0;
  677. if (selected_index != -1)
  678. Invalidate(GetTabRect(selected_index));
  679. base.WndProc (ref m);
  680. break;
  681. case Msg.WM_KILLFOCUS:
  682. if (selected_index != -1)
  683. Invalidate(GetTabRect(selected_index));
  684. base.WndProc (ref m);
  685. break;
  686. default:
  687. base.WndProc (ref m);
  688. break;
  689. }
  690. }
  691. #endregion // Protected Instance Methods
  692. #region Internal & Private Methods
  693. private bool CanScrollRight {
  694. get {
  695. return (slider_pos < TabCount - 1);
  696. }
  697. }
  698. private bool CanScrollLeft {
  699. get { return slider_pos > 0; }
  700. }
  701. private void MouseDownHandler (object sender, MouseEventArgs e)
  702. {
  703. if (ShowSlider) {
  704. Rectangle right = ThemeEngine.Current.TabControlGetRightScrollRect (this);
  705. Rectangle left = ThemeEngine.Current.TabControlGetLeftScrollRect (this);
  706. if (right.Contains (e.X, e.Y)) {
  707. right_slider_state = ButtonState.Pushed;
  708. if (CanScrollRight) {
  709. slider_pos++;
  710. SizeTabs ();
  711. switch (this.Alignment) {
  712. case TabAlignment.Top:
  713. Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
  714. break;
  715. case TabAlignment.Bottom:
  716. Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
  717. break;
  718. case TabAlignment.Left:
  719. Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
  720. break;
  721. case TabAlignment.Right:
  722. Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
  723. break;
  724. }
  725. } else {
  726. Invalidate (right);
  727. }
  728. return;
  729. } else if (left.Contains (e.X, e.Y)) {
  730. left_slider_state = ButtonState.Pushed;
  731. if (CanScrollLeft) {
  732. slider_pos--;
  733. SizeTabs ();
  734. switch (this.Alignment) {
  735. case TabAlignment.Top:
  736. Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
  737. break;
  738. case TabAlignment.Bottom:
  739. Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
  740. break;
  741. case TabAlignment.Left:
  742. Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
  743. break;
  744. case TabAlignment.Right:
  745. Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
  746. break;
  747. }
  748. } else {
  749. Invalidate (left);
  750. }
  751. return;
  752. }
  753. }
  754. int count = Controls.Count;
  755. for (int i = SliderPos; i < count; i++) {
  756. if (!GetTabRect (i).Contains (e.X, e.Y))
  757. continue;
  758. SelectedIndex = i;
  759. break;
  760. }
  761. }
  762. private void MouseUpHandler (object sender, MouseEventArgs e)
  763. {
  764. if (ShowSlider && (left_slider_state == ButtonState.Pushed || right_slider_state == ButtonState.Pushed)) {
  765. Rectangle invalid;
  766. if (left_slider_state == ButtonState.Pushed)
  767. invalid = ThemeEngine.Current.TabControlGetLeftScrollRect (this);
  768. else
  769. invalid = ThemeEngine.Current.TabControlGetRightScrollRect (this);
  770. left_slider_state = ButtonState.Normal;
  771. right_slider_state = ButtonState.Normal;
  772. Invalidate (invalid);
  773. }
  774. }
  775. private void SizeChangedHandler (object sender, EventArgs e)
  776. {
  777. Redraw ();
  778. }
  779. internal int IndexForTabPage (TabPage page)
  780. {
  781. for (int i = 0; i < tab_pages.Count; i++) {
  782. if (page == tab_pages [i])
  783. return i;
  784. }
  785. return -1;
  786. }
  787. private void ResizeTabPages ()
  788. {
  789. CalcTabRows ();
  790. SizeTabs ();
  791. Rectangle r = DisplayRectangle;
  792. foreach (TabPage page in Controls) {
  793. page.Bounds = r;
  794. }
  795. }
  796. private int MinimumTabWidth {
  797. get {
  798. return ThemeEngine.Current.TabControlMinimumTabWidth;
  799. }
  800. }
  801. private Size TabSpacing {
  802. get {
  803. return ThemeEngine.Current.TabControlGetSpacing (this);
  804. }
  805. }
  806. private void CalcTabRows ()
  807. {
  808. switch (Alignment) {
  809. case TabAlignment.Right:
  810. case TabAlignment.Left:
  811. CalcTabRows (Height);
  812. break;
  813. default:
  814. CalcTabRows (Width);
  815. break;
  816. }
  817. }
  818. private void CalcTabRows (int row_width)
  819. {
  820. int xpos = 0;
  821. int ypos = 0;
  822. Size spacing = TabSpacing;
  823. if (TabPages.Count > 0)
  824. row_count = 1;
  825. show_slider = false;
  826. int scrollerWidth = ThemeEngine.Current.TabControlScrollerWidth * 2;
  827. for (int i = 0; i < TabPages.Count; i++) {
  828. TabPage page = TabPages [i];
  829. int aux = 0;
  830. SizeTab (page, i, row_width - scrollerWidth, ref xpos, ref ypos, spacing, 0, ref aux, true);
  831. }
  832. if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow)
  833. DropRow (TabPages [SelectedIndex].Row);
  834. }
  835. private int BottomRow {
  836. get { return 1; }
  837. }
  838. private int Direction
  839. {
  840. get {
  841. switch (Alignment) {
  842. case TabAlignment.Right:
  843. case TabAlignment.Bottom:
  844. return -1;
  845. default:
  846. return 1;
  847. }
  848. }
  849. }
  850. private void DropRow (int row)
  851. {
  852. if (Appearance != TabAppearance.Normal)
  853. return;
  854. int bottom = BottomRow;
  855. int direction = Direction;
  856. foreach (TabPage page in TabPages) {
  857. if (page.Row == row) {
  858. page.Row = bottom;
  859. } else if (direction == 1 && page.Row < row) {
  860. page.Row += direction;
  861. } else if (direction == -1 && page.Row > row) {
  862. page.Row += direction;
  863. }
  864. }
  865. }
  866. private int CalcYPos ()
  867. {
  868. if (Alignment == TabAlignment.Bottom || Alignment == TabAlignment.Left)
  869. return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom;
  870. if (Appearance == TabAppearance.Normal)
  871. return this.ClientRectangle.Y + ThemeEngine.Current.TabControlSelectedDelta.Y;
  872. return this.ClientRectangle.Y;
  873. }
  874. private int CalcXPos ()
  875. {
  876. if (Alignment == TabAlignment.Right)
  877. return ThemeEngine.Current.TabControlGetPanelRect (this).Right;
  878. if (Appearance == TabAppearance.Normal)
  879. return this.ClientRectangle.X + ThemeEngine.Current.TabControlSelectedDelta.X;
  880. return this.ClientRectangle.X;
  881. }
  882. private void SizeTabs ()
  883. {
  884. switch (Alignment) {
  885. case TabAlignment.Right:
  886. case TabAlignment.Left:
  887. SizeTabs (Height, true);
  888. break;
  889. default:
  890. SizeTabs (Width, false);
  891. break;
  892. }
  893. }
  894. private void SizeTabs (int row_width, bool vertical)
  895. {
  896. int ypos = 0;
  897. int xpos = 0;
  898. int prev_row = 1;
  899. Size spacing = TabSpacing;
  900. int begin_prev = 0;
  901. row_width -= ThemeEngine.Current.TabControlScrollerWidth * 2;
  902. if (TabPages.Count == 0)
  903. return;
  904. prev_row = TabPages [0].Row;
  905. // Reset the slider position if the slider isn't needed
  906. // anymore (ie window size was increased so all tabs are visible)
  907. if (!show_slider)
  908. slider_pos = 0;
  909. else {
  910. // set X = -1 for marking tabs that are not visible due to scrolling
  911. for (int i = 0; i < slider_pos; i++) {
  912. TabPage page = TabPages[i];
  913. Rectangle x = page.TabBounds;
  914. x.X = -1;
  915. page.TabBounds = x;
  916. }
  917. }
  918. for (int i = slider_pos; i < TabPages.Count; i++) {
  919. TabPage page = TabPages[i];
  920. SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false);
  921. prev_row = page.Row;
  922. }
  923. if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
  924. FillRow (begin_prev, TabPages.Count - 1,
  925. ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)),
  926. spacing, vertical);
  927. }
  928. if (SelectedIndex != -1) {
  929. ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
  930. }
  931. }
  932. private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos,
  933. Size spacing, int prev_row, ref int begin_prev, bool widthOnly)
  934. {
  935. int width, height = 0;
  936. if (SizeMode == TabSizeMode.Fixed) {
  937. width = item_size.Width;
  938. } else {
  939. width = MeasureStringWidth (DeviceContext, page.Text, Font);
  940. width += (Padding.X * 2) - 2; // don't know why, but tabpages on ms.net have the right padding smaller :p
  941. if (ImageList != null && page.ImageIndex >= 0 && page.ImageIndex < ImageList.Images.Count) {
  942. width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X;
  943. item_size.Height = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y;
  944. }
  945. }
  946. height = item_size.Height - ThemeEngine.Current.TabControlSelectedDelta.Height; // full height only for selected tab
  947. if (width < MinimumTabWidth)
  948. width = MinimumTabWidth;
  949. if (i == SelectedIndex)
  950. width += ThemeEngine.Current.TabControlSelectedSpacing;
  951. if (widthOnly) {
  952. page.TabBounds = new Rectangle (xpos, 0, width, 0);
  953. page.Row = row_count;
  954. if (xpos + width > row_width && multiline) {
  955. xpos = 0;
  956. row_count++;
  957. } else if (xpos + width > row_width) {
  958. show_slider = true;
  959. }
  960. if (i == selected_index && show_slider) {
  961. for (int j = i-1; j >= 0; j--) {
  962. if (TabPages [j].TabBounds.Left < xpos + width - row_width) {
  963. slider_pos = j+1;
  964. break;
  965. }
  966. }
  967. }
  968. } else {
  969. if (page.Row != prev_row) {
  970. xpos = 0;
  971. }
  972. switch (Alignment) {
  973. case TabAlignment.Top:
  974. page.TabBounds = new Rectangle (
  975. xpos + CalcXPos (),
  976. ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
  977. width,
  978. height);
  979. break;
  980. case TabAlignment.Bottom:
  981. page.TabBounds = new Rectangle (
  982. xpos + CalcXPos (),
  983. ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
  984. width,
  985. height);
  986. break;
  987. case TabAlignment.Left:
  988. if (Appearance == TabAppearance.Normal) {
  989. // tab rows are positioned right to left
  990. page.TabBounds = new Rectangle (
  991. ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
  992. xpos,
  993. height,
  994. width);
  995. } else {
  996. // tab rows are positioned left to right
  997. page.TabBounds = new Rectangle (
  998. ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
  999. xpos,
  1000. height,
  1001. width);
  1002. }
  1003. break;
  1004. case TabAlignment.Right:
  1005. if (Appearance == TabAppearance.Normal) {
  1006. // tab rows are positioned left to right
  1007. page.TabBounds = new Rectangle (
  1008. ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
  1009. xpos,
  1010. height,
  1011. width);
  1012. } else {
  1013. // tab rows are positioned right to left
  1014. page.TabBounds = new Rectangle (
  1015. ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
  1016. xpos,
  1017. height,
  1018. width);
  1019. }
  1020. break;
  1021. }
  1022. if (page.Row != prev_row) {
  1023. if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
  1024. FillRow (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Right) / (i - begin_prev)), spacing);
  1025. }
  1026. begin_prev = i;
  1027. }
  1028. }
  1029. xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing;
  1030. }
  1031. private void FillRow (int start, int end, int amount, Size spacing, bool vertical)
  1032. {
  1033. if (vertical)
  1034. FillRowV (start, end, amount, spacing);
  1035. else
  1036. FillRow (start, end, amount, spacing);
  1037. }
  1038. private void FillRow (int start, int end, int amount, Size spacing)
  1039. {
  1040. int xpos = TabPages [start].TabBounds.Left;
  1041. for (int i = start; i <= end; i++) {
  1042. TabPage page = TabPages [i];
  1043. int left = xpos;
  1044. int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
  1045. page.TabBounds = new Rectangle (left, page.TabBounds.Top,
  1046. width, page.TabBounds.Height);
  1047. xpos = page.TabBounds.Right + 1 + spacing.Width;
  1048. }
  1049. }
  1050. private void FillRowV (int start, int end, int amount, Size spacing)
  1051. {
  1052. int ypos = TabPages [start].TabBounds.Top;
  1053. for (int i = start; i <= end; i++) {
  1054. TabPage page = TabPages [i];
  1055. int top = ypos;
  1056. int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
  1057. page.TabBounds = new Rectangle (page.TabBounds.Left, top,
  1058. page.TabBounds.Width, height);
  1059. ypos = page.TabBounds.Bottom + 1;
  1060. }
  1061. }
  1062. private void ExpandSelected (TabPage page, int left_edge, int right_edge)
  1063. {
  1064. if (Appearance != TabAppearance.Normal)
  1065. return;
  1066. Rectangle r = page.TabBounds;
  1067. switch (Alignment) {
  1068. case TabAlignment.Top:
  1069. case TabAlignment.Left:
  1070. r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
  1071. r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
  1072. break;
  1073. case TabAlignment.Bottom:
  1074. r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
  1075. r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
  1076. break;
  1077. case TabAlignment.Right:
  1078. r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
  1079. r.X += ThemeEngine.Current.TabControlSelectedDelta.X;
  1080. break;
  1081. }
  1082. r.Width += ThemeEngine.Current.TabControlSelectedDelta.Width;
  1083. r.Height += ThemeEngine.Current.TabControlSelectedDelta.Height;
  1084. if (r.Left < left_edge)
  1085. r.X = left_edge;
  1086. if (r.Right > right_edge && SizeMode != TabSizeMode.Normal)
  1087. r.Width = right_edge - r.X;
  1088. page.TabBounds = r;
  1089. }
  1090. private void Draw (Graphics dc, Rectangle clip)
  1091. {
  1092. ThemeEngine.Current.DrawTabControl (dc, clip, this);
  1093. }
  1094. private TabPage GetTab (int index)
  1095. {
  1096. return Controls [index] as TabPage;
  1097. }
  1098. private void SetTab (int index, TabPage value)
  1099. {
  1100. if (!tab_pages.Contains (value)) {
  1101. this.Controls.Add (value);
  1102. }
  1103. this.Controls.RemoveAt (index);
  1104. this.Controls.SetChildIndex (value, index);
  1105. Redraw ();
  1106. }
  1107. #if NET_2_0
  1108. private void InsertTab (int index, TabPage value)
  1109. {
  1110. if (!tab_pages.Contains (value)) {
  1111. this.Controls.Add (value);
  1112. }
  1113. this.Controls.SetChildIndex (value, index);
  1114. Redraw ();
  1115. }
  1116. #endif
  1117. internal void Redraw ()
  1118. {
  1119. if (!IsHandleCreated)
  1120. return;
  1121. ResizeTabPages ();
  1122. Refresh ();
  1123. }
  1124. private int MeasureStringWidth (Graphics graphics, string text, Font font)
  1125. {
  1126. if (text == String.Empty)
  1127. return 0;
  1128. StringFormat format = new StringFormat();
  1129. RectangleF rect = new RectangleF(0, 0, 1000, 1000);
  1130. CharacterRange[] ranges = { new CharacterRange(0, text.Length) };
  1131. Region[] regions = new Region[1];
  1132. format.SetMeasurableCharacterRanges(ranges);
  1133. format.FormatFlags = StringFormatFlags.NoClip;
  1134. format.FormatFlags |= StringFormatFlags.NoWrap;
  1135. regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format);
  1136. rect = regions[0].GetBounds(graphics);
  1137. return (int)(rect.Width);
  1138. }
  1139. #endregion // Internal & Private Methods
  1140. #region Events
  1141. [Browsable(false)]
  1142. [EditorBrowsable(EditorBrowsableState.Never)]
  1143. public new event EventHandler BackColorChanged {
  1144. add { base.BackColorChanged += value; }
  1145. remove { base.BackColorChanged -= value; }
  1146. }
  1147. [Browsable(false)]
  1148. [EditorBrowsable(EditorBrowsableState.Never)]
  1149. public new event EventHandler BackgroundImageChanged {
  1150. add { base.BackgroundImageChanged += value; }
  1151. remove { base.BackgroundImageChanged -= value; }
  1152. }
  1153. #if NET_2_0
  1154. [Browsable (false)]
  1155. [EditorBrowsable (EditorBrowsableState.Never)]
  1156. public new event EventHandler BackgroundImageLayoutChanged
  1157. {
  1158. add { base.BackgroundImageLayoutChanged += value; }
  1159. remove { base.BackgroundImageLayoutChanged -= value; }
  1160. }
  1161. #endif
  1162. [Browsable(false)]
  1163. [EditorBrowsable(EditorBrowsableState.Never)]
  1164. public new event EventHandler ForeColorChanged {
  1165. add { base.ForeColorChanged += value; }
  1166. remove { base.ForeColorChanged -= value; }
  1167. }
  1168. [Browsable(false)]
  1169. [EditorBrowsable(EditorBrowsableState.Never)]
  1170. public new event PaintEventHandler Paint {
  1171. add { base.Paint += value; }
  1172. remove { base.Paint -= value; }
  1173. }
  1174. [Browsable(false)]
  1175. [EditorBrowsable(EditorBrowsableState.Never)]
  1176. public new event EventHandler TextChanged {
  1177. add { base.TextChanged += value; }
  1178. remove { base.TextChanged -= value; }
  1179. }
  1180. static object DrawItemEvent = new object ();
  1181. static object SelectedIndexChangedEvent = new object ();
  1182. public event DrawItemEventHandler DrawItem {
  1183. add { Events.AddHandler (DrawItemEvent, value); }
  1184. remove { Events.RemoveHandler (DrawItemEvent, value); }
  1185. }
  1186. public event EventHandler SelectedIndexChanged {
  1187. add { Events.AddHandler (SelectedIndexChangedEvent, value); }
  1188. remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
  1189. }
  1190. #if NET_2_0
  1191. static object SelectedEvent = new object ();
  1192. public event TabControlEventHandler Selected {
  1193. add { Events.AddHandler (SelectedEvent, value); }
  1194. remove { Events.RemoveHandler (SelectedEvent, value); }
  1195. }
  1196. static object DeselectedEvent = new object ();
  1197. public event TabControlEventHandler Deselected
  1198. {
  1199. add { Events.AddHandler (DeselectedEvent, value); }
  1200. remove { Events.RemoveHandler (DeselectedEvent, value); }
  1201. }
  1202. static object SelectingEvent = new object ();
  1203. public event TabControlCancelEventHandler Selecting
  1204. {
  1205. add { Events.AddHandler (SelectingEvent, value); }
  1206. remove { Events.RemoveHandler (SelectingEvent, value); }
  1207. }
  1208. static object DeselectingEvent = new object ();
  1209. public event TabControlCancelEventHandler Deselecting
  1210. {
  1211. add { Events.AddHandler (DeselectingEvent, value); }
  1212. remove { Events.RemoveHandler (DeselectingEvent, value); }
  1213. }
  1214. static object RightToLeftLayoutChangedEvent = new object ();
  1215. public event EventHandler RightToLeftLayoutChanged
  1216. {
  1217. add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
  1218. remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
  1219. }
  1220. #endif
  1221. #endregion // Events
  1222. #region Class TaControl.ControlCollection
  1223. [ComVisible (false)]
  1224. public new class ControlCollection : System.Windows.Forms.Control.ControlCollection {
  1225. private TabControl owner;
  1226. public ControlCollection (TabControl owner) : base (owner)
  1227. {
  1228. this.owner = owner;
  1229. }
  1230. public override void Add (Control value)
  1231. {
  1232. TabPage page = value as TabPage;
  1233. if (page == null)
  1234. throw new ArgumentException ("Cannot add " +
  1235. value.GetType ().Name + " to TabControl. " +
  1236. "Only TabPages can be directly added to TabControls.");
  1237. page.SetVisible (false);
  1238. base.Add (value);
  1239. if (owner.TabCount == 1 && owner.selected_index < 0)
  1240. owner.SelectedIndex = 0;
  1241. owner.Redraw ();
  1242. }
  1243. public override void Remove (Control value)
  1244. {
  1245. TabPage page = value as TabPage;
  1246. if (page != null) {
  1247. int index = owner.IndexForTabPage (page);
  1248. if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1)
  1249. owner.SelectedIndex--;
  1250. }
  1251. base.Remove (value);
  1252. }
  1253. }
  1254. #endregion // Class TabControl.ControlCollection
  1255. #region Class TabPage.TabPageCollection
  1256. public class TabPageCollection : IList, ICollection, IEnumerable {
  1257. private TabControl owner;
  1258. public TabPageCollection (TabControl owner)
  1259. {
  1260. if (owner == null)
  1261. throw new ArgumentNullException ("Value cannot be null.");
  1262. this.owner = owner;
  1263. }
  1264. [Browsable(false)]
  1265. public int Count {
  1266. get { return owner.Controls.Count; }
  1267. }
  1268. public bool IsReadOnly {
  1269. get { return false; }
  1270. }
  1271. public virtual TabPage this [int index] {
  1272. get {
  1273. return owner.GetTab (index);
  1274. }
  1275. set {
  1276. owner.SetTab (index, value);
  1277. }
  1278. }
  1279. #if NET_2_0
  1280. public virtual TabPage this [string key] {
  1281. get {
  1282. if (string.IsNullOrEmpty (key))
  1283. return null;
  1284. int index = this.IndexOfKey (key);
  1285. if (index < 0 || index >= this.Count)
  1286. return null;
  1287. return this[index];
  1288. }
  1289. }
  1290. #endif
  1291. internal int this[TabPage tabPage] {
  1292. get {
  1293. if (tabPage == null)
  1294. return -1;
  1295. for (int i = 0; i < this.Count; i++)
  1296. if (this[i].Equals (tabPage))
  1297. return i;
  1298. return -1;
  1299. }
  1300. }
  1301. bool ICollection.IsSynchronized {
  1302. get { return false; }
  1303. }
  1304. object ICollection.SyncRoot {
  1305. get { return this; }
  1306. }
  1307. bool IList.IsFixedSize {
  1308. get { return false; }
  1309. }
  1310. object IList.this [int index] {
  1311. get {
  1312. return owner.GetTab (index);
  1313. }
  1314. set {
  1315. owner.SetTab (index, (TabPage) value);
  1316. }
  1317. }
  1318. public void Add (TabPage page)
  1319. {
  1320. if (page == null)
  1321. throw new ArgumentNullException ("Value cannot be null.");
  1322. owner.Controls.Add (page);
  1323. }
  1324. #if NET_2_0
  1325. public void Add (string text)
  1326. {
  1327. TabPage page = new TabPage (text);
  1328. this.Add (page);
  1329. }
  1330. public void Add (string key, string text)
  1331. {
  1332. TabPage page = new TabPage (text);
  1333. page.Name = key;
  1334. this.Add (page);
  1335. }
  1336. public void Add (string key, string text, int imageIndex)
  1337. {
  1338. TabPage page = new TabPage (text);
  1339. page.Name = key;
  1340. page.ImageIndex = imageIndex;
  1341. this.Add (page);
  1342. }
  1343. [MonoTODO("Implement imagekey")]
  1344. public void Add (string key, string text, string imageKey)
  1345. {
  1346. TabPage page = new TabPage (text);
  1347. page.Name = key;
  1348. this.Add (page);
  1349. page.ImageKey = imageKey;
  1350. }
  1351. #endif
  1352. public void AddRange (TabPage [] pages)
  1353. {
  1354. if (pages == null)
  1355. throw new ArgumentNullException ("Value cannot be null.");
  1356. owner.Controls.AddRange (pages);
  1357. }
  1358. public virtual void Clear ()
  1359. {
  1360. owner.Controls.Clear ();
  1361. }
  1362. public bool Contains (TabPage page)
  1363. {
  1364. if (page == null)
  1365. throw new ArgumentNullException ("Value cannot be null.");
  1366. return owner.Controls.Contains (page);
  1367. }
  1368. #if NET_2_0
  1369. public virtual bool ContainsKey (string key)
  1370. {
  1371. int index = this.IndexOfKey (key);
  1372. return (index >= 0 && index < this.Count);
  1373. }
  1374. #endif
  1375. public IEnumerator GetEnumerator ()
  1376. {
  1377. return owner.Controls.GetEnumerator ();
  1378. }
  1379. public int IndexOf (TabPage page)
  1380. {
  1381. return owner.Controls.IndexOf (page);
  1382. }
  1383. #if NET_2_0
  1384. public virtual int IndexOfKey(string key)
  1385. {
  1386. if (string.IsNullOrEmpty (key))
  1387. return -1;
  1388. for (int i = 0; i < this.Count; i++) {
  1389. if (string.Compare (this[i].Name, key, true,
  1390. System.Globalization.CultureInfo.InvariantCulture) == 0) {
  1391. return i;
  1392. }
  1393. }
  1394. return -1;
  1395. }
  1396. #endif
  1397. public void Remove (TabPage page)
  1398. {
  1399. owner.Controls.Remove (page);
  1400. }
  1401. public void RemoveAt (int index)
  1402. {
  1403. owner.Controls.RemoveAt (index);
  1404. }
  1405. #if NET_2_0
  1406. public virtual void RemoveByKey (string key)
  1407. {
  1408. int index = this.IndexOfKey (key);
  1409. if (index >= 0 && index < this.Count)
  1410. this.RemoveAt (index);
  1411. }
  1412. #endif
  1413. void ICollection.CopyTo (Array dest, int index)
  1414. {
  1415. owner.Controls.CopyTo (dest, index);
  1416. }
  1417. int IList.Add (object value)
  1418. {
  1419. TabPage page = value as TabPage;
  1420. if (value == null)
  1421. throw new ArgumentException ("value");
  1422. owner.Controls.Add (page);
  1423. return owner.Controls.IndexOf (page);
  1424. }
  1425. bool IList.Contains (object value)
  1426. {
  1427. TabPage page = value as TabPage;
  1428. if (page == null)
  1429. return false;
  1430. return Contains (page);
  1431. }
  1432. int IList.IndexOf (object value)
  1433. {
  1434. TabPage page = value as TabPage;
  1435. if (page == null)
  1436. return -1;
  1437. return IndexOf ((TabPage) page);
  1438. }
  1439. void IList.Insert (int index, object value)
  1440. {
  1441. throw new NotSupportedException ();
  1442. }
  1443. #if NET_2_0
  1444. public void Insert (int index, string text)
  1445. {
  1446. owner.InsertTab (index, new TabPage (text));
  1447. }
  1448. public void Insert (int index, TabPage page)
  1449. {
  1450. owner.InsertTab (index, page);
  1451. }
  1452. public void Insert (int index, string key, string text)
  1453. {
  1454. TabPage page = new TabPage(text);
  1455. page.Name = key;
  1456. owner.InsertTab (index, page);
  1457. }
  1458. public void Insert (int index, string key, string text, int imageIndex)
  1459. {
  1460. TabPage page = new TabPage(text);
  1461. page.Name = key;
  1462. owner.InsertTab (index, page);
  1463. page.ImageIndex = imageIndex;
  1464. }
  1465. public void Insert (int index, string key, string text, string imageKey)
  1466. {
  1467. TabPage page = new TabPage(text);
  1468. page.Name = key;
  1469. owner.InsertTab (index, page);
  1470. page.ImageKey = imageKey;
  1471. }
  1472. #endif
  1473. void IList.Remove (object value)
  1474. {
  1475. TabPage page = value as TabPage;
  1476. if (page == null)
  1477. return;
  1478. Remove ((TabPage) value);
  1479. }
  1480. }
  1481. #endregion // Class TabPage.TabPageCollection
  1482. }
  1483. }