2008-02-20 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGridView.cs
index cb1058581807be5279e24b9e49267085be1e0675..0b14141eaaf71821a56457a541f3813ff64e3b4a 100644 (file)
@@ -52,14 +52,13 @@ namespace System.Windows.Forms.PropertyGridInternal {
                private PropertyGridTextBox grid_textbox;
                private PropertyGrid property_grid;
                private bool resizing_grid;
-               private int open_grid_item_count = -1;
-               private int skipped_grid_items;
                private PropertyGridDropDown dropdown_form;
                private Form dialog_form;
                private ImplicitVScrollBar vbar;
                private StringFormat string_format;
                private Font bold_font;
                private Brush inactive_text_brush;
+               private ListBox dropdown_list;
                #endregion
 
                #region Contructors
@@ -84,7 +83,6 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        dialog_form.FormBorderStyle = FormBorderStyle.None;
                        dialog_form.ShowInTaskbar = false;
 
-                       skipped_grid_items = 0;
                        row_height = Font.Height + font_height_padding;
 
                        grid_textbox.Visible = false;
@@ -97,6 +95,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                        vbar = new ImplicitVScrollBar ();
                        vbar.Visible = false;
+                       vbar.Value = 0;
                        vbar.ValueChanged+=new EventHandler (VScrollBar_HandleValueChanged);
                        vbar.Dock = DockStyle.Right;
                        this.Controls.AddImplicit (vbar);
@@ -156,10 +155,8 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                ToggleValue ((GridEntry)property_grid.SelectedGridItem);
                }
 
-               protected override void OnPaint (PaintEventArgs e) {
-                       // Decide if we need a scrollbar
-                       open_grid_item_count = 0;
-
+               protected override void OnPaint (PaintEventArgs e) 
+               {
                        // Background
                        e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
                        
@@ -177,7 +174,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        if (e.Delta < 0)
                                vbar.Value = Math.Min (vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - vbar.SmallChange);
                        else
-                               vbar.Value = Math.Max (1, vbar.Value - SystemInformation.MouseWheelScrollLines);
+                               vbar.Value = Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines);
                        base.OnMouseWheel (e);
                }
 
@@ -220,8 +217,10 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                                foundItem.Expanded = !foundItem.Expanded;
                                        
                                        this.property_grid.SelectedGridItem = foundItem;
-                                       if (!GridLabelHitTest (e.X))
-                                               FocusSelection ();
+                                       if (!GridLabelHitTest (e.X)) {
+                                               // send mouse down so we get the carret under cursor
+                                               grid_textbox.SendMouseDown (PointToScreen (e.Location));
+                                       }
                                }
                        }
                }
@@ -234,13 +233,11 @@ namespace System.Windows.Forms.PropertyGridInternal {
                protected override void OnResize (EventArgs e) {
                        base.OnResize (e);
                        if (property_grid.SelectedGridItem != null) { // initialized already
-                               SuspendLayout ();
                                UpdateView ();
                                // MS scrolls to the currently selected item on resize, even
                                // when it's not in the visible area.
                                // 
                                ScrollToItem ((GridEntry)property_grid.SelectedGridItem);
-                               ResumeLayout (false);
                        }
                }
 
@@ -280,7 +277,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                private bool TrySetEntry (GridEntry entry, object value)
                {
-                       if (entry == null)
+                       if (entry == null || grid_textbox.Text.Equals (entry.ValueText))
                                return true;
 
                        if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) ||
@@ -291,7 +288,8 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                if (!changed && error != null) {
                                        if (property_grid.ShowError (error, MessageBoxButtons.OKCancel) == DialogResult.Cancel)
                                                UpdateItem (entry); // restore value, repaint, etc
-                                       return false;
+                                       else
+                                               return false;
                                }
                        }
                        return true;
@@ -384,7 +382,8 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        return item;
                }
 
