diff options
author | Mike Kestner <mkestner@gmail.com> | 2006-02-28 01:11:58 +0300 |
---|---|---|
committer | Mike Kestner <mkestner@gmail.com> | 2006-02-28 01:11:58 +0300 |
commit | 385e817034a3625fbbe1f65bafe7d94359840269 (patch) | |
tree | 0e28beea22d87ca334fc8ba78a07ede1f5685a49 | |
parent | 57fbaa058bc5806970bc9b2c1fd06398008ba3d4 (diff) |
2006-02-27 Mike Kestner <mkestner@novell.com>
* ListView.cs:
- Restructure layout and invalidation model to remove a ton of
flicker from the control and speed up performance in general.
- Add manual column resize, flickers like crazy, but I already have
some ideas on how I'll fix that. (#76822)
- Merge the three Icon-based views into a single layout method.
- Move item selection interaction logic from the item since
interaction with the collections is more appropriate to the view.
- Deselection on non-item clicks.
* ListViewItem.cs:
- Encapsulate most of the layout. Add some internal props to trigger
layout. Move to a model where Items invalidate themselves instead
of just invalidating the whole control every time something changes.
- Invalidate on Text/Caption changes.
- switch to an offset based layout model to avoid having to absolute
position every element on item moves.
- correct checkbox layout to conform to MS layout.
* ThemeWin32Classic.cs:
- refactor some column header drawing code.
- fix string justification for column headers (#76821)
- make SmallIcon labels top justified for compat with MS impl.
* ThemeClearlooks.cs:
- adjust to new ListViewItem internal checkbox bounds api.
svn path=/trunk/mcs/; revision=57357
5 files changed, 357 insertions, 368 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog index 3929d8802cf..08b274fdbfe 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog @@ -1,3 +1,29 @@ +2006-02-27 Mike Kestner <mkestner@novell.com> + + * ListView.cs: + - Restructure layout and invalidation model to remove a ton of + flicker from the control and speed up performance in general. + - Add manual column resize, flickers like crazy, but I already have + some ideas on how I'll fix that. (#76822) + - Merge the three Icon-based views into a single layout method. + - Move item selection interaction logic from the item since + interaction with the collections is more appropriate to the view. + - Deselection on non-item clicks. + * ListViewItem.cs: + - Encapsulate most of the layout. Add some internal props to trigger + layout. Move to a model where Items invalidate themselves instead + of just invalidating the whole control every time something changes. + - Invalidate on Text/Caption changes. + - switch to an offset based layout model to avoid having to absolute + position every element on item moves. + - correct checkbox layout to conform to MS layout. + * ThemeWin32Classic.cs: + - refactor some column header drawing code. + - fix string justification for column headers (#76821) + - make SmallIcon labels top justified for compat with MS impl. + * ThemeClearlooks.cs: + - adjust to new ListViewItem internal checkbox bounds api. + 2006-02-27 Jackson Harper <jackson@ximian.com> * Control.cs: Change where implicit controls fall in the zorder. diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs index 9066811f135..70ec71df299 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs @@ -22,6 +22,7 @@ // Authors: // Ravindra Kumar (rkumar@novell.com) // Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner (mkestner@novell.com) // // TODO: // - Item text editing @@ -29,7 +30,6 @@ // - Feedback for item activation, change in cursor types as mouse moves. // - HideSelection // - LabelEdit -// - Manual column resizing // - Drag and drop @@ -61,6 +61,8 @@ namespace System.Windows.Forms private ListViewItem clicked_item; private ListViewItem last_clicked_item; private ColumnHeaderCollection columns; + private ColumnHeader resize_column; + private bool column_resize_active = false; private bool ctrl_pressed; private bool shift_pressed; internal ListViewItem focused_item; @@ -525,7 +527,7 @@ namespace System.Windows.Forms // do a hit test for the scrolled position else { foreach (ListViewItem item in this.items) { - if (item.EntireRect.X >= h_marker && item.EntireRect.Y >= v_marker) + if (item.Bounds.X >= 0 && item.Bounds.Y >= 0) return item; } return null; @@ -564,8 +566,7 @@ namespace System.Windows.Forms return 0; foreach (ListViewItem item in this.items) { - if (item.EntireRect.X + item.EntireRect.Width >= h_marker - && item.EntireRect.Y + item.EntireRect.Height >= v_marker) + if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0) return item.Index; } return 0; @@ -574,10 +575,10 @@ namespace System.Windows.Forms } - internal int LastItemIndex { + internal int LastVisibleIndex { get { for (int i = FirstVisibleIndex; i < Items.Count; i++) { - if (Items[i].EntireRect.Y > v_marker + ClientRectangle.Bottom) + if (Items[i].Bounds.Y > ClientRectangle.Bottom) return i -1; } @@ -786,19 +787,72 @@ namespace System.Windows.Forms } } - + Size LargeIconItemSize { + get { + int w = Math.Max (text_size.Width, 2 + CheckBoxSize.Width + LargeImageList.ImageSize.Width); + int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, LargeImageList.ImageSize.Height); + return new Size (w, h); + } + } + + Size SmallIconItemSize { + get { + int w = text_size.Width + 2 + CheckBoxSize.Width + SmallImageList.ImageSize.Width; + int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, SmallImageList.ImageSize.Height)); + return new Size (w, h); + } + } + + void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing) + { + if (items.Count == 0) + return; + + Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize; + + int rows, cols; + + if (left_aligned) { + rows = (int) Math.Floor ((double)client_area.Height / (double)(sz.Height + y_spacing)); + if (rows == 0) + rows = 1; + cols = (int) Math.Ceiling ((double)items.Count / (double)rows); + } else { + cols = (int) Math.Floor ((double)client_area.Width / (double)(sz.Width + x_spacing)); + if (cols == 0) + cols = 1; + rows = (int) Math.Ceiling ((double)items.Count / (double)cols); + } + + layout_ht = rows * (sz.Height + y_spacing) - y_spacing; + layout_wd = cols * (sz.Width + x_spacing) - x_spacing; + int row = 0; + int col = 0; + foreach (ListViewItem item in items) { + int x = col * (sz.Width + x_spacing); + int y = row * (sz.Height + y_spacing); + item.Location = new Point (x, y); + item.Layout (); + if (left_aligned) { + if (++row == rows) { + row = 0; + col++; + } + } else { + if (++col == cols) { + col = 0; + row++; + } + } + } + } + // Sets the location of every item on // the ListView as per the view private void CalculateListView (ListViewAlignment align) { int current_pos_x = 0; // our x-position marker int current_pos_y = 0; // our y-position marker - int item_ht; - int item_wd; - int max; // max x_pos or y_pos depending on the alignment - int current = 0; // current row or column - int vertical_spacing = ThemeEngine.Current.ListViewVerticalSpacing; - int horizontal_spacing = ThemeEngine.Current.ListViewHorizontalSpacing; CalcTextSize (); @@ -806,8 +860,7 @@ namespace System.Windows.Forms case View.Details: // ColumnHeaders are not drawn if headerstyle is none - int ht = (this.header_style == ColumnHeaderStyle.None) ? - 0 : this.Font.Height + 3; + int ht = 0; if (columns.Count > 0) { foreach (ColumnHeader col in columns) { @@ -816,149 +869,41 @@ namespace System.Windows.Forms col.CalcColumnHeader (); current_pos_x += col.Wd; } - this.layout_wd = current_pos_x; + + if (header_style != ColumnHeaderStyle.None) + ht = columns [0].Ht; + layout_wd = current_pos_x; } // set the position marker for placing items // vertically down - current_pos_y = ht; + current_pos_y = ht + 2; if (items.Count > 0) { foreach (ListViewItem item in items) { - item.location.X = 0; - item.location.Y = current_pos_y; - item.CalcListViewItem (); - current_pos_y += item.EntireRect.Height; + item.Layout (); + item.Location = new Point (0, current_pos_y); + current_pos_y += item.Bounds.Height + 2; } - this.layout_ht = current_pos_y; + layout_ht = current_pos_y; // some space for bottom gridline - if (this.grid_lines) - this.layout_ht += 2; + if (grid_lines) + layout_ht += 2; } break; case View.SmallIcon: - vertical_spacing = 0; - horizontal_spacing = 0; - goto case View.LargeIcon; + LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2); + break; case View.LargeIcon: - if (items.Count > 0) { - items [0].CalcListViewItem (); - item_ht = items [0].EntireRect.Height; - item_wd = items [0].EntireRect.Width; - - // top (default) and snaptogrid alignments are handled same way - if (align == ListViewAlignment.Left) { - max = client_area.Height; - foreach (ListViewItem item in items) { - item.location.X = current_pos_x + - horizontal_spacing; - item.location.Y = 0; - item.CalcListViewItem (); - current_pos_y += item_ht; - - current ++; // just to know about the last element - // we just did the last item - if (current == items.Count) { - if (max < current_pos_y) - max = current_pos_y; - current_pos_x = item.EntireRect.Right; - break; - } - else { - // is there enough space for another row ? - if ((current_pos_y + vertical_spacing - + item_ht) <= client_area.Height) - current_pos_y += vertical_spacing; - else { - // start another column - // make current_pos_y as the - // max value and reset - // current_pos_y value. - max = current_pos_y; - current_pos_x += item_wd; - current_pos_y = 0; - } - } - } - // adjust the layout dimensions - this.layout_ht = max; - this.layout_wd = current_pos_x; - } - else { // other default/top alignment - max = client_area.Width; - foreach (ListViewItem item in items) { - item.location.X = current_pos_x + - horizontal_spacing; - - item.location.Y = current_pos_y; - item.CalcListViewItem (); - current_pos_x += item_wd; - - current ++; // just to know about the last element - // we just did the last item - if (current == items.Count) { - if (max < current_pos_x) - max = current_pos_x; - current_pos_y = item.EntireRect.Bottom; - break; - } - else { - // is there enough space for another column? - if ((current_pos_x + horizontal_spacing - + item_wd) <= client_area.Width) - continue; - else { - // start another row - // make current_pos_x as the - // max value and reset - // current_pos_x value. - max = current_pos_x; - current_pos_y += (item_ht + - vertical_spacing); - current_pos_x = 0; - } - } - } - // adjust the layout dimensions - this.layout_wd = max; - this.layout_ht = current_pos_y; - } - } + LayoutIcons (true, alignment == ListViewAlignment.Left, + ThemeEngine.Current.ListViewHorizontalSpacing, + ThemeEngine.Current.ListViewVerticalSpacing); break; case View.List: - if (items.Count > 0) { - items [0].CalcListViewItem (); - item_ht = items [0].EntireRect.Height; - item_wd = items [0].EntireRect.Width; - - max = client_area.Height / item_ht; - if (max == 0) - max = 1; // we draw at least one row - - foreach (ListViewItem item in items) { - item.location.X = current_pos_x; - item.location.Y = current_pos_y; - item.CalcListViewItem (); - current ++; - if (current == max) { - current_pos_x += item_wd; - current_pos_y = 0; - current = 0; - } - else - current_pos_y += item_ht; - } - - // adjust the layout dimensions - this.layout_ht = max * item_ht; - if (current == 0) // we have fully filled layout - this.layout_wd = current_pos_x; - else - this.layout_wd = current_pos_x + item_wd; - } + LayoutIcons (false, true, 4, 2); break; } @@ -966,6 +911,20 @@ namespace System.Windows.Forms } + void SelectItem (ListViewItem item) + { + if (!CanMultiselect && SelectedItems.Count > 0) { + SelectedItems.Clear (); + SelectedIndices.list.Clear (); + } + + if (!SelectedItems.Contains (item)) { + SelectedItems.list.Add (item); + SelectedIndices.list.Add (item.Index); + } + item.Selected = true; + } + private bool KeySearchString (KeyEventArgs ke) { int current_tickcnt = Environment.TickCount; @@ -981,7 +940,7 @@ namespace System.Windows.Forms if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text, CompareOptions.IgnoreCase)) { SetFocusedItem (Items [i]); - items [i].Selected = true; + SelectItem (items [i]); EnsureVisible (i); break; } @@ -1081,7 +1040,7 @@ namespace System.Windows.Forms } if (index != -1) { - items [index].Selected = true; + SelectItem (items [index]); SetFocusedItem (items [index]); EnsureVisible (index); } @@ -1111,6 +1070,12 @@ namespace System.Windows.Forms // hit test on columns if (this.view == View.Details && this.columns.Count > 0) { + if (resize_column != null) { + column_resize_active = true; + Capture = true; + return; + } + foreach (ColumnHeader col in this.columns) { if (col.Rect.Contains (hit)) { this.clicked_column = col; @@ -1121,7 +1086,9 @@ namespace System.Windows.Forms if (this.clicked_column != null) { this.clicked_column.pressed = true; - this.Redraw (false); + Rectangle bounds = clicked_column.Rect; + bounds.X -= h_marker; + Invalidate (bounds); return; } } @@ -1129,9 +1096,9 @@ namespace System.Windows.Forms // hit test on items // we need to take scrolling into account - hit = new Point (me.X + h_marker, me.Y + v_marker); + hit = new Point (me.X, me.Y); foreach (ListViewItem item in this.items) { - if (item.CheckRect.Contains (hit)) { + if (item.CheckRectReal.Contains (hit)) { CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked; if (item.Checked) @@ -1141,7 +1108,6 @@ namespace System.Windows.Forms CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked; - this.Redraw (false); // Raise the ItemCheck event ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, @@ -1153,25 +1119,24 @@ namespace System.Windows.Forms if (this.view == View.Details && this.FullRowSelect == false) { - if (item.LabelRect.Contains (hit)) { + if (item.GetBounds (ItemBoundsPortion.Label).Contains (hit)) { this.clicked_item = item; break; } } else { - if (item.EntireRect.Contains (hit)) { + if (item.Bounds.Contains (hit)) { this.clicked_item = item; break; } } } - // set the FocusedItem to be the current clicked_item SetFocusedItem (clicked_item); if (clicked_item != null) { bool changed = !clicked_item.Selected; - clicked_item.Selected = true; + SelectItem (clicked_item); // Only Raise the event if the selected item has changed if (changed) @@ -1183,16 +1148,12 @@ namespace System.Windows.Forms OnDoubleClick (EventArgs.Empty); else if (me.Clicks == 1 && clicked_item != null) OnClick (EventArgs.Empty); - - this.Redraw (false); } else if (selected_indices.Count > 0) { - // NOTE: selected_indices isn't computed properly so - // this doesn't actually work - // Raise the event if there was at least one item // selected and the user click on a dead area (unselecting all) + SelectedItems.Clear (); + SelectedIndices.list.Clear (); OnSelectedIndexChanged (EventArgs.Empty); - Redraw (false); } } @@ -1208,23 +1169,49 @@ namespace System.Windows.Forms ListViewItem item = this.GetItemAt (hit.X, hit.Y); if (item != null) { - item.Selected = true; + SelectItem (item); // Raise the event this.OnSelectedIndexChanged (new EventArgs ()); - - this.Redraw (false); } } private void ListView_MouseMove (object sender, MouseEventArgs me) { + if (View != View.Details || Columns.Count < 2) + return; + // Column header is always at the top. It can // scroll only horizontally. So, we have to take // only horizontal scrolling into account Point hit = new Point (me.X + h_marker, me.Y); + if (column_resize_active) { + resize_column.Width = hit.X - resize_column.X; + if (resize_column.Width < 0) + resize_column.Width = 0; + return; + } + + resize_column = null; + + for (int i = 0; i < Columns.Count; i++) { + Rectangle zone = Columns [i].Rect; + zone.X = zone.Right - 5; + zone.Width = 10; + if (zone.Contains (hit)) { + resize_column = Columns [i]; + break; + } + } + + if (resize_column == null) + Cursor = Cursors.Default; + else + Cursor = Cursors.VSplit; + // non-null clicked_col means mouse down has happened // on a column + // FIXME: this seems to be drag related if (this.clicked_column != null) { if (this.clicked_column.pressed == false && this.clicked_column.Rect.Contains (hit)) { @@ -1245,12 +1232,22 @@ namespace System.Windows.Forms if (items.Count == 0) return; + if (column_resize_active) { + Capture = false; + column_resize_active = false; + resize_column = null; + Cursor = Cursors.Default; + return; + } + Point hit = new Point (me.X, me.Y); if (this.clicked_column != null) { if (this.clicked_column.pressed) { this.clicked_column.pressed = false; - this.Redraw (false); + Rectangle bounds = clicked_column.Rect; + bounds.X -= h_marker; + Invalidate (bounds); // Raise the ColumnClick event this.OnColumnClick (new ColumnClickEventArgs @@ -1262,9 +1259,9 @@ namespace System.Windows.Forms Rectangle rect = Rectangle.Empty; if (this.clicked_item != null) { if (this.view == View.Details && !this.full_row_select) - rect = this.clicked_item.LabelRect; + rect = this.clicked_item.GetBounds (ItemBoundsPortion.Label); else - rect = this.clicked_item.EntireRect; + rect = this.clicked_item.Bounds; // We handle double click in a separate handler if (this.activation != ItemActivation.Standard && @@ -1290,8 +1287,7 @@ namespace System.Windows.Forms private void ListView_Paint (object sender, PaintEventArgs pe) { - if (this.Width <= 0 || this.Height <= 0 || - this.Visible == false || this.updating == true) + if (Width <= 0 || Height <= 0 || !Visible || updating) return; CalculateScrollBars (); @@ -1329,11 +1325,6 @@ namespace System.Windows.Forms int pixels = h_marker - h_scroll.Value; Rectangle area = client_area; - if (View == View.Details && Columns.Count > 0) { - area.Y += Columns[0].Ht; - area.Height -= Columns[0].Ht; - } - h_marker = h_scroll.Value; XplatUI.ScrollWindow (Handle, area, pixels, 0, false); } @@ -1525,37 +1516,24 @@ namespace System.Windows.Forms public void EnsureVisible (int index) { - if (index < 0 || index >= this.items.Count || this.scrollable == false) + if (index < 0 || index >= items.Count || scrollable == false) return; - // dimensions of visible area - int view_wd = client_area.Width; - int view_ht = client_area.Height; - // visible area is decided by the h_marker and v_marker - Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht); - - // an item's bounding rect - Rectangle rect = this.items [index].EntireRect; + Rectangle view_rect = new Rectangle (0, 0, client_area.Width, client_area.Height); + Rectangle bounds = items [index].Bounds; - // we don't need to do anything if item is visible. - // visible area is represented by (0,0,view_wd,view_ht) - if (view_rect.Contains (rect)) + if (view_rect.Contains (bounds)) return; - // Scroll Left or Up - if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) { - if (rect.Left < view_rect.Left) - this.h_scroll.Value -= (view_rect.Left - rect.Left); - if (rect.Top < view_rect.Top) - this.v_scroll.Value -= (view_rect.Top - rect.Top); - } - // Scroll Right or Down - else { - if (rect.Right > view_rect.Right) - this.h_scroll.Value += (rect.Right - view_rect.Right); - if (rect.Bottom > view_rect.Bottom) - this.v_scroll.Value += (rect.Bottom - view_rect.Bottom); - } + if (bounds.Left < 0) + h_scroll.Value += bounds.Left; + else if (bounds.Right > view_rect.Right) + h_scroll.Value += (bounds.Right - view_rect.Right); + + if (bounds.Top < 0) + v_scroll.Value += bounds.Top; + else if (bounds.Bottom > view_rect.Bottom) + v_scroll.Value += (bounds.Bottom - view_rect.Bottom); } public ListViewItem GetItemAt (int x, int y) @@ -2043,7 +2021,7 @@ namespace System.Windows.Forms if (list.Contains (value)) throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value"); - value.owner = this.owner; + value.Owner = owner; list [displayIndex] = value; owner.Redraw (true); @@ -2079,7 +2057,7 @@ namespace System.Windows.Forms if (list.Contains (value)) throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value"); - value.owner = this.owner; + value.Owner = owner; list.Add (value); if (owner.Sorting != SortOrder.None) @@ -2111,7 +2089,7 @@ namespace System.Windows.Forms owner.CheckedIndices.list.Clear (); foreach (ListViewItem item in values) { - item.owner = this.owner; + item.Owner = owner; list.Add (item); } @@ -2161,7 +2139,7 @@ namespace System.Windows.Forms else li = new ListViewItem (item.ToString ()); - li.owner = this.owner; + li.Owner = owner; result = list.Add (li); owner.Redraw (true); @@ -2206,7 +2184,7 @@ namespace System.Windows.Forms if (list.Contains (item)) throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item"); - item.owner = this.owner; + item.Owner = owner; list.Insert (index, item); owner.Redraw (true); return item; @@ -2411,14 +2389,10 @@ namespace System.Windows.Forms #region Public Methods public virtual void Clear () { - // mark the items as unselected before clearing the list for (int i = 0; i < list.Count; i++) - ((ListViewItem) list [i]).selected = false; + ((ListViewItem) list [i]).Selected = false; list.Clear (); - - if (owner != null) - owner.Invalidate (); } public bool Contains (ListViewItem item) diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListViewItem.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListViewItem.cs index dc223d13aef..6e5d38ef7fc 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListViewItem.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListViewItem.cs @@ -53,15 +53,13 @@ namespace System.Windows.Forms private object tag; private bool use_item_style = true; - // internal variables - internal Rectangle checkbox_rect; // calculated by CalcListViewItem method - internal Rectangle entire_rect; - internal Rectangle icon_rect; - internal Rectangle item_rect; - internal Rectangle label_rect; - internal Point location = Point.Empty; // set by the ListView control - internal ListView owner; - internal bool selected; + Rectangle bounds; + Rectangle checkbox_rect; // calculated by CalcListViewItem method + Rectangle icon_rect; + Rectangle item_rect; + Rectangle label_rect; + ListView owner; + bool selected; #endregion Instance Variables @@ -144,8 +142,9 @@ namespace System.Windows.Forms if (is_checked == value) return; + is_checked = value; + if (owner != null) { - is_checked = value; if (is_checked) { if (owner.CheckedItems.Contains (this) == false) { owner.CheckedItems.list.Add (this); @@ -157,8 +156,9 @@ namespace System.Windows.Forms owner.CheckedIndices.list.Remove (this.Index); } - owner.Invalidate (Bounds); + Layout (); } + Invalidate (); } } @@ -173,7 +173,8 @@ namespace System.Windows.Forms is_focused = value; if (owner != null) - owner.Invalidate (Bounds); + Layout (); + Invalidate (); } } @@ -196,7 +197,8 @@ namespace System.Windows.Forms sub_items[0].Font = value; if (owner != null) - owner.Invalidate (Bounds); + Layout (); + Invalidate (); } } @@ -229,7 +231,8 @@ namespace System.Windows.Forms image_index = value; if (owner != null) - owner.Invalidate (Bounds); + Layout (); + Invalidate (); } } @@ -265,27 +268,14 @@ namespace System.Windows.Forms public bool Selected { get { return selected; } set { - if (owner != null) { - if (owner.CanMultiselect == false && - owner.SelectedItems.Count > 0) { - owner.SelectedItems.Clear (); - owner.SelectedIndices.list.Clear (); - } + if (selected == value) + return; - selected = value; - if (selected) { - if (owner.SelectedItems.Contains (this) == false) { - owner.SelectedItems.list.Add (this); - owner.SelectedIndices.list.Add (this.Index); - } - } - else { - owner.SelectedItems.list.Remove (this); - owner.SelectedIndices.list.Remove (this.Index); - } - - owner.Invalidate (Bounds); - } + selected = value; + + if (owner != null) + Layout (); + Invalidate (); } } @@ -327,7 +317,16 @@ namespace System.Windows.Forms else return ""; } - set { this.sub_items [0].Text = value; } + set { + if (sub_items [0].Text == value) + return; + + sub_items [0].Text = value; + + if (owner != null) + Layout (); + Invalidate (); + } } [DefaultValue (true)] @@ -380,42 +379,34 @@ namespace System.Windows.Forms if (owner == null) return Rectangle.Empty; - /* Original Ravi's design calculated all items in a virtual space - We convert them real screen positions - */ - switch (portion) { + Rectangle rect; - case ItemBoundsPortion.Icon: { - Rectangle rect = icon_rect; - rect.X -= owner.h_marker; - rect.Y -= owner.v_marker; - return rect; - } + switch (portion) { + case ItemBoundsPortion.Icon: + rect = icon_rect; + break; - case ItemBoundsPortion.Label: { - Rectangle rect = label_rect; - rect.X -= owner.h_marker; - rect.Y -= owner.v_marker; - return rect; - } + case ItemBoundsPortion.Label: + rect = label_rect; + break; - case ItemBoundsPortion.ItemOnly: { - Rectangle rect = item_rect; - rect.X -= owner.h_marker; - rect.Y -= owner.v_marker; - return rect; - } + case ItemBoundsPortion.ItemOnly: + rect = item_rect; + break; - case ItemBoundsPortion.Entire: { - Rectangle rect = entire_rect; + case ItemBoundsPortion.Entire: + rect = bounds; rect.X -= owner.h_marker; rect.Y -= owner.v_marker; return rect; - } default: throw new ArgumentException ("Invalid value for portion."); } + + rect.X += bounds.X - owner.h_marker; + rect.Y += bounds.Y - owner.v_marker; + return rect; } void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) @@ -452,42 +443,71 @@ namespace System.Windows.Forms internal Rectangle CheckRectReal { get { Rectangle rect = checkbox_rect; - rect.X -= owner.h_marker; - rect.Y -= owner.v_marker; + rect.X += bounds.X - owner.h_marker; + rect.Y += bounds.Y - owner.v_marker; return rect; } } - internal Rectangle CheckRect { + Rectangle CheckRect { get { return this.checkbox_rect; } } - internal Rectangle EntireRect { - get { return this.entire_rect; } - } - - internal Rectangle IconRect { + Rectangle IconRect { get { return this.icon_rect; } } - internal Rectangle LabelRect { + Rectangle LabelRect { get { return this.label_rect; } } - internal void CalcListViewItem () + internal Point Location { + set { + if (bounds.X == value.X && bounds.Y == value.Y) + return; + + Rectangle prev = Bounds; + bounds.X = value.X; + bounds.Y = value.Y; + if (owner != null) { + if (prev != Rectangle.Empty) + owner.Invalidate (prev); + owner.Invalidate (Bounds); + } + } + } + + internal ListView Owner { + set { + if (owner == value) + return; + + owner = value; + if (owner != null) + Layout (); + Invalidate (); + } + } + + private void Invalidate () + { + if (owner == null) + return; + + owner.Invalidate (Bounds); + } + + internal void Layout () { int item_ht; + Rectangle total; Size text_size = owner.text_size; + checkbox_rect = Rectangle.Empty; if (owner.CheckBoxes) checkbox_rect.Size = owner.CheckBoxSize; - else - checkbox_rect = Rectangle.Empty; - - checkbox_rect.Location = this.location; switch (owner.View) { - case View.Details: // LAMESPEC: MSDN says, "In all views except the details // view of the ListView, this value specifies the same @@ -495,104 +515,85 @@ namespace System.Windows.Forms // returns same bounding rectangles for Item and Entire // values in the case of Details view. - icon_rect.X = checkbox_rect.X + checkbox_rect.Width + 2; - icon_rect.Y = checkbox_rect.Y; - - item_ht = Math.Max (owner.CheckBoxSize.Height + 1, - text_size.Height); + icon_rect = label_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Width + 2; + item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height); if (owner.SmallImageList != null) { - item_ht = Math.Max (item_ht, - owner.SmallImageList.ImageSize.Height + 1); + item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height); icon_rect.Width = owner.SmallImageList.ImageSize.Width; } - else - icon_rect.Width = 0; - label_rect.Height = checkbox_rect.Height = icon_rect.Height = item_ht; + label_rect.Height = icon_rect.Height = item_ht; + checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height - 1; - label_rect.X = icon_rect.X + icon_rect.Width; - label_rect.Y = icon_rect.Y; + label_rect.X = icon_rect.Right + 1; if (owner.Columns.Count > 0) label_rect.Width = Math.Max (text_size.Width, owner.Columns[0].Wd); else label_rect.Width = text_size.Width; - item_rect = entire_rect = Rectangle.Union + item_rect = total = Rectangle.Union (Rectangle.Union (checkbox_rect, icon_rect), label_rect); + bounds.Size = total.Size; // Take into account the rest of columns. First column // is already taken into account above. for (int i = 1; i < owner.Columns.Count; i++) { item_rect.Width += owner.Columns [i].Wd; - entire_rect.Width += owner.Columns [i].Wd; + bounds.Width += owner.Columns [i].Wd; } break; case View.LargeIcon: + label_rect = icon_rect = Rectangle.Empty; + if (owner.LargeImageList != null) { - icon_rect.Width = owner.LargeImageList.ImageSize.Width + 16; - icon_rect.Height = owner.LargeImageList.ImageSize.Height + 4; - } - else { - icon_rect.Width = 16; - icon_rect.Height = 4; + icon_rect.Width = owner.LargeImageList.ImageSize.Width; + icon_rect.Height = owner.LargeImageList.ImageSize.Height; } - if (text_size.Width <= (checkbox_rect.Width + icon_rect.Width)) { - icon_rect.X = checkbox_rect.X + checkbox_rect.Width; - icon_rect.Y = checkbox_rect.Y; + checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height - 1; - label_rect.X = icon_rect.X + (icon_rect.Width - - text_size.Width) / 2; - label_rect.Y = Math.Max (checkbox_rect.Bottom, - icon_rect.Bottom) + 2; + if (text_size.Width <= (checkbox_rect.Width + icon_rect.Width)) { + icon_rect.X = checkbox_rect.Width + 1; + label_rect.X = icon_rect.X + (icon_rect.Width - text_size.Width) / 2; + label_rect.Y = Math.Max (checkbox_rect.Bottom, icon_rect.Bottom) + 2; label_rect.Size = text_size; - } - else { - label_rect.X = this.location.X; - - int centerX = label_rect.X + text_size.Width / 2; + } else { + int centerX = text_size.Width / 2; icon_rect.X = centerX - icon_rect.Width / 2; checkbox_rect.X = (icon_rect.X - checkbox_rect.Width); - - icon_rect.Y = checkbox_rect.Y; - - label_rect.Y = Math.Max (checkbox_rect.Bottom, - icon_rect.Bottom) + 2; + label_rect.Y = Math.Max (checkbox_rect.Bottom, icon_rect.Bottom) + 2; label_rect.Size = text_size; } item_rect = Rectangle.Union (icon_rect, label_rect); - entire_rect = Rectangle.Union (item_rect, checkbox_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; break; case View.List: - goto case View.SmallIcon; - case View.SmallIcon: - icon_rect.X = checkbox_rect.X + checkbox_rect.Width; - icon_rect.Y = checkbox_rect.Y; - + label_rect = icon_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Width + 1; item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height); if (owner.SmallImageList != null) { - item_ht = Math.Max (item_ht, - owner.SmallImageList.ImageSize.Height + 1); + item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height); icon_rect.Width = owner.SmallImageList.ImageSize.Width; + icon_rect.Height = owner.SmallImageList.ImageSize.Height; } - else - icon_rect.Width = 0; - - label_rect.Height = checkbox_rect.Height = icon_rect.Height = item_ht; - label_rect.X = icon_rect.X + icon_rect.Width; - label_rect.Y = icon_rect.Y; + checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height + 1; + label_rect.X = icon_rect.Right + 1; label_rect.Width = text_size.Width; + label_rect.Height = icon_rect.Height = item_ht; item_rect = Rectangle.Union (icon_rect, label_rect); - entire_rect = Rectangle.Union (item_rect, checkbox_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; break; } diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeClearlooks.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeClearlooks.cs index 08ded7e05d8..2697229e025 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeClearlooks.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeClearlooks.cs @@ -2486,7 +2486,7 @@ namespace System.Windows.Forms { if ( control.View == View.Details ) { if ( control.FullRowSelect ) { // fill the entire rect excluding the checkbox - full_rect.Location = item.LabelRect.Location; + full_rect.Location = item.GetBounds (ItemBoundsPortion.Label).Location; dc.FillRectangle( this.ResPool.GetSolidBrush ( this.ColorHighlight ), full_rect ); } else { diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs index f3a596777c7..1dcb7cceef2 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs @@ -1428,7 +1428,7 @@ namespace System.Windows.Forms if (!details || control.Columns.Count > 0) { int first = control.FirstVisibleIndex; - for (int i = first; i <= control.LastItemIndex; i ++) { + for (int i = first; i <= control.LastVisibleIndex; i ++) { if (clip.IntersectsWith (control.Items[i].GetBounds (ItemBoundsPortion.Entire))) DrawListViewItem (dc, control, control.Items[i]); } @@ -1486,35 +1486,20 @@ namespace System.Windows.Forms dc.FillRectangle (ResPool.GetSolidBrush (control.BackColor), 0, 0, control.TotalWidth, control.Font.Height + 5); if (control.Columns.Count > 0) { - if (control.HeaderStyle == ColumnHeaderStyle.Clickable) { - foreach (ColumnHeader col in control.Columns) { - Rectangle rect = col.Rect; - rect.X -= control.h_marker; - this.CPDrawButton (dc, rect, - (col.Pressed ? - ButtonState.Pushed : - ButtonState.Normal)); - dc.DrawString (col.Text, DefaultFont, - ResPool.GetSolidBrush - (this.ColorControlText), - rect.X + 3, - rect.Y + rect.Height/2 + 1, - col.Format); - } - } - // Non-clickable columns - else { - foreach (ColumnHeader col in control.Columns) { - Rectangle rect = col.Rect; - rect.X -= control.h_marker; - this.CPDrawButton (dc, rect, ButtonState.Flat); - dc.DrawString (col.Text, DefaultFont, - ResPool.GetSolidBrush - (this.ColorControlText), - rect.X + 3, - rect.Y + rect.Height/2 + 1, - col.Format); - } + foreach (ColumnHeader col in control.Columns) { + Rectangle rect = col.Rect; + rect.X -= control.h_marker; + ButtonState state; + if (control.HeaderStyle == ColumnHeaderStyle.Clickable) + state = col.Pressed ? ButtonState.Pushed : ButtonState.Normal; + else + state = ButtonState.Flat; + this.CPDrawButton (dc, rect, state); + rect.X += 3; + rect.Width -= 8; + dc.DrawString (col.Text, DefaultFont, + ResPool.GetSolidBrush (ColorControlText), + rect, col.Format); } } } @@ -1593,7 +1578,10 @@ namespace System.Windows.Forms // draw the item text // format for the item text StringFormat format = new StringFormat (); - format.LineAlignment = StringAlignment.Center; + if (control.View == View.SmallIcon) + format.LineAlignment = StringAlignment.Near; + else + format.LineAlignment = StringAlignment.Center; if (control.View == View.LargeIcon) format.Alignment = StringAlignment.Center; else @@ -1606,7 +1594,7 @@ namespace System.Windows.Forms if (control.View == View.Details) { if (control.FullRowSelect) { // fill the entire rect excluding the checkbox - full_rect.Location = item.LabelRect.Location; + full_rect.Location = item.GetBounds (ItemBoundsPortion.Label).Location; dc.FillRectangle (this.ResPool.GetSolidBrush (this.ColorHighlight), full_rect); } @@ -1653,14 +1641,14 @@ namespace System.Windows.Forms // set the format for subitems format.FormatFlags = StringFormatFlags.NoWrap; - format.Alignment = StringAlignment.Near; // 0th subitem is the item already drawn for (int index = 1; index < count; index++) { subItem = subItems [index]; col = control.Columns [index]; - sub_item_rect.X = col.Rect.Left; - sub_item_rect.Width = col.Wd; + format.Alignment = col.Format.Alignment; + sub_item_rect.X = col.Rect.Left + 3; + sub_item_rect.Width = col.Wd - 6; sub_item_rect.X -= control.h_marker; SolidBrush sub_item_back_br = null; |