2 // System.Windows.Forms.ToolBar.cs
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 // Ravindra (rkumar@novell.com)
29 // Copyright (C) Novell, Inc. 2004 (http://www.novell.com)
35 using System.Collections;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
39 using System.Drawing.Imaging;
40 using System.Runtime.InteropServices;
42 namespace System.Windows.Forms
44 [DefaultEvent ("ButtonClick")]
45 [DefaultProperty ("Buttons")]
46 [Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
47 public class ToolBar : Control
49 #region Instance Variables
50 internal ToolBarAppearance appearance;
51 internal bool autosize;
52 internal ToolBarButtonCollection buttons;
53 internal Size buttonSize;
54 internal bool divider;
55 internal bool dropDownArrows;
56 internal ImageList imageList;
57 internal ImeMode imeMode;
58 internal bool showToolTips;
59 internal ToolBarTextAlign textAlignment;
60 internal bool wrappable; // flag to make the toolbar wrappable
61 internal bool redraw; // flag to force redrawing the control
62 private bool size_specified; // flag to know if button size is fixed.
63 internal ToolBarButton currentButton; // the highlighted button
64 #endregion Instance Variables
68 [EditorBrowsable (EditorBrowsableState.Never)]
69 public new event EventHandler BackColorChanged {
70 add { base.BackColorChanged += value; }
71 remove { base.BackColorChanged -= value; }
75 [EditorBrowsable (EditorBrowsableState.Never)]
76 public new event EventHandler BackgroundImageChanged {
77 add { base.BackgroundImageChanged += value; }
78 remove { base.BackgroundImageChanged -= value; }
81 public event ToolBarButtonClickEventHandler ButtonClick;
82 public event ToolBarButtonClickEventHandler ButtonDropDown;
85 [EditorBrowsable (EditorBrowsableState.Never)]
86 public new event EventHandler ForeColorChanged {
87 add { base.ForeColorChanged += value; }
88 remove { base.ForeColorChanged -= value; }
92 [EditorBrowsable (EditorBrowsableState.Never)]
93 public new event EventHandler ImeModeChanged {
94 add { base.ImeModeChanged += value; }
95 remove { base.ImeModeChanged -= value; }
99 [EditorBrowsable (EditorBrowsableState.Never)]
100 public new event PaintEventHandler Paint {
101 add { base.Paint += value; }
102 remove { base.Paint -= value; }
106 [EditorBrowsable (EditorBrowsableState.Never)]
107 public new event EventHandler RightToLeftChanged {
108 add { base.RightToLeftChanged += value; }
109 remove { base.RightToLeftChanged -= value; }
113 [EditorBrowsable (EditorBrowsableState.Never)]
114 public new event EventHandler TextChanged {
115 add { base.TextChanged += value; }
116 remove { base.TextChanged -= value; }
123 appearance = ToolBarAppearance.Normal;
125 background_color = ThemeEngine.Current.DefaultControlBackColor;
126 border_style = BorderStyle.None;
127 buttons = new ToolBarButtonCollection (this);
128 buttonSize = Size.Empty;
130 dropDownArrows = false;
131 foreground_color = ThemeEngine.Current.DefaultControlForeColor;
132 showToolTips = false;
133 textAlignment = ToolBarTextAlign.Underneath;
135 dock_style = DockStyle.Top;
137 size_specified = false;
140 this.MouseDown += new MouseEventHandler (ToolBar_MouseDown);
141 this.MouseLeave += new EventHandler (ToolBar_MouseLeave);
142 this.MouseMove += new MouseEventHandler (ToolBar_MouseMove);
143 this.MouseUp += new MouseEventHandler (ToolBar_MouseUp);
144 Paint += new PaintEventHandler (ToolBar_Paint);
146 SetStyle (ControlStyles.UserPaint, false);
147 SetStyle (ControlStyles.FixedHeight, true);
149 #endregion Constructor
151 #region protected Properties
152 protected override CreateParams CreateParams
154 get { return base.CreateParams; }
157 protected override ImeMode DefaultImeMode {
158 get { return ImeMode.Disable; }
161 protected override Size DefaultSize {
162 get { return ThemeEngine.Current.ToolBarDefaultSize; }
166 #region Public Properties
167 [DefaultValue (ToolBarAppearance.Normal)]
169 public ToolBarAppearance Appearance {
170 get { return appearance; }
172 if (value == appearance)
180 [DefaultValue (true)]
182 public bool AutoSize {
183 get { return autosize; }
185 if (value == autosize)
194 [EditorBrowsable (EditorBrowsableState.Never)]
195 public override Color BackColor {
196 get { return background_color; }
198 if (value == background_color)
201 background_color = value;
202 OnBackColorChanged (EventArgs.Empty);
208 [EditorBrowsable (EditorBrowsableState.Never)]
209 public override Image BackgroundImage {
210 get { return background_image; }
212 if (value == background_image)
215 background_image = value;
216 OnBackgroundImageChanged (EventArgs.Empty);
221 [DefaultValue (BorderStyle.None)]
222 [DispIdAttribute (-504)]
223 public BorderStyle BorderStyle {
224 get { return InternalBorderStyle; }
225 set { InternalBorderStyle = value; }
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
230 [MergableProperty (false)]
231 public ToolBarButtonCollection Buttons {
232 get { return buttons; }
236 [RefreshProperties (RefreshProperties.All)]
237 public Size ButtonSize {
239 if (buttonSize.IsEmpty) {
240 if (buttons.Count == 0)
241 return new Size (39, 36);
243 return CalcButtonSize ();
248 if (buttonSize.Width == value.Width && buttonSize.Height == value.Height)
252 size_specified = true;
257 [DefaultValue (true)]
258 public bool Divider {
259 get { return divider; }
261 if (value == divider)
269 [DefaultValue (DockStyle.Top)]
271 public override DockStyle Dock {
272 get { return base.Dock; }
273 set { base.Dock = value; }
276 [DefaultValue (false)]
278 public bool DropDownArrows {
279 get { return dropDownArrows; }
281 if (value == dropDownArrows)
284 dropDownArrows = value;
290 [EditorBrowsable (EditorBrowsableState.Never)]
291 public override Color ForeColor {
292 get { return foreground_color; }
294 if (value == foreground_color)
297 foreground_color = value;
298 OnForeColorChanged (EventArgs.Empty);
303 [DefaultValue (null)]
304 public ImageList ImageList {
305 get { return imageList; }
306 set { imageList = value; }
310 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
311 [EditorBrowsable (EditorBrowsableState.Advanced)]
312 public Size ImageSize {
314 if (imageList == null)
317 return imageList.ImageSize;
322 [EditorBrowsable (EditorBrowsableState.Never)]
323 public new ImeMode ImeMode {
324 get { return imeMode; }
326 if (value == imeMode)
330 OnImeModeChanged (EventArgs.Empty);
335 [EditorBrowsable (EditorBrowsableState.Never)]
336 public override RightToLeft RightToLeft {
337 get { return base.RightToLeft; }
339 if (value == base.RightToLeft)
342 base.RightToLeft = value;
343 OnRightToLeftChanged (EventArgs.Empty);
347 [DefaultValue (false)]
349 public bool ShowToolTips {
350 get { return showToolTips; }
351 set { showToolTips = value; }
354 [DefaultValue (false)]
355 public new bool TabStop {
356 get { return base.TabStop; }
357 set { base.TabStop = value; }
362 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
363 [EditorBrowsable (EditorBrowsableState.Never)]
364 public override string Text {
372 OnTextChanged (EventArgs.Empty);
376 [DefaultValue (ToolBarTextAlign.Underneath)]
378 public ToolBarTextAlign TextAlign {
379 get { return textAlignment; }
381 if (value == textAlignment)
384 textAlignment = value;
389 [DefaultValue (true)]
391 public bool Wrappable {
392 get { return wrappable; }
394 if (value == wrappable)
401 #endregion Public Properties
403 #region Public Methods
404 public override string ToString ()
406 int count = this.Buttons.Count;
409 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
411 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
412 count, this.Buttons [0].ToString ());
414 #endregion Public Methods
416 #region Internal Methods
417 internal Rectangle GetChildBounds (ToolBarButton button)
419 if (button.Style == ToolBarButtonStyle.Separator)
420 return new Rectangle (button.Location.X, button.Location.Y,
421 ThemeEngine.Current.ToolBarSeparatorWidth, this.ButtonSize.Height);
424 return new Rectangle (button.Location, this.ButtonSize);
426 SizeF sz = this.DeviceContext.MeasureString (button.Text, this.Font);
427 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
429 if (imageList != null) {
430 // adjustment for the image grip
431 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
432 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
434 if (textAlignment == ToolBarTextAlign.Right) {
435 size.Width = imgWidth + size.Width;
436 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
439 size.Height = imgHeight + size.Height;
440 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
443 if (button.Style == ToolBarButtonStyle.DropDownButton && this.dropDownArrows)
444 size.Width += ThemeEngine.Current.ToolBarDropDownWidth;
446 return new Rectangle (button.Location, size);
448 #endregion Internal Methods
450 #region Protected Methods
451 protected override void CreateHandle ()
453 base.CreateHandle ();
456 protected override void Dispose (bool disposing)
461 base.Dispose (disposing);
464 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
466 if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
467 if (! e.Button.Pushed)
468 e.Button.Pushed = true;
470 e.Button.Pushed = false;
472 e.Button.pressed = false;
474 Invalidate (e.Button.Rectangle);
477 if (ButtonClick != null)
478 ButtonClick (this, e);
483 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e)
485 // Reset the flag set on DropDown
486 e.Button.dd_pressed = false;
488 if (ButtonDropDown != null)
489 ButtonDropDown (this, e);
491 if (e.Button.DropDownMenu == null)
494 Point loc = new Point (e.Button.Location.X + 1,
495 e.Button.Rectangle.Bottom + 2);
496 ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
499 protected override void OnFontChanged (EventArgs e)
501 base.OnFontChanged (e);
505 protected override void OnHandleCreated (EventArgs e)
507 base.OnHandleCreated (e);
510 protected override void OnResize (EventArgs e)
514 if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
520 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
522 base.SetBoundsCore (x, y, width, height, specified);
525 protected override void WndProc (ref Message m)
527 base.WndProc (ref m);
530 #endregion Protected Methods
532 #region Private Methods
533 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
535 if (! this.Enabled) return;
537 Point hit = new Point (me.X, me.Y);
540 // draw the pushed button
541 foreach (ToolBarButton button in buttons) {
542 if (button.Enabled && button.Rectangle.Contains (hit)) {
543 // Mark the DropDown rect as pressed.
544 // We don't redraw the dropdown rect.
545 if (button.Style == ToolBarButtonStyle.DropDownButton) {
546 Rectangle ddRect = Rectangle.Empty;
547 Rectangle rect = button.Rectangle;
548 ddRect.Height = rect.Height;
549 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
550 ddRect.X = rect.X + rect.Width - ddRect.Width;
552 if (ddRect.Contains (hit)) {
553 button.dd_pressed = true;
557 // If it is not dropdown then we treat it as a normal
559 button.pressed = true;
560 button.inside = true;
561 Invalidate (button.Rectangle);
568 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
570 if (! this.Enabled) return;
572 Point hit = new Point (me.X, me.Y);
573 this.Capture = false;
575 // draw the normal button
576 foreach (ToolBarButton button in buttons) {
577 if (button.Enabled && button.Rectangle.Contains (hit)) {
578 if (button.Style == ToolBarButtonStyle.DropDownButton) {
579 Rectangle ddRect = Rectangle.Empty;
580 Rectangle rect = button.Rectangle;
581 ddRect.Height = rect.Height;
582 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
583 ddRect.X = rect.X + rect.Width - ddRect.Width;
585 // Fire a ButtonDropDown event
586 if (ddRect.Contains (hit)) {
587 if (button.dd_pressed)
588 this.OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
592 // Fire a ButtonClick
594 this.OnButtonClick (new ToolBarButtonClickEventArgs (button));
596 // Clear the button press flags, if any
597 else if (button.pressed) {
598 button.pressed = false;
599 Invalidate (button.Rectangle);
605 private void ToolBar_MouseLeave (object sender, EventArgs e)
607 if (! this.Enabled || appearance != ToolBarAppearance.Flat) return;
609 if (currentButton != null && currentButton.Hilight) {
610 currentButton.Hilight = false;
611 Invalidate (currentButton.Rectangle);
614 currentButton = null;
617 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
619 if (! this.Enabled) return;
621 Point hit = new Point (me.X, me.Y);
624 // If the button was pressed and we leave, release the
625 // button press and vice versa
626 foreach (ToolBarButton button in buttons) {
627 if (button.pressed &&
628 (button.inside != button.Rectangle.Contains (hit))) {
629 button.inside = button.Rectangle.Contains (hit);
630 button.Hilight = false;
631 Invalidate (button.Rectangle);
637 // following is only for flat style toolbar
638 else if (appearance == ToolBarAppearance.Flat) {
639 if (currentButton != null && currentButton.Rectangle.Contains (hit)) {
640 if (currentButton.Hilight || currentButton.Pushed)
642 currentButton.Hilight = true;
643 Invalidate (currentButton.Rectangle);
647 foreach (ToolBarButton button in buttons) {
648 if (button.Rectangle.Contains (hit) && button.Enabled) {
649 currentButton = button;
650 if (currentButton.Hilight || currentButton.Pushed)
652 currentButton.Hilight = true;
653 Invalidate (currentButton.Rectangle);
656 else if (button.Hilight) {
657 button.Hilight = false;
658 Invalidate (button.Rectangle);
666 private void ToolBar_Paint (object sender, PaintEventArgs pevent)
668 ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
671 internal void Redraw (bool recalculate)
673 // if (recalculate) {
681 private Size CalcButtonSize ()
683 String longestText = buttons [0].Text;
684 for (int i = 1; i < buttons.Count; i++) {
685 if (buttons[i].Text.Length > longestText.Length)
686 longestText = buttons[i].Text;
689 SizeF sz = this.DeviceContext.MeasureString (longestText, this.Font);
690 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
692 if (imageList != null) {
693 // adjustment for the image grip
694 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
695 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
697 if (textAlignment == ToolBarTextAlign.Right) {
698 size.Width = imgWidth + size.Width;
699 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
702 size.Height = imgHeight + size.Height;
703 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
709 /* Checks for the separators and sets the location of a button and its wrapper flag */
710 private void CalcToolBar ()
712 int wd = this.Width; // the amount of space we have for rest of the buttons
713 int ht = this.ButtonSize.Height; // all buttons are displayed with the same height
714 Point loc; // the location to place the next button, leave the space for border
715 loc = new Point (ThemeEngine.Current.ToolBarGripWidth, ThemeEngine.Current.ToolBarGripWidth);
717 // clear all the wrappers if toolbar is not wrappable
718 if (! wrappable && ! autosize) {
719 if (this.Height != this.DefaultSize.Height)
720 this.Height = this.DefaultSize.Height;
721 foreach (ToolBarButton button in buttons) {
722 button.Location = loc;
723 button.Wrapper = false;
724 loc.X = loc.X + button.Rectangle.Width;
727 else if (! wrappable) { // autosizeable
728 if (ht != this.Height)
730 foreach (ToolBarButton button in buttons) {
731 button.Location = loc;
732 button.Wrapper = false;
733 loc.X = loc.X + button.Rectangle.Width;
737 bool seenSeparator = false;
738 int separatorIndex = -1;
739 ToolBarButton button;
741 for (int i = 0; i < buttons.Count; i++) {
742 button = buttons [i];
743 if (button.Visible) {
744 if (button.Style == ToolBarButtonStyle.Separator) {
745 wd -= ThemeEngine.Current.ToolBarSeparatorWidth;
747 button.Wrapper = false; // clear the old flag in case it was set
748 button.Location = loc;
749 loc.X = loc.X + ThemeEngine.Current.ToolBarSeparatorWidth;
752 button.Wrapper = true;
753 button.Location = loc;
754 loc.X = ThemeEngine.Current.ToolBarGripWidth;
756 // we need space to draw horizontal separator
757 loc.Y = loc.Y + ThemeEngine.Current.ToolBarSeparatorWidth + ht;
759 seenSeparator = true;
763 Rectangle rect = button.Rectangle;
766 button.Wrapper = false;
767 button.Location = loc;
768 loc.X = loc.X + rect.Width;
770 else if (seenSeparator) {
771 // wrap at the separator and reassign the locations
772 i = separatorIndex; // for loop is going to increment it
773 buttons [separatorIndex].Wrapper = true;
774 seenSeparator = false;
776 loc.X = ThemeEngine.Current.ToolBarGripWidth;
777 // we need space to draw horizontal separator
778 loc.Y = loc.Y + ht + ThemeEngine.Current.ToolBarSeparatorWidth;
783 button.Wrapper = true;
787 button.Location = loc;
788 loc.X = loc.X + rect.Width;
792 else // don't consider invisible buttons
795 /* adjust the control height, if we are autosizeable */
796 if (autosize) // wrappable
797 if (this.Height != (loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth))
798 this.Height = loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth;
802 private void DumpToolBar (string msg)
804 Console.WriteLine (msg);
805 Console.WriteLine ("ToolBar: name: " + this.Text);
806 Console.WriteLine ("ToolBar: wd, ht: " + this.Size);
807 Console.WriteLine ("ToolBar: img size: " + this.ImageSize);
808 Console.WriteLine ("ToolBar: button sz: " + this.buttonSize);
809 Console.WriteLine ("ToolBar: textalignment: "+ this.TextAlign);
810 Console.WriteLine ("ToolBar: appearance: "+ this.Appearance);
811 Console.WriteLine ("ToolBar: wrappable: "+ this.Wrappable);
812 Console.WriteLine ("ToolBar: buttons count: " + this.Buttons.Count);
815 foreach (ToolBarButton b in buttons) {
816 Console.WriteLine ("ToolBar: button [{0}]:",i++);
820 #endregion Private Methods
823 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
825 #region instance variables
826 private ArrayList buttonsList;
827 private ToolBar owner;
831 public ToolBarButtonCollection (ToolBar owner)
834 this.buttonsList = new ArrayList ();
840 public virtual int Count {
841 get { return buttonsList.Count; }
844 public virtual bool IsReadOnly {
845 get { return buttonsList.IsReadOnly; }
848 public virtual ToolBarButton this [int index] {
849 get { return (ToolBarButton) buttonsList [index]; }
851 value.SetParent (owner);
852 buttonsList [index] = value;
857 bool ICollection.IsSynchronized {
858 get { return buttonsList.IsSynchronized; }
861 object ICollection.SyncRoot {
862 get { return buttonsList.SyncRoot; }
865 bool IList.IsFixedSize {
866 get { return buttonsList.IsFixedSize; }
869 object IList.this [int index] {
870 get { return this [index]; }
872 if (! (value is ToolBarButton))
873 throw new ArgumentException("Not of type ToolBarButton", "value");
874 this [index] = (ToolBarButton) value;
880 public int Add (string text)
882 ToolBarButton button = new ToolBarButton (text);
883 return this.Add (button);
886 public int Add (ToolBarButton button)
889 button.SetParent (owner);
890 result = buttonsList.Add (button);
895 public void AddRange (ToolBarButton [] buttons)
897 foreach (ToolBarButton button in buttons)
901 public virtual void Clear ()
903 buttonsList.Clear ();
904 owner.Redraw (false);
907 public bool Contains (ToolBarButton button)
909 return buttonsList.Contains (button);
912 public virtual IEnumerator GetEnumerator ()
914 return buttonsList.GetEnumerator ();
917 void ICollection.CopyTo (Array dest, int index)
919 buttonsList.CopyTo (dest, index);
922 int IList.Add (object button)
924 if (! (button is ToolBarButton)) {
925 throw new ArgumentException("Not of type ToolBarButton", "button");
928 return this.Add ((ToolBarButton) button);
931 bool IList.Contains (object button)
933 if (! (button is ToolBarButton)) {
934 throw new ArgumentException("Not of type ToolBarButton", "button");
937 return this.Contains ((ToolBarButton) button);
940 int IList.IndexOf (object button)
942 if (! (button is ToolBarButton)) {
943 throw new ArgumentException("Not of type ToolBarButton", "button");
946 return this.IndexOf ((ToolBarButton) button);
949 void IList.Insert (int index, object button)
951 if (! (button is ToolBarButton)) {
952 throw new ArgumentException("Not of type ToolBarButton", "button");
955 this.Insert (index, (ToolBarButton) button);
958 void IList.Remove (object button)
960 if (! (button is ToolBarButton)) {
961 throw new ArgumentException("Not of type ToolBarButton", "button");
964 this.Remove ((ToolBarButton) button);
967 public int IndexOf (ToolBarButton button)
969 return buttonsList.IndexOf (button);
972 public void Insert (int index, ToolBarButton button)
974 buttonsList.Insert (index, button);
978 public void Remove (ToolBarButton button)
980 buttonsList.Remove (button);
984 public virtual void RemoveAt (int index)
986 buttonsList.RemoveAt (index);