-               protected override void OnKeyDown (KeyEventArgs e) {
+               protected override void OnKeyDown (KeyEventArgs e) 
+               {
                        GridEntry selectedItem = (GridEntry)property_grid.SelectedGridItem;
 
                        if (selectedItem == null) {
@@ -526,21 +525,56 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        return null;
                }
 
-               private void UpdateScrollBar () {
-                       int visible_rows = this.ClientRectangle.Height/row_height;
-                       if (open_grid_item_count > visible_rows) {
+               private int GetVisibleItemsCount (GridEntry entry)
+               {
+                       if (entry == null)
+                               return 0;
+
+                       int count = 0;
+                       foreach (GridEntry e in entry.GridItems) {
+                               count += 1;
+                               if (e.Expandable && e.Expanded)
+                                       count += GetVisibleItemsCount (e);
+                       }
+                       return count;
+               }
+
+               private int GetVisibleRowsCount ()
+               {
+                       return this.Height / row_height;
+               }
+
+               private void UpdateScrollBar ()
+               {
+                       if (property_grid.RootGridItem == null)
+                               return;
+
+                       int visibleRows = GetVisibleRowsCount ();
+                       int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
+                       if (openedItems > visibleRows) {
                                vbar.Visible = true;
                                vbar.SmallChange = 1;
                                vbar.Minimum = 0;
-                               vbar.Maximum = open_grid_item_count-1;
-                               vbar.LargeChange = visible_rows;
-                       }
-                       else {
+                               vbar.Maximum = openedItems - 1;
+                               vbar.LargeChange = visibleRows;
+                       } else {
+                               vbar.Value = 0;
                                vbar.Visible = false;
                        }
-
+                       UpdateGridTextBoxBounds ((GridEntry)property_grid.SelectedGridItem);
                }
 
+               // private bool GetScrollBarVisible ()
+               // {
+               //      if (property_grid.RootGridItem == null)
+               //              return false;
+                // 
+               //      int visibleRows = GetVisibleRowsCount ();
+               //      int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
+               //      if (openedItems > visibleRows)
+               //              return true;
+               //      return false;
+               // }
                #region Drawing Code
 
                private void DrawGridItems (GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
@@ -590,14 +624,14 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        if (grid_item.PropertyDescriptor == null)
                                return; 
 
-                       int xLoc = SplitterLocation+1;
+                       int xLoc = SplitterLocation+ENTRY_SPACING;
                        if (grid_item.PaintValueSupported) {
                                pevent.Graphics.DrawRectangle (Pens.Black, SplitterLocation + ENTRY_SPACING, 
                                                               rect.Y + 2, VALUE_PAINT_WIDTH + 1, row_height - ENTRY_SPACING*2);
                                grid_item.PaintValue (pevent.Graphics, 
                                                      new Rectangle (SplitterLocation + ENTRY_SPACING + 1, 
                                                                     rect.Y + ENTRY_SPACING + 1,
-                                                                    VALUE_PAINT_WIDTH, row_height - (ENTRY_SPACING*2 + 1)));
+                                                                    VALUE_PAINT_WIDTH, row_height - (ENTRY_SPACING*2 +1)));
                                xLoc += VALUE_PAINT_INDENT;
                        }
 
@@ -608,8 +642,8 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        string valueText = grid_item.IsMerged && !grid_item.HasMergedValue ? String.Empty : grid_item.ValueText;
                        pevent.Graphics.DrawString (valueText, font,
                                                    brush,
-                                                   new RectangleF (xLoc, rect.Y + ENTRY_SPACING,
-                                                                   ClientRectangle.Width-(xLoc), row_height - (ENTRY_SPACING*2 + 1)), 
+                                                   new RectangleF (xLoc + ENTRY_SPACING, rect.Y + ENTRY_SPACING,
+                                                                   ClientRectangle.Width-(xLoc), row_height - ENTRY_SPACING*2), 
                                                    string_format);
                }
 
@@ -650,7 +684,6 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        }
                        grid_item.Top = yLoc;
                        yLoc += row_height;
-                       open_grid_item_count++;
                }
 
                private Rectangle DrawPlusMinus (Graphics g, int x, int y, bool expanded, bool category) {
@@ -673,12 +706,12 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        Refresh ();
                }
 
