PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListBox.cs

https://bitbucket.org/danipen/mono
C# | 3092 lines | 2419 code | 572 blank | 101 comment | 524 complexity | 89d4a7795a64d5596c09e313e938b5e8 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  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-2006 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jordi Mas i Hernandez, jordi@ximian.com
  24. // Mike Kestner <mkestner@novell.com>
  25. //
  26. // COMPLETE
  27. using System;
  28. using System.Drawing;
  29. using System.Collections;
  30. using System.ComponentModel;
  31. using System.ComponentModel.Design;
  32. using System.ComponentModel.Design.Serialization;
  33. using System.Globalization;
  34. using System.Reflection;
  35. using System.Runtime.InteropServices;
  36. using System.Collections.Generic;
  37. namespace System.Windows.Forms
  38. {
  39. [DefaultProperty("Items")]
  40. [DefaultEvent("SelectedIndexChanged")]
  41. [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  42. [DefaultBindingProperty ("SelectedValue")]
  43. [ClassInterface (ClassInterfaceType.AutoDispatch)]
  44. [ComVisible (true)]
  45. public class ListBox : ListControl
  46. {
  47. public const int DefaultItemHeight = 13;
  48. public const int NoMatches = -1;
  49. internal enum ItemNavigation
  50. {
  51. First,
  52. Last,
  53. Next,
  54. Previous,
  55. NextPage,
  56. PreviousPage,
  57. PreviousColumn,
  58. NextColumn
  59. }
  60. Hashtable item_heights;
  61. private int item_height = -1;
  62. private int column_width = 0;
  63. private int requested_height;
  64. private DrawMode draw_mode = DrawMode.Normal;
  65. private int horizontal_extent = 0;
  66. private bool horizontal_scrollbar = false;
  67. private bool integral_height = true;
  68. private bool multicolumn = false;
  69. private bool scroll_always_visible = false;
  70. private SelectedIndexCollection selected_indices;
  71. private SelectedObjectCollection selected_items;
  72. private SelectionMode selection_mode = SelectionMode.One;
  73. private bool sorted = false;
  74. private bool use_tabstops = true;
  75. private int column_width_internal = 120;
  76. private ImplicitVScrollBar vscrollbar;
  77. private ImplicitHScrollBar hscrollbar;
  78. private int hbar_offset;
  79. private bool suspend_layout;
  80. private bool ctrl_pressed = false;
  81. private bool shift_pressed = false;
  82. private bool explicit_item_height = false;
  83. private int top_index = 0;
  84. private int last_visible_index = 0;
  85. private Rectangle items_area;
  86. private int focused_item = -1;
  87. private ObjectCollection items;
  88. private IntegerCollection custom_tab_offsets;
  89. private Padding padding;
  90. private bool use_custom_tab_offsets;
  91. public ListBox ()
  92. {
  93. items = CreateItemCollection ();
  94. selected_indices = new SelectedIndexCollection (this);
  95. selected_items = new SelectedObjectCollection (this);
  96. requested_height = bounds.Height;
  97. InternalBorderStyle = BorderStyle.Fixed3D;
  98. BackColor = ThemeEngine.Current.ColorWindow;
  99. /* Vertical scrollbar */
  100. vscrollbar = new ImplicitVScrollBar ();
  101. vscrollbar.Minimum = 0;
  102. vscrollbar.SmallChange = 1;
  103. vscrollbar.LargeChange = 1;
  104. vscrollbar.Maximum = 0;
  105. vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
  106. vscrollbar.Visible = false;
  107. /* Horizontal scrollbar */
  108. hscrollbar = new ImplicitHScrollBar ();
  109. hscrollbar.Minimum = 0;
  110. hscrollbar.SmallChange = 1;
  111. hscrollbar.LargeChange = 1;
  112. hscrollbar.Maximum = 0;
  113. hscrollbar.Visible = false;
  114. hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
  115. Controls.AddImplicit (vscrollbar);
  116. Controls.AddImplicit (hscrollbar);
  117. /* Events */
  118. MouseDown += new MouseEventHandler (OnMouseDownLB);
  119. MouseMove += new MouseEventHandler (OnMouseMoveLB);
  120. MouseUp += new MouseEventHandler (OnMouseUpLB);
  121. MouseWheel += new MouseEventHandler (OnMouseWheelLB);
  122. KeyUp += new KeyEventHandler (OnKeyUpLB);
  123. GotFocus += new EventHandler (OnGotFocus);
  124. LostFocus += new EventHandler (OnLostFocus);
  125. SetStyle (ControlStyles.UserPaint, false);
  126. custom_tab_offsets = new IntegerCollection (this);
  127. }
  128. #region Events
  129. static object DrawItemEvent = new object ();
  130. static object MeasureItemEvent = new object ();
  131. static object SelectedIndexChangedEvent = new object ();
  132. [Browsable (false)]
  133. [EditorBrowsable (EditorBrowsableState.Never)]
  134. public new event EventHandler BackgroundImageChanged {
  135. add { base.BackgroundImageChanged += value; }
  136. remove { base.BackgroundImageChanged -= value; }
  137. }
  138. [Browsable (false)]
  139. [EditorBrowsable (EditorBrowsableState.Never)]
  140. public new event EventHandler BackgroundImageLayoutChanged {
  141. add { base.BackgroundImageLayoutChanged += value; }
  142. remove { base.BackgroundImageLayoutChanged -= value; }
  143. }
  144. [Browsable (true)]
  145. [EditorBrowsable (EditorBrowsableState.Always)]
  146. public new event EventHandler Click {
  147. add { base.Click += value; }
  148. remove { base.Click -= value; }
  149. }
  150. public event DrawItemEventHandler DrawItem {
  151. add { Events.AddHandler (DrawItemEvent, value); }
  152. remove { Events.RemoveHandler (DrawItemEvent, value); }
  153. }
  154. public event MeasureItemEventHandler MeasureItem {
  155. add { Events.AddHandler (MeasureItemEvent, value); }
  156. remove { Events.RemoveHandler (MeasureItemEvent, value); }
  157. }
  158. [Browsable (true)]
  159. [EditorBrowsable (EditorBrowsableState.Always)]
  160. public new event MouseEventHandler MouseClick {
  161. add { base.MouseClick += value; }
  162. remove { base.MouseClick -= value; }
  163. }
  164. [Browsable (false)]
  165. [EditorBrowsable (EditorBrowsableState.Never)]
  166. public new event EventHandler PaddingChanged {
  167. add { base.PaddingChanged += value; }
  168. remove { base.PaddingChanged -= value; }
  169. }
  170. [Browsable (false)]
  171. [EditorBrowsable (EditorBrowsableState.Never)]
  172. public new event PaintEventHandler Paint {
  173. add { base.Paint += value; }
  174. remove { base.Paint -= value; }
  175. }
  176. public event EventHandler SelectedIndexChanged {
  177. add { Events.AddHandler (SelectedIndexChangedEvent, value); }
  178. remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
  179. }
  180. [Browsable (false)]
  181. [EditorBrowsable (EditorBrowsableState.Advanced)]
  182. public new event EventHandler TextChanged {
  183. add { base.TextChanged += value; }
  184. remove { base.TextChanged -= value; }
  185. }
  186. #endregion // Events
  187. #region UIA Framework Events
  188. //NOTE:
  189. // We are using Reflection to add/remove internal events.
  190. // Class ListProvider uses the events.
  191. //
  192. //Event used to generate UIA Selection Pattern
  193. static object UIASelectionModeChangedEvent = new object ();
  194. internal event EventHandler UIASelectionModeChanged {
  195. add { Events.AddHandler (UIASelectionModeChangedEvent, value); }
  196. remove { Events.RemoveHandler (UIASelectionModeChangedEvent, value); }
  197. }
  198. internal void OnUIASelectionModeChangedEvent ()
  199. {
  200. EventHandler eh = (EventHandler) Events [UIASelectionModeChangedEvent];
  201. if (eh != null)
  202. eh (this, EventArgs.Empty);
  203. }
  204. static object UIAFocusedItemChangedEvent = new object ();
  205. internal event EventHandler UIAFocusedItemChanged {
  206. add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
  207. remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
  208. }
  209. internal void OnUIAFocusedItemChangedEvent ()
  210. {
  211. EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
  212. if (eh != null)
  213. eh (this, EventArgs.Empty);
  214. }
  215. #endregion UIA Framework Events
  216. #region Public Properties
  217. public override Color BackColor {
  218. get { return base.BackColor; }
  219. set {
  220. if (base.BackColor == value)
  221. return;
  222. base.BackColor = value;
  223. base.Refresh (); // Careful. Calling the base method is not the same that calling
  224. } // the overriden one that refresh also all the items
  225. }
  226. [Browsable (false)]
  227. [EditorBrowsable (EditorBrowsableState.Never)]
  228. public override Image BackgroundImage {
  229. get { return base.BackgroundImage; }
  230. set {
  231. base.BackgroundImage = value;
  232. base.Refresh ();
  233. }
  234. }
  235. [Browsable (false)]
  236. [EditorBrowsable (EditorBrowsableState.Never)]
  237. public override ImageLayout BackgroundImageLayout {
  238. get { return base.BackgroundImageLayout; }
  239. set { base.BackgroundImageLayout = value; }
  240. }
  241. [DefaultValue (BorderStyle.Fixed3D)]
  242. [DispId(-504)]
  243. public BorderStyle BorderStyle {
  244. get { return InternalBorderStyle; }
  245. set {
  246. InternalBorderStyle = value;
  247. UpdateListBoxBounds ();
  248. }
  249. }
  250. [DefaultValue (0)]
  251. [Localizable (true)]
  252. public int ColumnWidth {
  253. get { return column_width; }
  254. set {
  255. if (value < 0)
  256. throw new ArgumentException ("A value less than zero is assigned to the property.");
  257. column_width = value;
  258. if (value == 0)
  259. ColumnWidthInternal = 120;
  260. else
  261. ColumnWidthInternal = value;
  262. base.Refresh ();
  263. }
  264. }
  265. protected override CreateParams CreateParams {
  266. get { return base.CreateParams;}
  267. }
  268. [Browsable (false)]
  269. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  270. public IntegerCollection CustomTabOffsets {
  271. get { return custom_tab_offsets; }
  272. }
  273. protected override Size DefaultSize {
  274. get { return new Size (120, 96); }
  275. }
  276. [RefreshProperties(RefreshProperties.Repaint)]
  277. [DefaultValue (DrawMode.Normal)]
  278. public virtual DrawMode DrawMode {
  279. get { return draw_mode; }
  280. set {
  281. if (!Enum.IsDefined (typeof (DrawMode), value))
  282. throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
  283. if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
  284. throw new ArgumentException ("Cannot have variable height and multicolumn");
  285. if (draw_mode == value)
  286. return;
  287. draw_mode = value;
  288. if (draw_mode == DrawMode.OwnerDrawVariable)
  289. item_heights = new Hashtable ();
  290. else
  291. item_heights = null;
  292. if (Parent != null)
  293. Parent.PerformLayout (this, "DrawMode");
  294. base.Refresh ();
  295. }
  296. }
  297. public override Font Font {
  298. get { return base.Font; }
  299. set { base.Font = value; }
  300. }
  301. public override Color ForeColor {
  302. get { return base.ForeColor; }
  303. set {
  304. if (base.ForeColor == value)
  305. return;
  306. base.ForeColor = value;
  307. base.Refresh ();
  308. }
  309. }
  310. [DefaultValue (0)]
  311. [Localizable (true)]
  312. public int HorizontalExtent {
  313. get { return horizontal_extent; }
  314. set {
  315. if (horizontal_extent == value)
  316. return;
  317. horizontal_extent = value;
  318. base.Refresh ();
  319. }
  320. }
  321. [DefaultValue (false)]
  322. [Localizable (true)]
  323. public bool HorizontalScrollbar {
  324. get { return horizontal_scrollbar; }
  325. set {
  326. if (horizontal_scrollbar == value)
  327. return;
  328. horizontal_scrollbar = value;
  329. UpdateScrollBars ();
  330. base.Refresh ();
  331. }
  332. }
  333. [DefaultValue (true)]
  334. [Localizable (true)]
  335. [RefreshProperties(RefreshProperties.Repaint)]
  336. public bool IntegralHeight {
  337. get { return integral_height; }
  338. set {
  339. if (integral_height == value)
  340. return;
  341. integral_height = value;
  342. UpdateListBoxBounds ();
  343. }
  344. }
  345. [DefaultValue (13)]
  346. [Localizable (true)]
  347. [RefreshProperties(RefreshProperties.Repaint)]
  348. public virtual int ItemHeight {
  349. get {
  350. if (item_height == -1) {
  351. SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
  352. item_height = (int) sz.Height;
  353. }
  354. return item_height;
  355. }
  356. set {
  357. if (value > 255)
  358. throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
  359. explicit_item_height = true;
  360. if (item_height == value)
  361. return;
  362. item_height = value;
  363. if (IntegralHeight)
  364. UpdateListBoxBounds ();
  365. LayoutListBox ();
  366. }
  367. }
  368. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  369. [Localizable (true)]
  370. [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
  371. [MergableProperty (false)]
  372. public ObjectCollection Items {
  373. get { return items; }
  374. }
  375. [DefaultValue (false)]
  376. public bool MultiColumn {
  377. get { return multicolumn; }
  378. set {
  379. if (multicolumn == value)
  380. return;
  381. if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
  382. throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
  383. multicolumn = value;
  384. LayoutListBox ();
  385. Invalidate ();
  386. }
  387. }
  388. [Browsable (false)]
  389. [EditorBrowsable (EditorBrowsableState.Never)]
  390. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  391. public new Padding Padding {
  392. get { return padding; }
  393. set { padding = value; }
  394. }
  395. [Browsable (false)]
  396. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  397. [EditorBrowsable (EditorBrowsableState.Advanced)]
  398. public int PreferredHeight {
  399. get {
  400. int itemsHeight = 0;
  401. if (draw_mode == DrawMode.Normal)
  402. itemsHeight = FontHeight * items.Count;
  403. else if (draw_mode == DrawMode.OwnerDrawFixed)
  404. itemsHeight = ItemHeight * items.Count;
  405. else if (draw_mode == DrawMode.OwnerDrawVariable) {
  406. for (int i = 0; i < items.Count; i++)
  407. itemsHeight += (int) item_heights [Items [i]];
  408. }
  409. return itemsHeight;
  410. }
  411. }
  412. public override RightToLeft RightToLeft {
  413. get { return base.RightToLeft; }
  414. set {
  415. base.RightToLeft = value;
  416. if (base.RightToLeft == RightToLeft.Yes)
  417. StringFormat.Alignment = StringAlignment.Far;
  418. else
  419. StringFormat.Alignment = StringAlignment.Near;
  420. base.Refresh ();
  421. }
  422. }
  423. // Only affects the Vertical ScrollBar
  424. [DefaultValue (false)]
  425. [Localizable (true)]
  426. public bool ScrollAlwaysVisible {
  427. get { return scroll_always_visible; }
  428. set {
  429. if (scroll_always_visible == value)
  430. return;
  431. scroll_always_visible = value;
  432. UpdateScrollBars ();
  433. }
  434. }
  435. [Bindable(true)]
  436. [Browsable (false)]
  437. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  438. public override int SelectedIndex {
  439. get {
  440. if (selected_indices == null)
  441. return -1;
  442. return selected_indices.Count > 0 ? selected_indices [0] : -1;
  443. }
  444. set {
  445. if (value < -1 || value >= Items.Count)
  446. throw new ArgumentOutOfRangeException ("Index of out range");
  447. if (SelectionMode == SelectionMode.None)
  448. throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
  449. if (value == -1)
  450. selected_indices.Clear ();
  451. else
  452. selected_indices.Add (value);
  453. }
  454. }
  455. [Browsable (false)]
  456. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  457. public SelectedIndexCollection SelectedIndices {
  458. get { return selected_indices; }
  459. }
  460. [Bindable(true)]
  461. [Browsable (false)]
  462. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  463. public object SelectedItem {
  464. get {
  465. if (SelectedItems.Count > 0)
  466. return SelectedItems[0];
  467. else
  468. return null;
  469. }
  470. set {
  471. if (value != null && !Items.Contains (value))
  472. return; // FIXME: this is probably an exception
  473. SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
  474. }
  475. }
  476. [Browsable (false)]
  477. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  478. public SelectedObjectCollection SelectedItems {
  479. get {return selected_items;}
  480. }
  481. [DefaultValue (SelectionMode.One)]
  482. public virtual SelectionMode SelectionMode {
  483. get { return selection_mode; }
  484. set {
  485. if (!Enum.IsDefined (typeof (SelectionMode), value))
  486. throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
  487. if (selection_mode == value)
  488. return;
  489. selection_mode = value;
  490. switch (selection_mode) {
  491. case SelectionMode.None:
  492. SelectedIndices.Clear ();
  493. break;
  494. case SelectionMode.One:
  495. // FIXME: Probably this can be improved
  496. ArrayList old_selection = (ArrayList) SelectedIndices.List.Clone ();
  497. for (int i = 1; i < old_selection.Count; i++)
  498. SelectedIndices.Remove ((int)old_selection [i]);
  499. break;
  500. default:
  501. break;
  502. }
  503. // UIA Framework: Generates SelectionModeChanged event.
  504. OnUIASelectionModeChangedEvent ();
  505. }
  506. }
  507. [DefaultValue (false)]
  508. public bool Sorted {
  509. get { return sorted; }
  510. set {
  511. if (sorted == value)
  512. return;
  513. sorted = value;
  514. if (sorted)
  515. Sort ();
  516. }
  517. }
  518. [Bindable (false)]
  519. [Browsable (false)]
  520. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  521. [EditorBrowsable (EditorBrowsableState.Advanced)]
  522. public override string Text {
  523. get {
  524. if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
  525. return GetItemText (SelectedItem);
  526. return base.Text;
  527. }
  528. set {
  529. base.Text = value;
  530. if (SelectionMode == SelectionMode.None)
  531. return;
  532. int index;
  533. index = FindStringExact (value);
  534. if (index == -1)
  535. return;
  536. SelectedIndex = index;
  537. }
  538. }
  539. [Browsable (false)]
  540. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  541. public int TopIndex {
  542. get { return top_index; }
  543. set {
  544. if (value == top_index)
  545. return;
  546. if (value < 0 || value >= Items.Count)
  547. return;
  548. int page_size = (items_area.Height / ItemHeight);
  549. if (Items.Count < page_size)
  550. value = 0;
  551. else if (!multicolumn)
  552. top_index = Math.Min (value, Items.Count - page_size);
  553. else
  554. top_index = value;
  555. UpdateTopItem ();
  556. base.Refresh ();
  557. }
  558. }
  559. [Browsable (false)]
  560. [DefaultValue (false)]
  561. public bool UseCustomTabOffsets {
  562. get { return use_custom_tab_offsets; }
  563. set {
  564. if (use_custom_tab_offsets != value) {
  565. use_custom_tab_offsets = value;
  566. CalculateTabStops ();
  567. }
  568. }
  569. }
  570. [DefaultValue (true)]
  571. public bool UseTabStops {
  572. get { return use_tabstops; }
  573. set {
  574. if (use_tabstops == value)
  575. return;
  576. use_tabstops = value;
  577. CalculateTabStops ();
  578. }
  579. }
  580. protected override bool AllowSelection {
  581. get {
  582. return SelectionMode != SelectionMode.None;
  583. }
  584. }
  585. #endregion Public Properties
  586. #region Private Properties
  587. private int ColumnWidthInternal {
  588. get { return column_width_internal; }
  589. set { column_width_internal = value; }
  590. }
  591. private int row_count = 1;
  592. private int RowCount {
  593. get {
  594. return MultiColumn ? row_count : Items.Count;
  595. }
  596. }
  597. #endregion Private Properties
  598. #region UIA Framework Properties
  599. internal ScrollBar UIAHScrollBar {
  600. get { return hscrollbar; }
  601. }
  602. internal ScrollBar UIAVScrollBar {
  603. get { return vscrollbar; }
  604. }
  605. #endregion UIA Framework Properties
  606. #region Public Methods
  607. [Obsolete ("this method has been deprecated")]
  608. protected virtual void AddItemsCore (object[] value)
  609. {
  610. Items.AddRange (value);
  611. }
  612. public void BeginUpdate ()
  613. {
  614. suspend_layout = true;
  615. }
  616. public void ClearSelected ()
  617. {
  618. selected_indices.Clear ();
  619. }
  620. protected virtual ObjectCollection CreateItemCollection ()
  621. {
  622. return new ObjectCollection (this);
  623. }
  624. public void EndUpdate ()
  625. {
  626. suspend_layout = false;
  627. LayoutListBox ();
  628. base.Refresh ();
  629. }
  630. public int FindString (String s)
  631. {
  632. return FindString (s, -1);
  633. }
  634. public int FindString (string s, int startIndex)
  635. {
  636. if (Items.Count == 0)
  637. return -1; // No exception throwing if empty
  638. if (startIndex < -1 || startIndex >= Items.Count)
  639. throw new ArgumentOutOfRangeException ("Index of out range");
  640. startIndex = (startIndex == Items.Count - 1) ? 0 : startIndex + 1;
  641. int i = startIndex;
  642. while (true) {
  643. string text = GetItemText (Items [i]);
  644. if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (text, s,
  645. CompareOptions.IgnoreCase))
  646. return i;
  647. i = (i == Items.Count - 1) ? 0 : i + 1;
  648. if (i == startIndex)
  649. break;
  650. }
  651. return NoMatches;
  652. }
  653. public int FindStringExact (string s)
  654. {
  655. return FindStringExact (s, -1);
  656. }
  657. public int FindStringExact (string s, int startIndex)
  658. {
  659. if (Items.Count == 0)
  660. return -1; // No exception throwing if empty
  661. if (startIndex < -1 || startIndex >= Items.Count)
  662. throw new ArgumentOutOfRangeException ("Index of out range");
  663. startIndex = (startIndex + 1 == Items.Count) ? 0 : startIndex + 1;
  664. int i = startIndex;
  665. while (true) {
  666. if (String.Compare (GetItemText (Items[i]), s, true) == 0)
  667. return i;
  668. i = (i + 1 == Items.Count) ? 0 : i + 1;
  669. if (i == startIndex)
  670. break;
  671. }
  672. return NoMatches;
  673. }
  674. public int GetItemHeight (int index)
  675. {
  676. if (index < 0 || index >= Items.Count)
  677. throw new ArgumentOutOfRangeException ("Index of out range");
  678. if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
  679. object o = Items [index];
  680. if (item_heights.Contains (o))
  681. return (int) item_heights [o];
  682. MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
  683. OnMeasureItem (args);
  684. item_heights [o] = args.ItemHeight;
  685. return args.ItemHeight;
  686. }
  687. return ItemHeight;
  688. }
  689. public Rectangle GetItemRectangle (int index)
  690. {
  691. if (index < 0 || index >= Items.Count)
  692. throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
  693. Rectangle rect = new Rectangle ();
  694. if (MultiColumn) {
  695. int col = index / RowCount;
  696. int y = index;
  697. if (y < 0) // We convert it to valid positive value
  698. y += RowCount * (top_index / RowCount);
  699. rect.Y = (y % RowCount) * ItemHeight;
  700. rect.X = (col - (top_index / RowCount)) * ColumnWidthInternal;
  701. rect.Height = ItemHeight;
  702. rect.Width = ColumnWidthInternal;
  703. } else {
  704. rect.X = 0;
  705. rect.Height = GetItemHeight (index);
  706. rect.Width = items_area.Width;
  707. if (DrawMode == DrawMode.OwnerDrawVariable) {
  708. rect.Y = 0;
  709. if (index >= top_index) {
  710. for (int i = top_index; i < index; i++) {
  711. rect.Y += GetItemHeight (i);
  712. }
  713. } else {
  714. for (int i = index; i < top_index; i++) {
  715. rect.Y -= GetItemHeight (i);
  716. }
  717. }
  718. } else {
  719. rect.Y = ItemHeight * (index - top_index);
  720. }
  721. }
  722. if (this is CheckedListBox)
  723. rect.Width += 15;
  724. return rect;
  725. }
  726. [EditorBrowsable (EditorBrowsableState.Advanced)]
  727. protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
  728. {
  729. bounds.Height = requested_height;
  730. return base.GetScaledBounds (bounds, factor, specified);
  731. }
  732. public bool GetSelected (int index)
  733. {
  734. if (index < 0 || index >= Items.Count)
  735. throw new ArgumentOutOfRangeException ("Index of out range");
  736. return SelectedIndices.Contains (index);
  737. }
  738. public int IndexFromPoint (Point p)
  739. {
  740. return IndexFromPoint (p.X, p.Y);
  741. }
  742. // Only returns visible points
  743. public int IndexFromPoint (int x, int y)
  744. {
  745. if (Items.Count == 0) {
  746. return -1;
  747. }
  748. for (int i = top_index; i <= last_visible_index; i++) {
  749. if (GetItemRectangle (i).Contains (x,y) == true)
  750. return i;
  751. }
  752. return -1;
  753. }
  754. protected override void OnChangeUICues (UICuesEventArgs e)
  755. {
  756. base.OnChangeUICues (e);
  757. }
  758. protected override void OnDataSourceChanged (EventArgs e)
  759. {
  760. base.OnDataSourceChanged (e);
  761. BindDataItems ();
  762. if (DataSource == null || DataManager == null) {
  763. SelectedIndex = -1;
  764. } else {
  765. SelectedIndex = DataManager.Position;
  766. }
  767. }
  768. protected override void OnDisplayMemberChanged (EventArgs e)
  769. {
  770. base.OnDisplayMemberChanged (e);
  771. if (DataManager == null || !IsHandleCreated)
  772. return;
  773. BindDataItems ();
  774. base.Refresh ();
  775. }
  776. protected virtual void OnDrawItem (DrawItemEventArgs e)
  777. {
  778. switch (DrawMode) {
  779. case DrawMode.OwnerDrawFixed:
  780. case DrawMode.OwnerDrawVariable:
  781. DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
  782. if (eh != null)
  783. eh (this, e);
  784. break;
  785. default:
  786. ThemeEngine.Current.DrawListBoxItem (this, e);
  787. break;
  788. }
  789. }
  790. protected override void OnFontChanged (EventArgs e)
  791. {
  792. base.OnFontChanged (e);
  793. if (use_tabstops)
  794. StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
  795. if (explicit_item_height) {
  796. base.Refresh ();
  797. } else {
  798. SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
  799. item_height = (int) sz.Height;
  800. if (IntegralHeight)
  801. UpdateListBoxBounds ();
  802. LayoutListBox ();
  803. }
  804. }
  805. protected override void OnHandleCreated (EventArgs e)
  806. {
  807. base.OnHandleCreated (e);
  808. if (IntegralHeight)
  809. UpdateListBoxBounds ();
  810. LayoutListBox ();
  811. EnsureVisible (focused_item);
  812. }
  813. protected override void OnHandleDestroyed (EventArgs e)
  814. {
  815. base.OnHandleDestroyed (e);
  816. }
  817. protected virtual void OnMeasureItem (MeasureItemEventArgs e)
  818. {
  819. if (draw_mode != DrawMode.OwnerDrawVariable)
  820. return;
  821. MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
  822. if (eh != null)
  823. eh (this, e);
  824. }
  825. protected override void OnParentChanged (EventArgs e)
  826. {
  827. base.OnParentChanged (e);
  828. }
  829. protected override void OnResize (EventArgs e)
  830. {
  831. base.OnResize (e);
  832. if (canvas_size.IsEmpty || MultiColumn)
  833. LayoutListBox ();
  834. Invalidate ();
  835. }
  836. protected override void OnSelectedIndexChanged (EventArgs e)
  837. {
  838. base.OnSelectedIndexChanged (e);
  839. EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
  840. if (eh != null)
  841. eh (this, e);
  842. }
  843. protected override void OnSelectedValueChanged (EventArgs e)
  844. {
  845. base.OnSelectedValueChanged (e);
  846. }
  847. public override void Refresh ()
  848. {
  849. if (draw_mode == DrawMode.OwnerDrawVariable)
  850. item_heights.Clear ();
  851. base.Refresh ();
  852. }
  853. protected override void RefreshItem (int index)
  854. {
  855. if (index < 0 || index >= Items.Count)
  856. throw new ArgumentOutOfRangeException ("Index of out range");
  857. if (draw_mode == DrawMode.OwnerDrawVariable)
  858. item_heights.Remove (Items [index]);
  859. }
  860. protected override void RefreshItems ()
  861. {
  862. for (int i = 0; i < Items.Count; i++) {
  863. RefreshItem (i);
  864. }
  865. LayoutListBox ();
  866. Refresh ();
  867. }
  868. public override void ResetBackColor ()
  869. {
  870. base.ResetBackColor ();
  871. }
  872. public override void ResetForeColor ()
  873. {
  874. base.ResetForeColor ();
  875. }
  876. protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
  877. {
  878. base.ScaleControl (factor, specified);
  879. }
  880. private int SnapHeightToIntegral (int height)
  881. {
  882. int border;
  883. switch (border_style) {
  884. case BorderStyle.Fixed3D:
  885. border = ThemeEngine.Current.Border3DSize.Height;
  886. break;
  887. case BorderStyle.FixedSingle:
  888. border = ThemeEngine.Current.BorderSize.Height;
  889. break;
  890. case BorderStyle.None:
  891. default:
  892. border = 0;
  893. break;
  894. }
  895. height -= (2 * border);
  896. height -= height % ItemHeight;
  897. height += (2 * border);
  898. return height;
  899. }
  900. protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
  901. {
  902. if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
  903. requested_height = height;
  904. if (IntegralHeight && IsHandleCreated)
  905. height = SnapHeightToIntegral (height);
  906. base.SetBoundsCore (x, y, width, height, specified);
  907. UpdateScrollBars ();
  908. last_visible_index = LastVisibleItem ();
  909. }
  910. protected override void SetItemCore (int index, object value)
  911. {
  912. if (index < 0 || index >= Items.Count)
  913. return;
  914. Items[index] = value;
  915. }
  916. protected override void SetItemsCore (IList value)
  917. {
  918. BeginUpdate ();
  919. try {
  920. Items.Clear ();
  921. Items.AddItems (value);
  922. } finally {
  923. EndUpdate ();
  924. }
  925. }
  926. public void SetSelected (int index, bool value)
  927. {
  928. if (index < 0 || index >= Items.Count)
  929. throw new ArgumentOutOfRangeException ("Index of out range");
  930. if (SelectionMode == SelectionMode.None)
  931. throw new InvalidOperationException ();
  932. if (value)
  933. SelectedIndices.Add (index);
  934. else
  935. SelectedIndices.Remove (index);
  936. }
  937. protected virtual void Sort ()
  938. {
  939. Sort (true);
  940. }
  941. //
  942. // Sometimes we could need to Sort, and request a Refresh
  943. // in a different place, to not have the painting done twice
  944. //
  945. void Sort (bool paint)
  946. {
  947. if (Items.Count == 0)
  948. return;
  949. Items.Sort ();
  950. if (paint)
  951. base.Refresh ();
  952. }
  953. public override string ToString ()
  954. {
  955. return base.ToString ();
  956. }
  957. protected virtual void WmReflectCommand (ref Message m)
  958. {
  959. }
  960. protected override void WndProc (ref Message m)
  961. {
  962. if ((Msg)m.Msg == Msg.WM_KEYDOWN) {
  963. if (ProcessKeyMessage (ref m))
  964. m.Result = IntPtr.Zero;
  965. else {
  966. HandleKeyDown ((Keys)m.WParam.ToInt32 ());
  967. DefWndProc (ref m);
  968. }
  969. return;
  970. }
  971. base.WndProc (ref m);
  972. }
  973. #endregion Public Methods
  974. #region Private Methods
  975. private void CalculateTabStops ()
  976. {
  977. if (use_tabstops) {
  978. if (use_custom_tab_offsets) {
  979. float[] f = new float[custom_tab_offsets.Count];
  980. custom_tab_offsets.CopyTo (f, 0);
  981. StringFormat.SetTabStops (0, f);
  982. }
  983. else
  984. StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) });
  985. } else
  986. StringFormat.SetTabStops (0, new float[0]);
  987. this.Invalidate ();
  988. }
  989. private Size canvas_size;
  990. private void LayoutListBox ()
  991. {
  992. if (!IsHandleCreated || suspend_layout)
  993. return;
  994. if (MultiColumn)
  995. LayoutMultiColumn ();
  996. else
  997. LayoutSingleColumn ();
  998. last_visible_index = LastVisibleItem ();
  999. UpdateScrollBars ();
  1000. }
  1001. private void LayoutSingleColumn ()
  1002. {
  1003. int height, width;
  1004. switch (DrawMode) {
  1005. case DrawMode.OwnerDrawVariable:
  1006. height = 0;
  1007. width = HorizontalExtent;
  1008. for (int i = 0; i < Items.Count; i++) {
  1009. height += GetItemHeight (i);
  1010. }
  1011. break;
  1012. case DrawMode.OwnerDrawFixed:
  1013. height = Items.Count * ItemHeight;
  1014. width = HorizontalExtent;
  1015. break;
  1016. case DrawMode.Normal:
  1017. default:
  1018. height = Items.Count * ItemHeight;
  1019. width = 0;
  1020. for (int i = 0; i < Items.Count; i++) {
  1021. SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font);
  1022. int t = (int)sz.Width;
  1023. if (this is CheckedListBox)
  1024. t += 15;
  1025. if (t > width)
  1026. width = t;
  1027. }
  1028. break;
  1029. }
  1030. canvas_size = new Size (width, height);
  1031. }
  1032. private void LayoutMultiColumn ()
  1033. {
  1034. int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
  1035. row_count = Math.Max (1, usable_height / ItemHeight);
  1036. int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
  1037. Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
  1038. if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
  1039. usable_height = ClientRectangle.Height - hscrollbar.Height;
  1040. row_count = Math.Max (1, usable_height / ItemHeight);
  1041. cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
  1042. sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
  1043. }
  1044. canvas_size = sz;
  1045. }
  1046. internal void Draw (Rectangle clip, Graphics dc)
  1047. {
  1048. Theme theme = ThemeEngine.Current;
  1049. if (hscrollbar.Visible && vscrollbar.Visible) {
  1050. // Paint the dead space in the bottom right corner
  1051. Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
  1052. if (rect.IntersectsWith (clip))
  1053. dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
  1054. }
  1055. dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
  1056. if (Items.Count == 0)
  1057. return;
  1058. for (int i = top_index; i <= last_visible_index; i++) {
  1059. Rectangle rect = GetItemDisplayRectangle (i, top_index);
  1060. if (!clip.IntersectsWith (rect))
  1061. continue;
  1062. DrawItemState state = DrawItemState.None;
  1063. if (SelectedIndices.Contains (i))
  1064. state |= DrawItemState.Selected;
  1065. if (has_focus && FocusedItem == i)
  1066. state |= DrawItemState.Focus;
  1067. if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
  1068. rect.X -= hscrollbar.Value;
  1069. rect.Width += hscrollbar.Value;
  1070. }
  1071. Color fore_color = !Enabled ? ThemeEngine.Current.ColorGrayText :
  1072. (state & DrawItemState.Selected) != 0 ? ThemeEngine.Current.ColorHighlightText : ForeColor;
  1073. OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, fore_color, BackColor));
  1074. }
  1075. }
  1076. // Converts a GetItemRectangle to a one that we can display
  1077. internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
  1078. {
  1079. Rectangle item_rect;
  1080. Rectangle first_item_rect = GetItemRectangle (first_displayble);
  1081. item_rect = GetItemRectangle (index);
  1082. item_rect.X -= first_item_rect.X;
  1083. item_rect.Y -= first_item_rect.Y;
  1084. // Subtract the checkboxes from the width
  1085. if (this is CheckedListBox)
  1086. item_rect.Width -= 14;
  1087. return item_rect;
  1088. }
  1089. // Value Changed
  1090. private void HorizontalScrollEvent (object sender, EventArgs e)
  1091. {
  1092. if (multicolumn) {
  1093. int top_item = top_index;
  1094. int last_item = last_visible_index;
  1095. top_index = RowCount * hscrollbar.Value;
  1096. last_visible_index = LastVisibleItem ();
  1097. if (top_item != top_index || last_item != last_visible_index)
  1098. Invalidate (items_area);
  1099. }
  1100. else {
  1101. int old_offset = hbar_offset;
  1102. hbar_offset = hscrollbar.Value;
  1103. if (hbar_offset < 0)
  1104. hbar_offset = 0;
  1105. if (IsHandleCreated) {
  1106. XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
  1107. // Invalidate the previous selection border, to keep it properly updated.
  1108. Rectangle selection_border_area = new Rectangle (items_area.Width - (hbar_offset - old_offset) - 3, 0,
  1109. 3, items_area.Height);
  1110. Invalidate (selection_border_area);
  1111. }
  1112. }
  1113. }
  1114. // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
  1115. // has screen coordinates
  1116. private int IndexAtClientPoint (int x, int y)
  1117. {
  1118. if (Items.Count == 0)
  1119. return -1;
  1120. if (x < 0)
  1121. x = 0;
  1122. else if (x > ClientRectangle.Right)
  1123. x = ClientRectangle.Right;
  1124. if (y < 0)
  1125. y = 0;
  1126. else if (y > ClientRectangle.Bottom)
  1127. y = ClientRectangle.Bottom;
  1128. for (int i = top_index; i <= last_visible_index; i++)
  1129. if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
  1130. return i;
  1131. return -1;
  1132. }
  1133. internal override bool IsInputCharInternal (char charCode)
  1134. {
  1135. return true;
  1136. }
  1137. private int LastVisibleItem ()
  1138. {
  1139. Rectangle item_rect;
  1140. int top_y = items_area.Y + items_area.Height;
  1141. int i = 0;
  1142. if (top_index >= Items.Count)
  1143. return top_index;
  1144. for (i = top_index; i < Items.Count; i++) {
  1145. item_rect = GetItemDisplayRectangle (i, top_index);
  1146. if (MultiColumn) {
  1147. if (item_rect.X > items_area.Width)
  1148. return i - 1;
  1149. } else {
  1150. if (item_rect.Y + item_rect.Height > top_y)
  1151. return i;
  1152. }
  1153. }
  1154. return i - 1;
  1155. }
  1156. private void UpdateTopItem ()
  1157. {
  1158. if (MultiColumn) {
  1159. int col = top_index / RowCount;
  1160. if (col > hscrollbar.Maximum)
  1161. hscrollbar.Value = hscrollbar.Maximum;
  1162. else
  1163. hscrollbar.Value = col;
  1164. } else {
  1165. if (top_index > vscrollbar.Maximum)
  1166. vscrollbar.Value = vscrollbar.Maximum;
  1167. else
  1168. vscrollbar.Value = top_index;
  1169. Scroll (vscrollbar, vscrollbar.Value - top_index);
  1170. }
  1171. }
  1172. // Navigates to the indicated item and returns the new item
  1173. private int NavigateItemVisually (ItemNavigation navigation)
  1174. {
  1175. int page_size, columns, selected_index = -1;
  1176. if (multicolumn) {
  1177. columns = items_area.Width / ColumnWidthInternal;
  1178. page_size = columns * RowCount;
  1179. if (page_size == 0) {
  1180. page_size = RowCount;
  1181. }
  1182. } else {
  1183. page_size = items_area.Height / ItemHeight;
  1184. }
  1185. switch (navigation) {
  1186. case ItemNavigation.PreviousColumn: {
  1187. if (SelectedIndex - RowCount < 0) {
  1188. return -1;
  1189. }
  1190. if (SelectedIndex - RowCount < top_index) {
  1191. top_index = SelectedIndex - RowCount;
  1192. UpdateTopItem ();
  1193. }
  1194. selected_index = SelectedIndex - RowCount;
  1195. break;
  1196. }
  1197. case ItemNavigation.NextColumn: {
  1198. if (SelectedIndex + RowCount >= Items.Count) {
  1199. break;
  1200. }
  1201. if (SelectedIndex + RowCount > last_visible_index) {
  1202. top_index = SelectedIndex;
  1203. UpdateTopItem ();
  1204. }
  1205. selected_index = SelectedIndex + RowCount;
  1206. break;
  1207. }
  1208. case ItemNavigation.First: {
  1209. top_index = 0;
  1210. selected_index = 0;
  1211. UpdateTopItem ();
  1212. break;
  1213. }
  1214. case ItemNavigation.Last: {
  1215. int rows = items_area.Height / ItemHeight;
  1216. if (multicolumn) {
  1217. selected_index = Items.Count - 1;
  1218. break;
  1219. }
  1220. if (Items.Count < rows) {
  1221. top_index = 0;
  1222. selected_index = Items.Count - 1;
  1223. UpdateTopItem ();
  1224. } else {
  1225. top_index = Items.Count - rows;
  1226. selected_index = Items.Count - 1;
  1227. UpdateTopItem ();
  1228. }
  1229. break;
  1230. }
  1231. case ItemNavigation.Next: {
  1232. if (FocusedItem == Items.Count - 1)
  1233. return -1;
  1234. if (multicolumn) {
  1235. selected_index = FocusedItem + 1;
  1236. break;
  1237. }
  1238. int bottom = 0;
  1239. ArrayList heights = new ArrayList ();
  1240. if (draw_mode == DrawMode.OwnerDrawVariable) {
  1241. for (int i = top_index; i <= FocusedItem + 1; i++) {
  1242. int h = GetItemHeight (i);
  1243. bottom += h;
  1244. heights.Add (h);
  1245. }
  1246. } else {
  1247. bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
  1248. }
  1249. if (bottom >= items_area.Height) {
  1250. int overhang = bottom - items_area.Height;
  1251. int offset = 0;
  1252. if (draw_mode == DrawMode.OwnerDrawVariable)
  1253. while (overhang > 0)
  1254. overhang -= (int) heights [offset];
  1255. else
  1256. offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
  1257. top_index += offset;
  1258. UpdateTopItem ();
  1259. }
  1260. selected_index = FocusedItem + 1;
  1261. break;
  1262. }
  1263. case ItemNavigation.Previous: {
  1264. if (FocusedItem > 0) {
  1265. if (FocusedItem - 1 < top_index) {
  1266. top_index--;
  1267. UpdateTopItem ();
  1268. }
  1269. selected_index = FocusedItem - 1;
  1270. }
  1271. break;
  1272. }
  1273. case ItemNavigation.NextPage: {
  1274. if (Items.Count < page_size) {
  1275. NavigateItemVisually (ItemNavigation.Last);
  1276. break;
  1277. }
  1278. if (FocusedItem + page_size - 1 >= Items.Count) {
  1279. top_index = Items.Count - page_size;
  1280. UpdateTopItem ();
  1281. selected_index = Items.Count - 1;
  1282. }
  1283. else {
  1284. if (FocusedItem + page_size - 1 > last_visible_index) {
  1285. top_index = FocusedItem;
  1286. UpdateTopItem ();
  1287. }
  1288. selected_index = FocusedItem + page_size - 1;
  1289. }
  1290. break;
  1291. }
  1292. case ItemNavigation.PreviousPage: {
  1293. int rows = items_area.Height / ItemHeight;
  1294. if (FocusedItem - (rows - 1) <= 0) {
  1295. top_index = 0;
  1296. UpdateTopItem ();
  1297. selected_index = 0;
  1298. }
  1299. else {
  1300. if (SelectedIndex - (rows - 1) < top_index) {
  1301. top_index = FocusedItem - (rows - 1);
  1302. UpdateTopItem ();
  1303. }
  1304. selected_index = FocusedItem - (rows - 1);
  1305. }
  1306. break;
  1307. }
  1308. default:
  1309. break;
  1310. }
  1311. return selected_index;
  1312. }
  1313. private void OnGotFocus (object sender, EventArgs e)
  1314. {
  1315. if (Items.Count == 0)
  1316. return;
  1317. if (FocusedItem == -1)
  1318. FocusedItem = 0;
  1319. InvalidateItem (FocusedItem);
  1320. }
  1321. private void OnLostFocus (object sender, EventArgs e)
  1322. {
  1323. if (FocusedItem != -1)
  1324. InvalidateItem (FocusedItem);
  1325. }
  1326. private bool KeySearch (Keys key)
  1327. {
  1328. char c = (char) key;
  1329. if (!Char.IsLetterOrDigit (c))
  1330. return false;
  1331. int idx = FindString (c.ToString (), SelectedIndex);
  1332. if (idx != ListBox.NoMatches)
  1333. SelectedIndex = idx;
  1334. return true;
  1335. }
  1336. internal void HandleKeyDown (Keys key)
  1337. {
  1338. int new_item = -1;
  1339. if (Items.Count == 0)
  1340. return;
  1341. if (KeySearch (key))
  1342. return;
  1343. switch (key) {
  1344. case Keys.ControlKey:
  1345. ctrl_pressed = true;
  1346. break;
  1347. case Keys.ShiftKey:
  1348. shift_pressed = true;
  1349. break;
  1350. case Keys.Home:
  1351. new_item = NavigateItemVisually (ItemNavigation.First);
  1352. break;
  1353. case Keys.End:
  1354. new_item = NavigateItemVisually (ItemNavigation.Last);
  1355. break;
  1356. case Keys.Up:
  1357. new_item = NavigateItemVisually (ItemNavigation.Previous);
  1358. break;
  1359. case Keys.Down:
  1360. new_item = NavigateItemVisually (ItemNavigation.Next);
  1361. break;
  1362. case Keys.PageUp:
  1363. new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
  1364. break;
  1365. case Keys.PageDown:
  1366. new_item = NavigateItemVisually (ItemNavigation.NextPage);
  1367. break;
  1368. case Keys.Right:
  1369. if (multicolumn == true) {
  1370. new_item = NavigateItemVisually (ItemNavigation.NextColumn);
  1371. }
  1372. break;
  1373. case Keys.Left:
  1374. if (multicolumn == true) {
  1375. new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
  1376. }
  1377. break;
  1378. case Keys.Space:
  1379. if (selection_mode == SelectionMode.MultiSimple) {
  1380. SelectedItemFromNavigation (FocusedItem);
  1381. }
  1382. break;
  1383. default:
  1384. break;
  1385. }
  1386. if (new_item != -1) {
  1387. FocusedItem = new_item;
  1388. if (selection_mode != SelectionMode.MultiSimple)
  1389. SelectedItemFromNavigation (new_item);
  1390. }
  1391. }
  1392. private void OnKeyUpLB (object sender, KeyEventArgs e)
  1393. {
  1394. switch (e.KeyCode) {
  1395. case Keys.ControlKey:
  1396. ctrl_pressed = false;
  1397. break;
  1398. case Keys.ShiftKey:
  1399. shift_pressed = false;
  1400. break;
  1401. default:
  1402. break;
  1403. }
  1404. }
  1405. internal void InvalidateItem (int index)
  1406. {
  1407. if (!IsHandleCreated)
  1408. return;
  1409. Rectangle bounds = GetItemDisplayRectangle (index, top_index);
  1410. if (ClientRectangle.IntersectsWith (bounds))
  1411. Invalidate (bounds);
  1412. }
  1413. internal virtual void OnItemClick (int index)
  1414. {
  1415. OnSelectedIndexChanged (EventArgs.Empty);
  1416. OnSelectedValueChanged (EventArgs.Empty);
  1417. }
  1418. int anchor = -1;
  1419. int[] prev_selection;
  1420. bool button_pressed = false;
  1421. Point button_pressed_loc = new Point (-1, -1);
  1422. private void SelectExtended (int index)
  1423. {
  1424. SuspendLayout ();
  1425. ArrayList new_selection = new ArrayList ();
  1426. int start = anchor < index ? anchor : index;
  1427. int end = anchor > index ? anchor : index;
  1428. for (int i = start; i <= end; i++)
  1429. new_selection.Add (i);
  1430. if (ctrl_pressed)
  1431. foreach (int i in prev_selection)
  1432. if (!new_selection.Contains (i))
  1433. new_selection.Add (i);
  1434. // Need to make a copy since we can't enumerate and modify the collection
  1435. // at the same time
  1436. ArrayList sel_indices = (ArrayList) selected_indices.List.Clone ();
  1437. foreach (int i in sel_indices)
  1438. if (!new_selection.Contains (i))
  1439. selected_indices.Remove (i);
  1440. foreach (int i in new_selection)
  1441. if (!sel_indices.Contains (i))
  1442. selected_indices.AddCore (i);
  1443. ResumeLayout ();
  1444. }
  1445. private void OnMouseDownLB (object sender, MouseEventArgs e)
  1446. {
  1447. // Only do stuff with the left mouse button
  1448. if ((e.Button & MouseButtons.Left) == 0)
  1449. return;
  1450. int index = IndexAtClientPoint (e.X, e.Y);
  1451. if (index == -1)
  1452. return;
  1453. switch (SelectionMode) {
  1454. case SelectionMode.One:
  1455. SelectedIndices.AddCore (index); // Unselects previous one
  1456. break;
  1457. case SelectionMode.MultiSimple:
  1458. if (SelectedIndices.Contains (index))
  1459. SelectedIndices.RemoveCore (index);
  1460. else
  1461. SelectedIndices.AddCore (index);
  1462. break;
  1463. case SelectionMode.MultiExtended:
  1464. shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
  1465. ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
  1466. if (shift_pressed) {
  1467. SelectedIndices.ClearCore ();
  1468. SelectExtended (index);
  1469. break;
  1470. }
  1471. anchor = index;
  1472. if (ctrl_pressed) {
  1473. prev_selection = new int [SelectedIndices.Count];
  1474. SelectedIndices.CopyTo (prev_selection, 0);
  1475. if (SelectedIndices.Contains (index))
  1476. SelectedIndices.RemoveCore (index);
  1477. else
  1478. SelectedIndices.AddCore (index);
  1479. break;
  1480. }
  1481. SelectedIndices.ClearCore ();
  1482. SelectedIndices.AddCore (index);
  1483. break;
  1484. case SelectionMode.None:
  1485. break;
  1486. default:
  1487. return;
  1488. }
  1489. button_pressed = true;
  1490. button_pressed_loc = new Point (e.X, e.Y);
  1491. FocusedItem = index;
  1492. }
  1493. private void OnMouseMoveLB (object sender, MouseEventArgs e)
  1494. {
  1495. // Don't take into account MouseMove events generated with MouseDown
  1496. if (!button_pressed || button_pressed_loc == new Point (e.X, e.Y))
  1497. return;
  1498. int index = IndexAtClientPoint (e.X, e.Y);
  1499. if (index == -1)
  1500. return;
  1501. switch (SelectionMode) {
  1502. case SelectionMode.One:
  1503. SelectedIndices.AddCore (index); // Unselects previous one
  1504. break;
  1505. case SelectionMode.MultiSimple:
  1506. break;
  1507. case SelectionMode.MultiExtended:
  1508. SelectExtended (index);
  1509. break;
  1510. case SelectionMode.None:
  1511. break;
  1512. default:
  1513. return;
  1514. }
  1515. FocusedItem = index;
  1516. }
  1517. internal override void OnDragDropEnd (DragDropEffects effects)
  1518. {
  1519. // In the case of a DnD operation (started on MouseDown)
  1520. // there will be no MouseUp event, so we need to reset
  1521. // the state here
  1522. button_pressed = false;
  1523. }
  1524. private void OnMouseUpLB (object sender, MouseEventArgs e)
  1525. {
  1526. // Only do stuff with the left mouse button
  1527. if ((e.Button & MouseButtons.Left) == 0)
  1528. return;
  1529. if (e.Clicks > 1) {
  1530. OnDoubleClick (EventArgs.Empty);
  1531. OnMouseDoubleClick (e);
  1532. }
  1533. else if (e.Clicks == 1) {
  1534. OnClick (EventArgs.Empty);
  1535. OnMouseClick (e);
  1536. }
  1537. if (!button_pressed)
  1538. return;
  1539. int index = IndexAtClientPoint (e.X, e.Y);
  1540. OnItemClick (index);
  1541. button_pressed = ctrl_pressed = shift_pressed = false;
  1542. }
  1543. private void Scroll (ScrollBar scrollbar, int delta)
  1544. {
  1545. if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
  1546. return;
  1547. int max;
  1548. if (scrollbar == hscrollbar)
  1549. max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
  1550. else
  1551. max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
  1552. int val = scrollbar.Value + delta;
  1553. if (val > max)
  1554. val = max;
  1555. else if (val < scrollbar.Minimum)
  1556. val = scrollbar.Minimum;
  1557. scrollbar.Value = val;
  1558. }
  1559. private void OnMouseWheelLB (object sender, MouseEventArgs me)
  1560. {
  1561. if (Items.Count == 0)
  1562. return;
  1563. int lines = me.Delta / 120;
  1564. if (MultiColumn)
  1565. Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
  1566. else
  1567. Scroll (vscrollbar, -lines);
  1568. }
  1569. internal override void OnPaintInternal (PaintEventArgs pevent)
  1570. {
  1571. if (suspend_layout)
  1572. return;
  1573. Draw (pevent.ClipRectangle, pevent.Graphics);
  1574. }
  1575. internal void RepositionScrollBars ()
  1576. {
  1577. if (vscrollbar.is_visible) {
  1578. vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
  1579. vscrollbar.Location = new Point (items_area.Width, 0);
  1580. }
  1581. if (hscrollbar.is_visible) {
  1582. hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
  1583. hscrollbar.Location = new Point (0, items_area.Height);
  1584. }
  1585. }
  1586. // An item navigation operation (mouse or keyboard) has caused to select a new item
  1587. internal void SelectedItemFromNavigation (int index)
  1588. {
  1589. switch (SelectionMode) {
  1590. case SelectionMode.None:
  1591. // .Net doesn't select the item, only ensures that it's visible
  1592. // and fires the selection related events
  1593. EnsureVisible (index);
  1594. OnSelectedIndexChanged (EventArgs.Empty);
  1595. OnSelectedValueChanged (EventArgs.Empty);
  1596. break;
  1597. case SelectionMode.One: {
  1598. SelectedIndex = index;
  1599. break;
  1600. }
  1601. case SelectionMode.MultiSimple: {
  1602. if (SelectedIndex == -1) {
  1603. SelectedIndex = index;
  1604. } else {
  1605. if (SelectedIndices.Contains (index))
  1606. SelectedIndices.Remove (index);
  1607. else {
  1608. SelectedIndices.AddCore (index);
  1609. OnSelectedIndexChanged (EventArgs.Empty);
  1610. OnSelectedValueChanged (EventArgs.Empty);
  1611. }
  1612. }
  1613. break;
  1614. }
  1615. case SelectionMode.MultiExtended: {
  1616. if (SelectedIndex == -1) {
  1617. SelectedIndex = index;
  1618. } else {
  1619. if (ctrl_pressed == false && shift_pressed == false) {
  1620. SelectedIndices.Clear ();
  1621. }
  1622. if (shift_pressed == true) {
  1623. ShiftSelection (index);
  1624. } else { // ctrl_pressed or single item
  1625. SelectedIndices.AddCore (index);
  1626. }
  1627. OnSelectedIndexChanged (EventArgs.Empty);
  1628. OnSelectedValueChanged (EventArgs.Empty);
  1629. }
  1630. break;
  1631. }
  1632. default:
  1633. break;
  1634. }
  1635. }
  1636. private void ShiftSelection (int index)
  1637. {
  1638. int shorter_item = -1, dist = Items.Count + 1, cur_dist;
  1639. foreach (int idx in selected_indices) {
  1640. if (idx > index) {
  1641. cur_dist = idx - index;
  1642. } else {
  1643. cur_dist = index - idx;
  1644. }
  1645. if (cur_dist < dist) {
  1646. dist = cur_dist;
  1647. shorter_item = idx;
  1648. }
  1649. }
  1650. if (shorter_item != -1) {
  1651. int start, end;
  1652. if (shorter_item > index) {
  1653. start = index;
  1654. end = shorter_item;
  1655. } else {
  1656. start = shorter_item;
  1657. end = index;
  1658. }
  1659. selected_indices.Clear ();
  1660. for (int idx = start; idx <= end; idx++) {
  1661. selected_indices.AddCore (idx);
  1662. }
  1663. }
  1664. }
  1665. internal int FocusedItem {
  1666. get { return focused_item; }
  1667. set {
  1668. if (focused_item == value)
  1669. return;
  1670. int prev = focused_item;
  1671. focused_item = value;
  1672. if (has_focus == false)
  1673. return;
  1674. if (prev != -1)
  1675. InvalidateItem (prev);
  1676. if (value != -1)
  1677. InvalidateItem (value);
  1678. // UIA Framework: Ge…

Large files files are truncated, but you can click here to view the full file