2 // System.Windows.Forms.TabControl.cs
5 // stubbed out by Jackson Harper (jackson@latitudegeo.com)
6 // Dennis Hayes (dennish@Raytek.com)
7 // implemented by Aleksey Ryabchuk (ryabchuk@yahoo.com)
8 // (C) 2002 Ximian, Inc
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.ComponentModel
;
32 using System
.Collections
;
34 using System
.Runtime
.InteropServices
;
36 namespace System
.Windows
.Forms
{
38 public class TabControl
: Control
{
40 public class ControlCollection
: Control
.ControlCollection
{
42 public ControlCollection ( TabControl owner
): base( owner
){ }
44 public override void Add( Control c
) {
45 if ( !( c
is TabPage
) ) {
46 throw new ArgumentException();
49 if ( owner
.IsHandleCreated
)
50 ((TabControl
) owner
).addPage ( c
, Count
- 1);
53 public override void Clear () {
55 if ( owner
.IsHandleCreated
)
56 ((TabControl
) owner
).removeAllTabs ( );
59 public override void Remove ( Control
value ) {
60 int index
= IndexOf ( value );
61 base.Remove ( value );
62 if ( index
!= -1 && owner
.IsHandleCreated
)
63 ((TabControl
) owner
).removeTab ( value, index
);
67 private int selectedIndex
;
68 private TabAlignment tabAlignment
;
69 private bool multiline
;
70 private TabAppearance appearance
;
71 private TabDrawMode tabDrawMode
;
72 private bool hotTrack
;
73 private Point padding
;
74 private Size itemSize
;
75 private TabSizeMode sizeMode
;
76 private bool showTooltips
;
77 private ImageList imageList
;
80 SubClassWndProc_
= true;
83 tabAlignment
= TabAlignment
.Top
;
84 appearance
= TabAppearance
.Normal
;
85 tabDrawMode
= TabDrawMode
.Normal
;
87 padding
= new Point ( 6, 3 );
88 itemSize
= Size
.Empty
;
89 sizeMode
= TabSizeMode
.Normal
;
93 public TabAlignment Alignment
{
98 if ( !Enum
.IsDefined ( typeof(TabAlignment
), value ) )
99 throw new InvalidEnumArgumentException( "Alignment",
101 typeof(TabAlignment
));
103 if ( tabAlignment
!= value ) {
104 if ( value == TabAlignment
.Right
||
105 value == TabAlignment
.Left
)
108 tabAlignment
= value;
115 public TabAppearance Appearance
{
116 get { return appearance; }
118 if ( !Enum
.IsDefined ( typeof(TabAppearance
), value ) )
119 throw new InvalidEnumArgumentException( "Appearance",
121 typeof(TabAppearance
));
123 if ( appearance
!= value ) {
131 [EditorBrowsable (EditorBrowsableState
.Never
)]
132 public override Color BackColor
{
133 get { return base.BackColor; }
134 set { base.BackColor = value; }
137 [EditorBrowsable (EditorBrowsableState
.Never
)]
138 public override Image BackgroundImage
{
139 get { return base.BackgroundImage; }
140 set { base.BackgroundImage = value;}
143 public override Rectangle DisplayRectangle
{
145 RECT rect
= new RECT( );
146 Rectangle disp
= base.DisplayRectangle
;
148 rect
.left
= disp
.Left
;
150 rect
.right
= disp
.Right
;
151 rect
.bottom
= disp
.Bottom
;
153 Win32
.SendMessage ( Handle
, (int)TabControlMessages
.TCM_ADJUSTRECT
, 0, ref rect
);
155 return new Rectangle ( rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
159 public TabDrawMode DrawMode
{
160 get { return tabDrawMode; }
162 if ( !Enum
.IsDefined ( typeof(TabDrawMode
), value ) )
163 throw new InvalidEnumArgumentException( "DrawMode",
165 typeof(TabDrawMode
));
167 if ( tabDrawMode
!= value ) {
175 [EditorBrowsable (EditorBrowsableState
.Never
)]
176 public override Color ForeColor
{
177 get { return base.ForeColor; }
178 set { base.ForeColor = value; }
181 public bool HotTrack
{
182 get { return hotTrack; }
184 if ( hotTrack
!= value ) {
192 public ImageList ImageList
{
193 get { return imageList; }
195 if ( imageList
!= value ) {
197 if ( IsHandleCreated
)
198 setImageList ( imageList
!= null ? imageList
.Handle
: IntPtr
.Zero
);
204 public Size ItemSize
{
205 get { return itemSize; }
// FIXME: don't know how to get size initially
207 if ( itemSize
!= value ) {
208 if ( value.Width
< 0 || value.Height
< 0 )
209 throw new ArgumentException ( ); // FIXME: message
213 if ( IsHandleCreated
)
219 public bool Multiline
{
220 get { return multiline; }
222 if ( multiline
!= value ) {
225 if ( multiline
== false && ( Alignment
== TabAlignment
.Left
||
226 Alignment
== TabAlignment
.Right
) )
227 tabAlignment
= TabAlignment
.Top
;
234 public Point Padding
{
235 get { return padding; }
237 if ( padding
!= value ) {
238 if ( value.X
< 0 || value.Y
< 0 )
239 throw new ArgumentException (
240 string.Format ( "'{0}' is not a valid value for 'Padding'.", value ) );
244 if ( IsHandleCreated
)
250 public int RowCount
{
254 if ( Multiline
== false )
256 // referencing this property creates handle in ms.swf
257 return Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_GETROWCOUNT
, 0, 0);
261 public int SelectedIndex
{
262 get { return selectedIndex; }
264 if ( selectedIndex
!= value ) {
266 throw new ArgumentException (
267 string.Format( " '{0}' is not a valid value for 'value'. 'value' must be greater than or equal to -1.", value ) );
269 selectedIndex
= value;
271 if ( IsHandleCreated
)
272 selectPage ( selectedIndex
);
277 public TabPage SelectedTab
{
279 if ( SelectedIndex
>= 0 )
280 return TabPages
[ SelectedIndex
];
284 int index
= TabPages
.IndexOf ( value );
286 SelectedIndex
= index
;
290 public bool ShowToolTips
{
291 get { return showTooltips; }
293 if ( showTooltips
!= value ) {
294 showTooltips
= value;
301 public TabSizeMode SizeMode
{
302 get { return sizeMode; }
304 if ( !Enum
.IsDefined ( typeof(TabSizeMode
), value ) )
305 throw new InvalidEnumArgumentException( "SizeMode",
307 typeof(TabSizeMode
));
309 if ( sizeMode
!= value ) {
317 public int TabCount
{
318 get { return Controls.Count; }
321 public TabControl
.TabPageCollection TabPages
{
322 get { return new TabPageCollection ( this ); }
325 [EditorBrowsable (EditorBrowsableState
.Never
)]
326 public override string Text
{
327 get { return base.Text; }
328 set { base.Text = value;}
331 public Rectangle
GetTabRect( int index
) {
332 if ( index
< 0 || index
>= TabCount
)
333 throw new ArgumentOutOfRangeException( "index" );
334 RECT rect
= new RECT();
335 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_GETITEMRECT
, index
, ref rect
);
336 return new Rectangle( rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
340 public override string ToString() {
341 string str
= GetType().FullName
.ToString () + ", TabPages.Count: ";
342 str
+= TabCount
.ToString ( );
343 for ( int i
= 0; i
< TabPages
.Count
; i
++ ) {
345 str
+= ", TabPage[" + i
+ "]: " + TabPages
[i
].ToString ( );
350 public event DrawItemEventHandler DrawItem
;
351 public event EventHandler SelectedIndexChanged
;
354 protected override CreateParams CreateParams
{
356 CreateParams createParams
= base.CreateParams
;
357 createParams
.ClassName
= Win32
.TABCONTROL
;
358 createParams
.Style
= (int) ( WindowStyles
.WS_CHILD
| WindowStyles
.WS_VISIBLE
| WindowStyles
.WS_OVERLAPPED
) |
359 (int) ( TabControlStyles
.TCS_RAGGEDRIGHT
);
362 createParams
.Style
|= (int) TabControlStyles
.TCS_MULTILINE
;
364 if (DrawMode
== TabDrawMode
.OwnerDrawFixed
)
365 createParams
.Style
|= (int) TabControlStyles
.TCS_OWNERDRAWFIXED
;
368 createParams
.Style
|= (int) TabControlStyles
.TCS_HOTTRACK
;
371 createParams
.Style
|= (int) TabControlStyles
.TCS_TOOLTIPS
;
373 switch ( Alignment
) {
374 case TabAlignment
.Bottom
:
375 createParams
.Style
|= (int) TabControlStyles
.TCS_BOTTOM
;
377 case TabAlignment
.Left
:
378 createParams
.Style
|= (int) TabControlStyles
.TCS_VERTICAL
;
380 case TabAlignment
.Right
:
381 createParams
.Style
|= (int) ( TabControlStyles
.TCS_RIGHT
| TabControlStyles
.TCS_VERTICAL
);
385 switch ( Appearance
) {
386 case TabAppearance
.Buttons
:
387 createParams
.Style
|= (int) TabControlStyles
.TCS_BUTTONS
;
389 case TabAppearance
.FlatButtons
:
390 createParams
.Style
|= (int) TabControlStyles
.TCS_FLATBUTTONS
;
392 case TabAppearance
.Normal
:
393 createParams
.Style
|= (int) TabControlStyles
.TCS_TABS
;
397 switch ( SizeMode
) {
398 case TabSizeMode
.Fixed
:
399 createParams
.Style
|= (int) TabControlStyles
.TCS_FIXEDWIDTH
;
401 case TabSizeMode
.FillToRight
:
402 createParams
.Style
|= (int) TabControlStyles
.TCS_RIGHTJUSTIFY
;
410 protected override Size DefaultSize
{
411 get { return new System.Drawing.Size(200, 100); }
414 protected override Control
.ControlCollection
CreateControlsInstance() {
415 return new ControlCollection ( this );
418 protected override void CreateHandle() {
419 initCommonControlsLibrary ( );
424 protected override void Dispose(bool disposing
) { // .NET V1.1 Beta. .needs implmentation
425 base.Dispose(disposing
);
429 protected override bool IsInputKey(Keys keyData
) {
434 protected virtual void OnDrawItem(DrawItemEventArgs e
) {
435 throw new NotImplementedException ();
439 protected override void OnFontChanged(EventArgs e
) {
440 throw new NotImplementedException ();
444 protected override void OnHandleCreated(EventArgs e
) {
445 base.OnHandleCreated ( e
);
449 if ( imageList
!= null )
450 setImageList ( imageList
.Handle
);
454 protected override void OnHandleDestroyed(EventArgs e
) {
455 base.OnHandleDestroyed ( e
);
459 protected override void OnKeyDown(KeyEventArgs ke
) {
460 base.OnKeyDown( ke
);
464 protected override void OnResize(EventArgs e
) {
465 for ( int i
= 0; i
< Controls
.Count
; i
++ )
466 Controls
[ i
].SetBounds ( 0, 0, 0, 0, BoundsSpecified
.None
);
471 protected virtual void OnSelectedIndexChanged(EventArgs e
) {
472 if ( SelectedIndexChanged
!= null )
473 SelectedIndexChanged ( this, e
);
477 protected override void OnStyleChanged(EventArgs e
) {
478 throw new NotImplementedException ();
482 protected override bool ProcessKeyPreview(ref Message m
) {
483 return base.ProcessKeyPreview( ref m
);
486 protected void RemoveAll() {
490 protected override void OnCreateControl () {
491 // create pages as needed
495 protected override void WndProc(ref Message m
) {
496 switch ((Msg
) m
.Msg
) {
498 NMHDR nmhdr
= (NMHDR
)Marshal
.PtrToStructure ( m
.LParam
, typeof ( NMHDR
) );
499 switch ( nmhdr
.code
) {
500 case (int)TabControlNotifications
.TCN_SELCHANGE
:
501 selectedIndex
= Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_GETCURSEL
, 0, 0);
502 updatePage ( selectedIndex
, true );
503 OnSelectedIndexChanged ( EventArgs
.Empty
);
505 case (int)TabControlNotifications
.TCN_SELCHANGING
:
506 m
.Result
= IntPtr
.Zero
;
511 base.WndProc ( ref m
);
516 private void initCommonControlsLibrary ( ) {
517 if ( !RecreatingHandle
) {
518 INITCOMMONCONTROLSEX initEx
= new INITCOMMONCONTROLSEX();
519 initEx
.dwICC
= CommonControlInitFlags
.ICC_TAB_CLASSES
;
520 Win32
.InitCommonControlsEx(initEx
);
524 private void update ( ) {
527 private void updatePage ( int index
, bool doShowOrHide
) {
528 if ( Controls
.Count
!= 0 && index
>=0 && index
< Controls
.Count
) {
529 Control c
= Controls
[ index
];
531 if ( c
.Created
== false )
534 c
.SetBounds ( 0, 0, 0, 0, BoundsSpecified
.None
);
536 showOrHidePages( index
);
540 private void setPages ( ) {
541 for (int i
= 0; i
< Controls
.Count
; i
++ )
542 addPage ( Controls
[i
], i
);
545 private void addPage ( Control page
, int index
) {
546 TabPage tabPage
= page
as TabPage
;
547 if ( tabPage
.isAdded
)
550 TCITEM header
= new TCITEM();
551 header
.mask
= (uint) ( TabControlItemFlags
.TCIF_TEXT
| TabControlItemFlags
.TCIF_IMAGE
);
552 header
.pszText
= tabPage
.Text
;
553 header
.iImage
= tabPage
.ImageIndex
;
555 sendMessageHelper ( TabControlMessages
.TCM_INSERTITEM
, index
, ref header
);
556 tabPage
.isAdded
= true;
558 if ( !RecreatingHandle
&& index
== SelectedIndex
)
559 selectPage ( index
);
562 internal void pageTextChanged ( TabPage page
) {
563 if ( IsHandleCreated
) {
564 int index
= Controls
.IndexOf ( page
);
566 TCITEM header
= new TCITEM();
567 header
.mask
= (uint) TabControlItemFlags
.TCIF_TEXT
;
568 header
.pszText
= page
.Text
;
570 sendMessageHelper ( TabControlMessages
.TCM_SETITEM
, index
, ref header
);
575 internal void pageImageIndexChanged ( TabPage page
) {
576 if ( IsHandleCreated
) {
577 int index
= Controls
.IndexOf ( page
);
579 TCITEM header
= new TCITEM();
580 header
.mask
= (uint) TabControlItemFlags
.TCIF_IMAGE
;
581 header
.iImage
= page
.ImageIndex
;
583 sendMessageHelper ( TabControlMessages
.TCM_SETITEM
, index
, ref header
);
588 private void sendMessageHelper ( TabControlMessages mes
, int index
, ref TCITEM hdr
) {
589 if ( IsHandleCreated
) {
590 IntPtr ptr
= Marshal
.AllocHGlobal ( Marshal
.SizeOf ( hdr
) );
591 Marshal
.StructureToPtr( hdr
, ptr
, false );
592 Win32
.SendMessage ( Handle
, (int)mes
, index
, ptr
.ToInt32() );
593 Marshal
.FreeHGlobal ( ptr
);
597 private void setPadding ( ) {
598 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_SETPADDING
, 0, Win32
.MAKELONG ( Padding
.X
, Padding
.Y
) );
601 private void setItemSize ( ) {
602 if ( ItemSize
!= Size
.Empty
) {
603 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_SETITEMSIZE
, 0, Win32
.MAKELONG ( ItemSize
.Width
, ItemSize
.Height
) );
607 private void selectPage ( int selectedIndex
) {
608 if ( selectedIndex
!= -1 ) {
609 if ( Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_SETCURSEL
, selectedIndex
, 0 ) != -1 )
610 OnSelectedIndexChanged ( EventArgs
.Empty
);
612 updatePage ( selectedIndex
!= -1 ? selectedIndex
: 0 , true );
615 private void removeAllTabs ( ) {
616 for (int i
= 0; i
< Controls
.Count
; i
++ )
617 ( ( TabPage
) Controls
[i
] ).isAdded
= false;
619 if ( IsHandleCreated
)
620 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_DELETEALLITEMS
, 0, 0 );
623 private void removeTab ( Control c
, int index
) {
624 if ( IsHandleCreated
)
625 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_DELETEITEM
, index
, 0 );
626 ( ( TabPage
) c
).isAdded
= false;
629 private void showOrHidePages ( int index
) {
630 for (int i
= 0; i
< Controls
.Count
; i
++ )
631 Controls
[i
].Visible
= ( i
== index
) ? true : false;
634 private void setImageList ( IntPtr handle
)
636 Win32
.SendMessage ( Handle
, (int) TabControlMessages
.TCM_SETIMAGELIST
, 0, handle
.ToInt32 ( ) );
638 int CurrentPage
= SelectedIndex
;
639 updatePage ( CurrentPage
, false );
641 if ( Controls
.Count
!= 0 && CurrentPage
>=0 && CurrentPage
< Controls
.Count
)
642 Controls
[ CurrentPage
].Invalidate ( true );
645 private void recreate ( ) {
648 if ( IsHandleCreated
) {
650 selectPage ( SelectedIndex
);
654 public class TabPageCollection
: IList
, ICollection
, IEnumerable
{
656 Control
.ControlCollection collection
;
658 public TabPageCollection( TabControl owner
) {
660 collection
= owner
.Controls
;
664 get { return collection.Count; }
667 public bool IsReadOnly
{
668 get { return collection.IsReadOnly; }
672 public virtual TabPage
this[int index
] {
673 get { return collection[ index ] as TabPage; }
675 ( (IList
)collection
)[ index
] = value;
680 public void Add(TabPage
value) {
681 collection
.Add ( value );
684 public void AddRange( TabPage
[] pages
) {
685 collection
.AddRange ( pages
);
688 public virtual void Clear() {
689 collection
.Clear ( );
692 public bool Contains( TabPage page
) {
693 return collection
.Contains ( page
);
696 public IEnumerator
GetEnumerator() {
697 return collection
.GetEnumerator ( );
700 public int IndexOf( TabPage page
) {
701 return collection
.IndexOf ( page
);
704 public void Remove( TabPage
value ) {
705 collection
.Remove ( value );
708 public void RemoveAt(int index
) {
709 collection
.RemoveAt ( index
);
713 /// IList Interface implmentation.
715 bool IList
.IsReadOnly
{
716 get{ return this.IsReadOnly; }
719 bool IList
.IsFixedSize
{
720 get{ return (( IList )collection).IsFixedSize; }
723 object IList
.this[int index
]{
724 get{ return collection [ index ]; }
725 set{ if ( ! (value is TabPage
) )
726 throw new ArgumentException ( );
727 this[ index
] = (TabPage
) value;
737 int IList
.Add( object value ) {
738 TabPage page
= value as TabPage
;
740 throw new ArgumentException ( );
742 return this.IndexOf ( page
);
746 bool IList
.Contains( object value ){
747 return this.Contains ( value as TabPage
);
751 int IList
.IndexOf( object value ){
752 return this.IndexOf ( value as TabPage
);
756 void IList
.Insert(int index
, object value){
757 if ( ! (value is TabPage
) )
758 throw new ArgumentException ( );
760 (( IList
)collection
).Insert ( index
, value );
764 void IList
.Remove( object value ){
765 this.Remove ( value as TabPage
);
768 void IList
.RemoveAt( int index
){
769 this.RemoveAt ( index
);
771 // End of IList interface
774 /// ICollection Interface implmentation.
776 int ICollection
.Count
{
777 get{ return this.Count; }
780 bool ICollection
.IsSynchronized
{
781 get{ return ( (ICollection) collection).IsSynchronized; }
784 object ICollection
.SyncRoot
{
785 get{ return ( (ICollection) collection).SyncRoot; }
788 void ICollection
.CopyTo(Array array
, int index
){
789 ( (ICollection
) collection
).CopyTo ( array
, index
);
791 // End Of ICollection