-               private void TextBoxValidating (object sender, CancelEventArgs e) 
-               {
-                       GridEntry entry = (GridEntry) property_grid.SelectedGridItem;
-                       if (entry != null && entry.IsEditable)
-                               TrySetEntry (entry, grid_textbox.Text);
-               }
+               // private void TextBoxValidating (object sender, CancelEventArgs e)
+               // {
+               //      GridEntry entry = (GridEntry) property_grid.SelectedGridItem;
+               //      if (entry != null && entry.IsEditable)
+               //              TrySetEntry (entry, grid_textbox.Text);
+               // }
 
                #endregion
 
@@ -702,6 +735,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                {
                        GridEntry entry = this.property_grid.SelectedGridItem as GridEntry;
                        if (entry != null) {
+                               grid_textbox.Text = (string) ((ListBox) sender).SelectedItem;
                                if (TrySetEntry (entry, (string) ((ListBox) sender).SelectedItem))
                                        UnfocusSelection ();
                        }
@@ -723,23 +757,25 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                else {
                                        ICollection std_values = entry.AcceptedValues;
                                        if (std_values != null) {
-                                               ListBox listBox = new ListBox ();
-                                               listBox.BorderStyle = BorderStyle.FixedSingle;
+                                               if (dropdown_list == null)
+                                                       dropdown_list = new ListBox ();
+                                               dropdown_list.Items.Clear ();
+                                               dropdown_list.BorderStyle = BorderStyle.FixedSingle;
                                                int selected_index = 0;
                                                int i = 0;
                                                foreach (object obj in std_values) {
-                                                       listBox.Items.Add (obj);
+                                                       dropdown_list.Items.Add (obj);
                                                        if (entry.ValueText != null && entry.ValueText.Equals (obj))
                                                                selected_index = i;
                                                        i++;
                                                }
-                                               listBox.Height = row_height * Math.Min (listBox.Items.Count, 15);
-                                               listBox.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0);
-                                               listBox.KeyDown += new KeyEventHandler (listBox_KeyDown);
-                                               listBox.MouseUp+=new MouseEventHandler (listBox_MouseUp);
+                                               dropdown_list.Height = row_height * Math.Min (dropdown_list.Items.Count, 15);
+                                               dropdown_list.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0);
+                                               dropdown_list.KeyDown += new KeyEventHandler (listBox_KeyDown);
+                                               dropdown_list.MouseUp+=new MouseEventHandler (listBox_MouseUp);
                                                if (std_values.Count > 0)
-                                                       listBox.SelectedIndex = selected_index;
-                                               DropDownControl (listBox);
+                                                       dropdown_list.SelectedIndex = selected_index;
+                                               DropDownControl (dropdown_list);
                                        }
                                }
                        }
@@ -754,18 +790,6 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                private void VScrollBar_HandleValueChanged (object sender, EventArgs e) 
                {
-                       if (vbar.Value <= 0)
-                               vbar.Value = 0;
-                       if (vbar.Value > vbar.Maximum-ClientRectangle.Height/row_height)
-                               vbar.Value = vbar.Maximum-ClientRectangle.Height/row_height+1;
-
-                       int scroll_amount = (skipped_grid_items-vbar.Value)*row_height;
-
-                       if (scroll_amount == 0)
-                               return;
-
-                       skipped_grid_items = vbar.Value;
-                       XplatUI.ScrollWindow (Handle, 0, scroll_amount, false);
                        UpdateView ();
                }
 
