2
0

TabControl.cs 49 KB

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