@@ -809,13 +833,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                        grid_textbox.ForeColor = SystemColors.ControlText;
                                        grid_textbox.ReadOnly = !entry.IsEditable;
                                }
-
-                               int y = -vbar.Value*row_height;
-                               CalculateItemY (entry, property_grid.RootGridItem.GridItems, ref y);
-                               int x = SplitterLocation + 1 + (entry.PaintValueSupported ? 27 : 0);
-                               grid_textbox.SetBounds (x, y + ENTRY_SPACING,
-                                                       ClientRectangle.Width - x - (vbar.Visible ? vbar.Width : 0),
-                                                       row_height - ENTRY_SPACING);
+                               UpdateGridTextBoxBounds (entry);
                                grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText;
                                grid_textbox.Visible = true;
                                InvalidateItem (entry);
@@ -825,6 +843,18 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        }
                }
 
+               private void UpdateGridTextBoxBounds (GridEntry entry)
+               {
+                       if (entry == null)
+                               return;
+                       int y = -vbar.Value*row_height;
+                       CalculateItemY (entry, property_grid.RootGridItem.GridItems, ref y);
+                       int x = SplitterLocation + ENTRY_SPACING + (entry.PaintValueSupported ? VALUE_PAINT_INDENT : 0);
+                       grid_textbox.SetBounds (x + ENTRY_SPACING, y + ENTRY_SPACING,
+                                               ClientRectangle.Width - ENTRY_SPACING - x - (vbar.Visible ? vbar.Width : 0),
+                                               row_height - ENTRY_SPACING);
+               }
+
                // Calculates the sum of the heights of all items before the one
                //
                private bool CalculateItemY (GridEntry entry, GridItemCollection items, ref int y)
@@ -852,7 +882,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                value += itemY / row_height;
                        else if (itemY + row_height > Height) // the new item is below the viewable area
                                value += ((itemY + row_height) - Height) / row_height + 1;
-                       if (value > vbar.Minimum && value < vbar.Maximum)
+                       if (value >= vbar.Minimum && value <= vbar.Maximum)
                                vbar.Value = value;
                }
 
@@ -869,6 +899,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                internal void UpdateView ()
                {
+                       UpdateScrollBar ();
                        UpdateItem ((GridEntry)property_grid.SelectedGridItem);
                        Invalidate ();
                        Update ();
@@ -876,11 +907,13 @@ namespace System.Windows.Forms.PropertyGridInternal {
 
                internal void ExpandItem (GridEntry item)
                {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
                        Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
                internal void CollapseItem (GridEntry item)
                {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
                        Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
@@ -897,6 +930,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        dropdown_form.Width = Math.Max (ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0), 
                                                        control.Width);
                        dropdown_form.Location = PointToScreen (new Point (grid_textbox.Right - control.Width, grid_textbox.Location.Y + row_height));
+                       RepositionInScreenWorkingArea (dropdown_form);
                        location = dropdown_form.Location;
 
                        owner.AddOwnedForm (dropdown_form);
@@ -933,6 +967,26 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        }
                }
 
+               private void RepositionInScreenWorkingArea (Form form)
+               {
+                       Rectangle workingArea = Screen.FromControl (form).WorkingArea;
+                       if (!workingArea.Contains (form.Bounds)) {
+                               int x, y;
+                               x = form.Location.X;
+                               y = form.Location.Y;
+
+                               if (form.Location.X < workingArea.X)
+                                       x = workingArea.X;
+
+                               if (form.Location.Y + form.Size.Height > workingArea.Height) {
+                                       Point aboveTextBox = PointToScreen (new Point (grid_textbox.Right - form.Width, grid_textbox.Location.Y));
+                                       y = aboveTextBox.Y - form.Size.Height;
+                               }
+
+                               form.Location = new Point (x, y);
+                       }
+               }
+
                private bool HwndInControl (Control c, IntPtr hwnd)
                {
                        if (hwnd == c.window.Handle)