2008-02-19 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGridView.cs
index 6c36f2826d093611b824e71a26402105b1d235c4..6966ef0a43536b82ca2e63e56be803fd9546388b 100644 (file)
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com)
 //
 // Authors:
 //      Jonathan Chambers      (jonathan.chambers@ansys.com)
+//      Ivan N. Zlatev         (contact@i-nz.net)
 //
 //
 
@@ -36,44 +37,42 @@ using System.Threading;
 using System.Windows.Forms.Design;
 
 namespace System.Windows.Forms.PropertyGridInternal {
-       internal class PropertyGridView : System.Windows.Forms.ScrollableControl, IWindowsFormsEditorService {
+       internal class PropertyGridView : ScrollableControl, IWindowsFormsEditorService {
 
                #region Private Members
-               private double splitter_percent = .5;
                private const int V_INDENT = 16;
-               private int row_height;
-               private int font_height_padding = 3;
+               private const int ENTRY_SPACING = 2;
                private const int RESIZE_WIDTH = 3;
                private const int BUTTON_WIDTH = 25;
+               private const int VALUE_PAINT_WIDTH = 19;
+               private const int VALUE_PAINT_INDENT = 27;
+               private double splitter_percent = .5;
+               private int row_height;
+               private int font_height_padding = 3;
                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;
                #endregion
 
                #region Contructors
                public PropertyGridView (PropertyGrid propertyGrid) {
                        property_grid = propertyGrid;
 
-                       property_grid.SelectedGridItemChanged+=new SelectedGridItemChangedEventHandler(HandleSelectedGridItemChanged);
-                       property_grid.PropertyValueChanged+=new PropertyValueChangedEventHandler(HandlePropertyValueChanged);
-
-                       string_format = new StringFormat();
+                       string_format = new StringFormat ();
                        string_format.FormatFlags = StringFormatFlags.NoWrap;
                        string_format.Trimming = StringTrimming.None;
 
-                       grid_textbox = new PropertyGridTextBox();
-                       grid_textbox.DropDownButtonClicked +=new EventHandler(DropDownButtonClicked);
-                       grid_textbox.DialogButtonClicked +=new EventHandler(DialogButtonClicked);
+                       grid_textbox = new PropertyGridTextBox ();
+                       grid_textbox.DropDownButtonClicked +=new EventHandler (DropDownButtonClicked);
+                       grid_textbox.DialogButtonClicked +=new EventHandler (DialogButtonClicked);
 
-                       
-                       dropdown_form = new PropertyGridDropDown();
+                       dropdown_form = new PropertyGridDropDown ();
                        dropdown_form.FormBorderStyle = FormBorderStyle.None;
                        dropdown_form.StartPosition = FormStartPosition.Manual;
                        dropdown_form.ShowInTaskbar = false;
@@ -83,101 +82,109 @@ 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;
                        grid_textbox.Font = this.Font;
-                       grid_textbox.BackColor = this.BackColor;
+                       grid_textbox.BackColor = SystemColors.Window;
                        // Not working at all, used to??
-                       grid_textbox.Validating += new CancelEventHandler(TextBoxValidating);
-                       grid_textbox.ToggleValue+=new EventHandler(grid_textbox_ToggleValue);
-                       this.Controls.Add(grid_textbox);
+                       // grid_textbox.Validating += new CancelEventHandler (TextBoxValidating);
+                       grid_textbox.ToggleValue+=new EventHandler (grid_textbox_ToggleValue);
+                       this.Controls.Add (grid_textbox);
 
-                       vbar = new ImplicitVScrollBar();
+                       vbar = new ImplicitVScrollBar ();
                        vbar.Visible = false;
-                       vbar.ValueChanged+=new EventHandler(HandleValueChanged);
+                       vbar.Value = 0;
+                       vbar.ValueChanged+=new EventHandler (VScrollBar_HandleValueChanged);
                        vbar.Dock = DockStyle.Right;
-                       this.Controls.AddImplicit(vbar);
+                       this.Controls.AddImplicit (vbar);
 
                        resizing_grid = false;
 
-                       bold_font = new Font(this.Font, FontStyle.Bold);
+                       bold_font = new Font (this.Font, FontStyle.Bold);
+                       inactive_text_brush = new SolidBrush (ThemeEngine.Current.ColorGrayText);
 
-                       ForeColorChanged+=new EventHandler(RedrawEvent);
-                       BackColorChanged+=new System.EventHandler(RedrawEvent);
-                       FontChanged+=new EventHandler(RedrawEvent);
-                       SizeChanged+=new EventHandler(RedrawEvent);
+                       ForeColorChanged+=new EventHandler (RedrawEvent);
+                       BackColorChanged+=new System.EventHandler (RedrawEvent);
+                       FontChanged+=new EventHandler (RedrawEvent);
                        
-                       SetStyle(ControlStyles.DoubleBuffer, true);
-                       SetStyle(ControlStyles.UserPaint, true);
-                       SetStyle(ControlStyles.AllPaintingInWmPaint, true);
-                       SetStyle(ControlStyles.ResizeRedraw, false);
+                       SetStyle (ControlStyles.Selectable, true);
+                       SetStyle (ControlStyles.DoubleBuffer, true);
+                       SetStyle (ControlStyles.UserPaint, true);
+                       SetStyle (ControlStyles.AllPaintingInWmPaint, true);
+                       SetStyle (ControlStyles.ResizeRedraw, true);
                }
 
                #endregion
 
                #region Protected Instance Methods
 
-               protected override void OnFontChanged(EventArgs e) {
-                       bold_font = new Font(this.Font, FontStyle.Bold);
+               protected override void OnFontChanged (EventArgs e) {
+                       base.OnFontChanged (e);
 
-                       
+                       bold_font = new Font (this.Font, FontStyle.Bold);
                        row_height = Font.Height + font_height_padding;
-                       base.OnFontChanged (e);
                }
 
-               protected override void OnDoubleClick(EventArgs e) {
-                       if (property_grid.SelectedGridItem.Expandable)
-                               property_grid.SelectedGridItem.Expanded = !property_grid.SelectedGridItem.Expanded;
-                       else 
-                               ToggleValue();
-                       Invalidate();
-                       base.OnDoubleClick (e);
+               private void InvalidateItemLabel (GridEntry item)
+               {
+                       Invalidate (new Rectangle (0, ((GridEntry)item).Top, SplitterLocation, row_height));
+               }
+
+               private void InvalidateItem (GridEntry item)
+               {
+                       if (item == null)
+                               return;
+
+                       Rectangle rect = new Rectangle (0, item.Top, Width, row_height);
+                       Invalidate (rect);
+
+                       if (item.Expanded) {
+                               rect = new Rectangle (0, item.Top + row_height, Width,
+                                                     Height - (item.Top + row_height));
+                               Invalidate (rect);
+                       }
                }
 
-               protected override void OnPaint(PaintEventArgs e) {
-                       // Decide if we need a scrollbar
-                       open_grid_item_count = 0;
+               protected override void OnDoubleClick (EventArgs e) 
+               {
+                       if (property_grid.SelectedGridItem != null && property_grid.SelectedGridItem.Expandable)
+                               property_grid.SelectedGridItem.Expanded = !property_grid.SelectedGridItem.Expanded;
+                       else
+                               ToggleValue ((GridEntry)property_grid.SelectedGridItem);
+               }
 
+               protected override void OnPaint (PaintEventArgs e) 
+               {
                        // Background
                        e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
                        
-                       // Left column
-                       e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), 0,0,V_INDENT, ClientRectangle.Height);
-                       
-
                        int yLoc = -vbar.Value*row_height;
-                       DrawGridItems(property_grid.grid_items, e, 1, ref yLoc);
+                       if (property_grid.RootGridItem != null)
+                               DrawGridItems (property_grid.RootGridItem.GridItems, e, 1, ref yLoc);
 
-                       // Grid
-                       DrawGrid(e);
-
-                       UpdateScrollBar();
-                       
-                       base.OnPaint(e);
+                       UpdateScrollBar ();
                }
 
-               protected override void OnMouseWheel(MouseEventArgs e) {
-                       if (vbar == null || !vbar.Visible) {
+               protected override void OnMouseWheel (MouseEventArgs e) 
+               {
+                       if (vbar == null || !vbar.Visible)
                                return;
-                       }
-
-                       if (e.Delta < 0) {
-                               vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum);
-                       } else {
-                               vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
-                       }
+                       if (e.Delta < 0)
+                               vbar.Value = Math.Min (vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - vbar.SmallChange);
+                       else
+                               vbar.Value = Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines);
                        base.OnMouseWheel (e);
                }
 
 
                protected override void OnMouseMove (MouseEventArgs e) {
+                       if (property_grid.RootGridItem == null)
+                               return;
 
                        if (resizing_grid) {
-                               int loc = Math.Max(e.X,2*V_INDENT);
+                               int loc = Math.Max (e.X,2*V_INDENT);
                                SplitterPercent = 1.0*loc/Width;
-                               Refresh();
                        }
                        if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) 
                                this.Cursor = Cursors.SizeWE;
@@ -186,25 +193,34 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        base.OnMouseMove (e);
                }
 
-               protected override void OnMouseDown (MouseEventArgs e) {
+               protected override void OnMouseDown (MouseEventArgs e) 
+               {
+                       base.OnMouseDown (e);
+                       if (property_grid.RootGridItem == null)
+                               return;
+
+                       if (!TrySetEntry ((GridEntry)property_grid.SelectedGridItem, grid_textbox.Text)) {
+                               FocusSelection ();
+                               return;
+                       }
+
                        if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) {
                                resizing_grid = true;
                        }
                        else {
                                int offset = -vbar.Value*row_height;
-                               GridItem foundItem = GetSelectedGridItem(property_grid.grid_items, e.Y, ref offset);
-                               
+                               GridItem foundItem = GetSelectedGridItem (property_grid.RootGridItem.GridItems, e.Y, ref offset);
+
                                if (foundItem != null) {
-                                       if (foundItem.Expandable) {
-                                               if (e.X >=3 && e.X <= 11 && (e.Y % row_height >= row_height/2-2 && e.Y % row_height <= row_height/2+4)) {
-                                                       foundItem.Expanded = !foundItem.Expanded;
-                                                       Invalidate();
-                                               }
-                                       }
+                                       if (foundItem.Expandable && ((GridEntry)foundItem).PlusMinusBounds.Contains (e.X, e.Y))
+                                               foundItem.Expanded = !foundItem.Expanded;
+                                       
                                        this.property_grid.SelectedGridItem = foundItem;
+                                       if (!GridLabelHitTest (e.X)) {
+                                               // send mouse down so we get the carret under cursor
+                                               grid_textbox.SendMouseDown (PointToScreen (e.Location));
+                                       }
                                }
-                               
-                               base.OnMouseDown (e);
                        }
                }
 
@@ -213,28 +229,286 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        base.OnMouseUp (e);
                }
 
-               protected override void OnKeyPress(KeyPressEventArgs e) {
-                       if (property_grid.SelectedGridItem.Expandable)
-                               property_grid.SelectedGridItem.Expanded = !property_grid.SelectedGridItem.Expanded;
-                       base.OnKeyPress (e);
+               protected override void OnResize (EventArgs e) {
+                       base.OnResize (e);
+                       if (property_grid.SelectedGridItem != null) { // initialized already
+                               UpdateView ();
+                               // MS scrolls to the currently selected item on resize, even
+                               // when it's not in the visible area.
+                               // 
+                               ScrollToItem ((GridEntry)property_grid.SelectedGridItem);
+                       }
+               }
+
+               private void UnfocusSelection ()
+               {
+                       Select (this);
+               }
+
+               private void FocusSelection ()
+               {
+                       Select (grid_textbox);
+               }
+
+               protected override bool ProcessDialogKey (Keys keyData) {
+                       GridEntry selectedItem = (GridEntry) property_grid.SelectedGridItem;
+                       if (selectedItem != null
+                           && grid_textbox.Visible) {
+                               switch (keyData) {
+                               case Keys.Enter:
+                                       if (TrySetEntry (selectedItem, grid_textbox.Text))
+                                               UnfocusSelection ();
+                                       return true;
+                               case Keys.Escape:
+                                       if (selectedItem.IsEditable)
+                                               UpdateItem (selectedItem); // reset value
+                                       UnfocusSelection ();
+                                       return true;
+                               case Keys.Tab:
+                                       FocusSelection ();
+                                       return true;
+                               default:
+                                       return false;
+                               }
+                       }
+                       return base.ProcessDialogKey (keyData);
+               }
+
+               private bool TrySetEntry (GridEntry entry, object value)
+               {
+                       if (entry == null || grid_textbox.Text.Equals (entry.ValueText))
+                               return true;
+
+                       if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) ||
+                           !entry.IsMerged || entry.HasMergedValue || 
+                           (!entry.HasMergedValue && grid_textbox.Text != String.Empty)) {
+                               string error = null;
+                               bool changed = entry.SetValue (value, out error);
+                               if (!changed && error != null) {
+                                       if (property_grid.ShowError (error, MessageBoxButtons.OKCancel) == DialogResult.Cancel)
+                                               UpdateItem (entry); // restore value, repaint, etc
+                                       else
+                                               return false;
+                               }
+                       }
+                       return true;
+               }
+
+               protected override bool IsInputKey (Keys keyData) {
+                       switch (keyData) {
+                       case Keys.Left:
+                       case Keys.Right:
+                       case Keys.Enter:
+                       case Keys.Escape:
+                       case Keys.Up:
+                       case Keys.Down:
+                       case Keys.PageDown:
+                       case Keys.PageUp:
+                       case Keys.Home:
+                       case Keys.End:
+                               return true;
+                       default:
+                               return false;
+                       }
+               }
+
+               private GridEntry MoveUpFromItem (GridEntry item, int up_count)
+               {
+                       GridItemCollection items;
+                       int index;
+
+                       /* move back up the visible rows (and up the hierarchy as necessary) until
+                          up_count == 0, or we reach the top of the display */
+                       while (up_count > 0) {
+                               items = item.Parent != null ? item.Parent.GridItems : property_grid.RootGridItem.GridItems;
+                               index = items.IndexOf (item);
+
+                               if (index == 0) {
+                                       if (item.Parent.GridItemType == GridItemType.Root) // we're at the top row
+                                               return item;
+                                       item = (GridEntry)item.Parent;
+                                       up_count --;
+                               }
+                               else {
+                                       GridEntry prev_item = (GridEntry)items[index-1];
+                                       if (prev_item.Expandable && prev_item.Expanded) {
+                                               item = (GridEntry)prev_item.GridItems[prev_item.GridItems.Count - 1];
+                                       }
+                                       else {
+                                               item = prev_item;
+                                       }
+                                       up_count --;
+                               }
+                       }
+                       return item;
+               }
+
+               private GridEntry MoveDownFromItem (GridEntry item, int down_count)
+               {
+                       while (down_count > 0) {
+                               /* if we're a parent node and we're expanded, move to our first child */
+                               if (item.Expandable && item.Expanded) {
+                                       item = (GridEntry)item.GridItems[0];
+                                       down_count--;
+                               }
+                               else {
+                                       GridItem searchItem = item;
+                                       GridItemCollection searchItems = searchItem.Parent.GridItems;
+                                       int searchIndex = searchItems.IndexOf (searchItem);
+
+                                       while (searchIndex == searchItems.Count - 1) {
+                                               searchItem = searchItem.Parent;
+
+                                               if (searchItem == null || searchItem.Parent == null)
+                                                       break;
+
+                                               searchItems = searchItem.Parent.GridItems;
+                                               searchIndex = searchItems.IndexOf (searchItem);
+                                       }
+
+                                       if (searchIndex == searchItems.Count - 1) {
+                                               /* if we got all the way back to the root with no nodes after
+                                                  us, the original item was the last one */
+                                               return item;
+                                       }
+                                       else {
+                                               item = (GridEntry)searchItems[searchIndex+1];
+                                               down_count--;
+                                       }
+                               }
+                       }
+
+                       return item;
+               }
+
+               protected override void OnKeyDown (KeyEventArgs e) 
+               {
+                       GridEntry selectedItem = (GridEntry)property_grid.SelectedGridItem;
+
+                       if (selectedItem == null) {
+                               /* XXX not sure what MS does, but at least we shouldn't crash */
+                               base.OnKeyDown (e);
+                               return;
+                       }
+
+                       if (!TrySetEntry (selectedItem, grid_textbox.Text)) {
+                               FocusSelection ();
+                               return;
+                       }
+
+                       switch (e.KeyData & Keys.KeyCode) {
+                       case Keys.Left:
+                               if (e.Control) {
+                                       if (SplitterLocation > 2 * V_INDENT)
+                                               SplitterPercent -= 0.01;
+
+                                       e.Handled = true;
+                                       break;
+                               }
+                               else {
+                                       /* if the node is expandable and is expanded, collapse it.
+                                          otherwise, act just like the user pressed up */
+                                       if (selectedItem.Expandable && selectedItem.Expanded) {
+                                               selectedItem.Expanded = false;
+                                               e.Handled = true;
+                                               break;
+                                       }
+                                       else
+                                               goto case Keys.Up;
+                               }
+                       case Keys.Right:
+                               if (e.Control) {
+                                       if (SplitterLocation < Width)
+                                               SplitterPercent += 0.01;
+
+                                       e.Handled = true;
+                                       break;
+                               }
+                               else {
+                                       /* if the node is expandable and not expanded, expand it.
+                                          otherwise, act just like the user pressed down */
+                                       if (selectedItem.Expandable && !selectedItem.Expanded) {
+                                               selectedItem.Expanded = true;
+                                               e.Handled = true;
+                                               break;
+                                       }
+                                       else
+                                               goto case Keys.Down;
+                               }
+                       case Keys.Enter:
+                               /* toggle the expanded state of the selected item */
+                               if (selectedItem.Expandable) {
+                                       selectedItem.Expanded = !selectedItem.Expanded;
+                               }
+                               e.Handled = true;
+                               break;
+                       case Keys.Up:
+                               property_grid.SelectedGridItem = MoveUpFromItem (selectedItem, 1);
+                               e.Handled = true;
+                               break;
+                       case Keys.Down:
+                               property_grid.SelectedGridItem = MoveDownFromItem (selectedItem, 1);
+                               e.Handled = true;
+                               break;
+                       case Keys.PageUp:
+                               property_grid.SelectedGridItem = MoveUpFromItem (selectedItem, vbar.LargeChange);
+                               e.Handled = true;
+                               break;
+                       case Keys.PageDown:
+                               property_grid.SelectedGridItem = MoveDownFromItem (selectedItem, vbar.LargeChange);
+                               e.Handled = true;
+                               break;
+                       case Keys.End:
+                               /* find the last, most deeply nested visible item */
+                               GridEntry item = (GridEntry)property_grid.RootGridItem.GridItems[property_grid.RootGridItem.GridItems.Count - 1];
+                               while (item.Expandable && item.Expanded)
+                                       item = (GridEntry)item.GridItems[item.GridItems.Count - 1];
+                               property_grid.SelectedGridItem = item;
+                               e.Handled = true;
+                               break;
+                       case Keys.Home:
+                               property_grid.SelectedGridItem = property_grid.RootGridItem.GridItems[0];
+                               e.Handled = true;
+                               break;
+                       }
+
+                       base.OnKeyDown (e);
                }
 
                #endregion
 
                #region Private Helper Methods
 
-               private int SplitterLocation{
+               private int SplitterLocation {
                        get {
                                return (int)(splitter_percent*Width);
                        }
                }
 
-               private double SplitterPercent{
+               private double SplitterPercent {
                        set {
-                               splitter_percent = Math.Max(Math.Min(value, .9),.1);
+                               int old_splitter_location = SplitterLocation;
+                               
+                               splitter_percent = Math.Max (Math.Min (value, .9),.1);
+
+                               if (old_splitter_location != SplitterLocation) {
+                                       int x = old_splitter_location > SplitterLocation ? SplitterLocation : old_splitter_location;
+                                       Invalidate (new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height));
+                                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                               }
+                       }
+                       get {
+                               return splitter_percent;
                        }
                }
 
+               private bool GridLabelHitTest (int x)
+               {
+                       if (0 <= x && x <= splitter_percent * this.Width)
+                               return true;
+                       return false;
+               }
+
                private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y, ref int current) {
                        foreach (GridItem child_grid_item in grid_items) {
                                if (y > current && y < current + row_height) {
@@ -242,7 +516,7 @@ namespace System.Windows.Forms.PropertyGridInternal {
                                }
                                current += row_height;
                                if (child_grid_item.Expanded) {
-                                       GridItem foundItem = GetSelectedGridItem(child_grid_item.GridItems, y, ref current);
+                                       GridItem foundItem = GetSelectedGridItem (child_grid_item.GridItems, y, ref current);
                                        if (foundItem != null)
                                                return foundItem;
                                }
@@ -250,179 +524,169 @@ 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 DrawGrid(PaintEventArgs pevent) {
-                       Pen pen = ThemeEngine.Current.ResPool.GetPen(property_grid.LineColor);
-                       // vertical divider line
-                       pevent.Graphics.DrawLine(pen, SplitterLocation, 0, SplitterLocation, (open_grid_item_count-skipped_grid_items)*row_height);
-                       
-                       int y = 0;
-                       while (y < ClientRectangle.Height && y/row_height + skipped_grid_items < open_grid_item_count) {
-                               // horizontal lines
-                               pevent.Graphics.DrawLine(pen, 0, y, ClientRectangle.Width, y);
-                               y += row_height;
-                       }
-               }
-
-               private void DrawGridItems(GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
+               private void DrawGridItems (GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
                        foreach (GridItem grid_item in grid_items) {
-                               DrawGridItem (grid_item, pevent, depth, ref yLoc);
+                               DrawGridItem ((GridEntry)grid_item, pevent, depth, ref yLoc);
                                if (grid_item.Expanded)
-                                       DrawGridItems(grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
+                                       DrawGridItems (grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
                        }
                }
 
-               private void DrawGridItemLabel(GridItem grid_item, PaintEventArgs pevent, Rectangle rect) {
-                       int x = rect.X+1;
-                       if (grid_item.Parent != null && grid_item.Parent.GridItemType != GridItemType.Category)
-                               x += V_INDENT;
-
+               private void DrawGridItemLabel (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) {
                        Font font = this.Font;
-                       Brush brush = SystemBrushes.WindowText;
+                       Brush brush;
+
                        if (grid_item.GridItemType == GridItemType.Category) {
                                font = bold_font;
-                               brush = SystemBrushes.ControlDark;
-                       }
+                               brush = SystemBrushes.ControlText;
 
-                       if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category) {
-                               pevent.Graphics.FillRectangle (SystemBrushes.Highlight, rect);
-                               // Label
-                               brush = SystemBrushes.HighlightText;
-                       }
-
-                       
-                       if (grid_item.GridItemType == GridItemType.Category) {
-                               pevent.Graphics.DrawString(grid_item.Label,font,brush,x, rect.Y + 2);
+                               pevent.Graphics.DrawString (grid_item.Label, font, brush, rect.X + 1, rect.Y + ENTRY_SPACING);
                                if (grid_item == property_grid.SelectedGridItem) {
-                                       SizeF size = pevent.Graphics.MeasureString(grid_item.Label, bold_font);
-                                       ControlPaint.DrawFocusRectangle(pevent.Graphics, new Rectangle(x,rect.Y+2, (int)size.Width, (int)size.Height));
+                                       SizeF size = pevent.Graphics.MeasureString (grid_item.Label, font);
+                                       ControlPaint.DrawFocusRectangle (pevent.Graphics, new Rectangle (rect.X + 1, rect.Y+ENTRY_SPACING, (int)size.Width, (int)size.Height));
                                }
                        }
-                       else
-                               pevent.Graphics.DrawString(grid_item.Label,font,brush,new Rectangle(x, rect.Y + 2,x-rect.X+rect.Width-2,rect.Height-2),string_format);
-               }
-
-               private void DrawGridItemValue(GridItem grid_item, PaintEventArgs pevent, Rectangle rect) {
-                       // Value
-                       if (grid_item.PropertyDescriptor != null) {
-
-                               bool paintsValue = false;
-                               UITypeEditor editor = null;
-                               object temp = grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
-                               editor = (UITypeEditor)temp;//grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
-                               if (editor != null) {
-                                       paintsValue = editor.GetPaintValueSupported();
-                               }
-
+                       else {
                                if (grid_item == property_grid.SelectedGridItem) {
-                                       grid_textbox.ReadOnly = false;
-                                       grid_textbox.DropDownButtonVisible = false;
-                                       grid_textbox.DialogButtonVisible = false;
-                                       if (editor != null) {
-                                               UITypeEditorEditStyle style = editor.GetEditStyle();
-                                       
-                                               switch (style) {
-                                                       case UITypeEditorEditStyle.DropDown:
-                                                               grid_textbox.DropDownButtonVisible = true;
-                                                               break;
-                                                       case UITypeEditorEditStyle.Modal:
-                                                               grid_textbox.DialogButtonVisible = true;
-                                                               break;
-                                               }
-                                       }
-                                       else {
-                                               try {
-                                                       if (grid_item.PropertyDescriptor.Converter != null) {
-                                                               if (grid_item.PropertyDescriptor.Converter.GetStandardValuesSupported()) {
-                                                       
-                                                                       grid_textbox.DropDownButtonVisible = true;
-                                                                       grid_textbox.ReadOnly = true;
-                                                               }
-                                                       }
-                                                       else {
-                                                               System.Console.WriteLine("Converter not available for type {0}",grid_item.PropertyDescriptor.PropertyType);
-                                                       }
-                                               
-                                               }
-                                               catch (Exception) {
-                                               }
+                                       Rectangle highlight = rect;
+                                       if (depth > 1) {
+                                               highlight.X -= V_INDENT;
+                                               highlight.Width += V_INDENT;
                                        }
+                                       pevent.Graphics.FillRectangle (SystemBrushes.Highlight, highlight);
+                                       // Label
+                                       brush = SystemBrushes.HighlightText;
                                }
-
-                               
-
-                               int xLoc = SplitterLocation+1;
-                               if (paintsValue) {
-                                       pevent.Graphics.DrawRectangle(Pens.Black, SplitterLocation+2,rect.Y+2, 20, row_height-4);
-                                       try {
-                                               editor.PaintValue(grid_item.Value, pevent.Graphics, new Rectangle(SplitterLocation+3,rect.Y+3, 19, row_height-5));
-                                       }
-                                       catch (Exception ex) {
-                                               System.Console.WriteLine(ex.Message);
-                                               System.Console.WriteLine("Paint Value failed for type {0}",grid_item.PropertyDescriptor.PropertyType);
-                                               // design time stuff is not playing nice
-                                       }
-                                       xLoc += 27;
+                               else {
+                                       brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
                                }
+                       }
+                       pevent.Graphics.DrawString (grid_item.Label, font, brush,
+                                                   new Rectangle (rect.X + 1, rect.Y + ENTRY_SPACING, rect.Width - ENTRY_SPACING, rect.Height - ENTRY_SPACING),
+                                                   string_format);
+               }
 
-                               Font font = this.Font;
-                               try {
-                                       if (grid_item.PropertyDescriptor.Converter != null) {
-                                               string value = grid_item.PropertyDescriptor.Converter.ConvertToString(grid_item.Value);
-                                               if (grid_item.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
-                                                       font = bold_font;
-                               
-                                               pevent.Graphics.DrawString(value,font,SystemBrushes.WindowText,new RectangleF(xLoc,rect.Y+2, ClientRectangle.Width-(xLoc), row_height),string_format);
-                                       }
-                                       else {
-                                               System.Console.WriteLine("No converter for type {0}",grid_item.PropertyDescriptor.PropertyType);
-                                       }
-
-                               }
-                               catch (Exception) {
-                               }
-                               if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category) {
-                                       grid_textbox.SetBounds(xLoc, rect.Top, ClientRectangle.Width-xLoc - (vbar.Visible ? vbar.Width: 0),row_height);
-                               }
+               private void DrawGridItemValue (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) 
+               {
+                       if (grid_item.PropertyDescriptor == null)
+                               return; 
+
+                       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)));
+                               xLoc += VALUE_PAINT_INDENT;
                        }
+
+                       Font font = this.Font;
+                       if (grid_item.IsResetable || !grid_item.HasDefaultValue)
+                               font = bold_font;
+                       Brush brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
+                       string valueText = grid_item.IsMerged && !grid_item.HasMergedValue ? String.Empty : grid_item.ValueText;
+                       pevent.Graphics.DrawString (valueText, font,
+                                                   brush,
+                                                   new RectangleF (xLoc + ENTRY_SPACING, rect.Y + ENTRY_SPACING,
+                                                                   ClientRectangle.Width-(xLoc), row_height - ENTRY_SPACING*2), 
+                                                   string_format);
                }
 
-               private void DrawGridItem (GridItem grid_item, PaintEventArgs pevent, int depth, ref int yLoc) {
+               private void DrawGridItem (GridEntry grid_item, PaintEventArgs pevent, int depth, ref int yLoc) {
                        if (yLoc > -row_height && yLoc < ClientRectangle.Height) {
-                               if (grid_item.Expandable) {
-                                       grid_item.PlusMinusBounds = DrawPlusMinus(pevent.Graphics, 3, yLoc+row_height/2-3, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
-                               }
+                               // Left column
+                               pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor),
+                                                              0, yLoc, V_INDENT, row_height);
                        
                                if (grid_item.GridItemType == GridItemType.Category) {
-                                       pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), row_height);
+                                       pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.CategoryForeColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), row_height);
+                               }
+
+                               DrawGridItemLabel (grid_item, pevent,
+                                                  depth,
+                                                 new Rectangle (depth * V_INDENT, yLoc, SplitterLocation - depth * V_INDENT, row_height));
+                               DrawGridItemValue (grid_item, pevent,
+                                                 depth,
+                                                 new Rectangle (SplitterLocation + ENTRY_SPACING , yLoc, 
+                                                                ClientRectangle.Width - SplitterLocation - ENTRY_SPACING - (vbar.Visible ? vbar.Width : 0), 
+                                                                row_height));
+
+                               if (grid_item.GridItemType != GridItemType.Category) {
+                                       Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.LineColor);
+                                       // vertical divider line
+                                       pevent.Graphics.DrawLine (pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height);
+                       
+                                       // draw the horizontal line
+                                       pevent.Graphics.DrawLine (pen, 0, yLoc + row_height, ClientRectangle.Width, yLoc + row_height);
+                               }                               
+                               
+                               if (grid_item.Expandable) {
+                                       int y = yLoc + row_height / 2 - ENTRY_SPACING + 1;
+                                       grid_item.PlusMinusBounds = DrawPlusMinus (pevent.Graphics, (depth - 1) * V_INDENT + ENTRY_SPACING + 1, 
+                                                                                  y, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
                                }
 
-                               DrawGridItemLabel(grid_item, pevent, new Rectangle(depth*V_INDENT,yLoc, SplitterLocation-depth*V_INDENT, row_height));
-                               DrawGridItemValue(grid_item, pevent, new Rectangle(SplitterLocation+2,yLoc, ClientRectangle.Width-SplitterLocation-2, row_height));
                        }
                        grid_item.Top = yLoc;
                        yLoc += row_height;
-                       open_grid_item_count++;
                }
 
                private Rectangle DrawPlusMinus (Graphics g, int x, int y, bool expanded, bool category) {
-                       Rectangle bounds = new Rectangle(x, y, 8, 8);
+                       Rectangle bounds = new Rectangle (x, y, 8, 8);
                        if (!category) g.FillRectangle (Brushes.White, bounds);
                        Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.ViewForeColor);
                        g.DrawRectangle (pen, bounds);
@@ -436,297 +700,326 @@ namespace System.Windows.Forms.PropertyGridInternal {
                #endregion
 
                #region Event Handling
-               private void RedrawEvent (object sender, System.EventArgs e) {
-                       Refresh();
+               private void RedrawEvent (object sender, System.EventArgs e) 
+               {
+                       Refresh ();
                }
 
-               private void TextBoxValidating (object sender, CancelEventArgs e) {
-                       if (this.property_grid.SelectedGridItem != null) {
-                               PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                               if (desc != null) {
-                                       try {
-                                               if (desc.Converter != null) {
-                                                       SetPropertyValue(desc.Converter.ConvertFromString(grid_textbox.Text));
-                                               }
-                                               else {
-                                                       System.Console.WriteLine("No converter for type {0}",desc.PropertyType);
-                                               }
-                                       }
-                                       catch (Exception) {
-                                               Console.WriteLine("Error converting string");
-                                       }
-                               }
-                       }
-               }
+               // private void TextBoxValidating (object sender, CancelEventArgs e)
+               // {
+               //      GridEntry entry = (GridEntry) property_grid.SelectedGridItem;
+               //      if (entry != null && entry.IsEditable)
+               //              TrySetEntry (entry, grid_textbox.Text);
+               // }
 
                #endregion
 
-               private void ToggleValue() {
-                       if (property_grid.SelectedGridItem.GridItemType == GridItemType.Property) {
-                               if (property_grid.SelectedGridItem.PropertyDescriptor != null) {
-                                       if (property_grid.SelectedGridItem.PropertyDescriptor.PropertyType == typeof(bool))
-                                               SetPropertyValue(!(bool)property_grid.SelectedGridItem.Value);
-                                       else if (property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValuesSupported()){
-                                               System.ComponentModel.TypeConverter.StandardValuesCollection coll = 
-                                                       (System.ComponentModel.TypeConverter.StandardValuesCollection)property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValues();
-                                               for (int i = 0; i < coll.Count; i++) {
-                                                       if (property_grid.SelectedGridItem.Value.Equals(coll[i])){
-                                                               if (i < coll.Count-1)
-                                                                       SetPropertyValue(coll[i+1]);
-                                                               else
-                                                                       SetPropertyValue(coll[0]);
-                                                               break;
-                                                       }
-
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               private void dropdown_form_Deactivate (object sender, EventArgs e) {
-                       dropdown_form.Hide();
-               }
-
-               private void listBox_MouseUp(object sender, MouseEventArgs e) {
+               private void listBox_MouseUp (object sender, MouseEventArgs e) {
                        AcceptListBoxSelection (sender);
                }
 
-               private void listBox_KeyDown(object sender, KeyEventArgs e)
+               private void listBox_KeyDown (object sender, KeyEventArgs e)
                {
                        switch (e.KeyData & Keys.KeyCode) {
                        case Keys.Enter:
                                AcceptListBoxSelection (sender);
                                return;
                        case Keys.Escape:
-                               dropdown_form.Hide();
+                               CloseDropDown ();
                                return;
                        }
                }
 
-               void AcceptListBoxSelection (object sender) {
-                       if (this.property_grid.SelectedGridItem != null) {
-                               PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                               if (desc != null) {
-                                       SetPropertyValue(((ListBox)sender).SelectedItem);
-                               }
+               void AcceptListBoxSelection (object sender) 
+               {
+                       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 ();
                        }
-                       dropdown_form.Hide();
-                       Refresh();
+                       CloseDropDown ();
                }
 
-               private void SetPropertyValue(object newVal) {
-                       if (this.property_grid.SelectedGridItem != null) {
-                               PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
-                               if (desc != null) {
-                                       object target = property_grid.SelectedObject;
-                                       if (property_grid.SelectedGridItem.Parent != null)
-                                               target = property_grid.SelectedGridItem.Parent.Value;
-                                       desc.SetValue(target, newVal);
-                               }
-                       }
-               }
+               private void DropDownButtonClicked (object sender, EventArgs e) 
+               {
+                       GridEntry entry = property_grid.SelectedGridItem as GridEntry;
+                       if (entry == null)
+                               return;
 
-               private void DropDownButtonClicked (object sender, EventArgs e) {
-                       UITypeEditor editor = property_grid.SelectedGridItem.PropertyDescriptor.GetEditor (typeof (UITypeEditor)) as UITypeEditor;
-                       if (editor == null) {
+                       if (entry.HasCustomEditor) {
+                               entry.EditValue ((IWindowsFormsEditorService) this);
+                       } else {
                                if (dropdown_form.Visible) {
-                                       dropdown_form.Hide ();
+                                       CloseDropDown ();
                                }
                                else {
-                                       dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
-                                       ListBox listBox = new ListBox();
-                                       listBox.BorderStyle = BorderStyle.FixedSingle;
-                                       listBox.Dock = DockStyle.Fill;
-                                       int selected_index = 0;
-                                       int i = 0;
-                                       foreach (object obj in property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValues()) {
-                                               listBox.Items.Add(obj);
-                                               if (property_grid.SelectedGridItem.Value.Equals(obj))
-                                                       selected_index = i;
-                                               i++;
+                                       ICollection std_values = entry.AcceptedValues;
+                                       if (std_values != null) {
+                                               ListBox listBox = new ListBox ();
+                                               listBox.BorderStyle = BorderStyle.FixedSingle;
+                                               int selected_index = 0;
+                                               int i = 0;
+                                               foreach (object obj in std_values) {
+                                                       listBox.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);
+                                               if (std_values.Count > 0)
+                                                       listBox.SelectedIndex = selected_index;
+                                               DropDownControl (listBox);
                                        }
-                                       listBox.SelectedIndex = selected_index;
-                                       listBox.KeyDown += new KeyEventHandler(listBox_KeyDown);
-                                       listBox.MouseUp+=new MouseEventHandler(listBox_MouseUp);
-                                       dropdown_form.Controls.Clear();
-                                       dropdown_form.Controls.Add(listBox);
-                                       dropdown_form.Location = PointToScreen(new Point(SplitterLocation,grid_textbox.Location.Y+row_height));
-                                       dropdown_form.Width = this.Width - this.SplitterLocation;
-                                       dropdown_form.ActiveControl = listBox;
-                                       dropdown_form.Show();
                                }
-                       } else { // use editor
-                               SetPropertyValueFromUITypeEditor (editor);
                        }
                }
 
-               void SetPropertyValueFromUITypeEditor (UITypeEditor editor)
+               private void DialogButtonClicked (object sender, EventArgs e) 
                {
-                       ServiceContainer service_container = new ServiceContainer ();
-                       service_container.AddService (typeof (IWindowsFormsEditorService), this);
-                       object value = editor.EditValue (
-                               new ITypeDescriptorContextImpl (this.property_grid),
-                               service_container,
-                               property_grid.SelectedGridItem.Value);
-                       SetPropertyValue (value);
-               }
-               
-               private void DialogButtonClicked(object sender, EventArgs e) {
-                       UITypeEditor editor = property_grid.SelectedGridItem.PropertyDescriptor.GetEditor (typeof (UITypeEditor)) as UITypeEditor;
-                       if (editor != null)
-                               SetPropertyValueFromUITypeEditor (editor);
+                       GridEntry entry = property_grid.SelectedGridItem as GridEntry;
+                       if (entry != null && entry.HasCustomEditor)
+                               entry.EditValue ((IWindowsFormsEditorService) this);
                }
 
-               private void 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;
-                       XplatUI.ScrollWindow(Handle, 0, scroll_amount, false);
-                       skipped_grid_items = vbar.Value;
-                       if (scroll_amount > 0)
-                               Invalidate(new Rectangle(0,0,Width,scroll_amount+1));
-                       else
-                               Invalidate(new Rectangle(0,Height+scroll_amount-1,Width,1-scroll_amount));
+               private void VScrollBar_HandleValueChanged (object sender, EventArgs e) 
+               {
+                       UpdateView ();
                }
 
-               private void grid_textbox_ToggleValue(object sender, EventArgs e) {
-                       ToggleValue();
-                       Invalidate();
+               private void grid_textbox_ToggleValue (object sender, EventArgs args) 
+               {
+                       ToggleValue ((GridEntry)property_grid.SelectedGridItem);
                }
 
-               private void HandleSelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e) {                 
-                       // Region not working correctly
-                       //Region clip = new Region();
-                       //if (property_grid.SelectedGridItem != null)
-                       //      clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, row_height));
-                       //      clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, row_height));
+               private void ToggleValue (GridEntry entry)
+               {
+                       if (entry != null && !entry.IsReadOnly && entry.GridItemType == GridItemType.Property)
+                               entry.ToggleValue ();
+               }
 
-                       if (e.NewSelection.GridItemType == GridItemType.Property)
-                               grid_textbox.Visible = true;
-                       else
+               internal void UpdateItem (GridEntry entry)
+               {
+                       if (entry == null || entry.GridItemType == GridItemType.Category || 
+                           entry.GridItemType == GridItemType.Root) {
                                grid_textbox.Visible = false;
+                               InvalidateItem (entry);
+                               return;
+                       }
 
-                       if (e.NewSelection.PropertyDescriptor != null) {
-                               grid_textbox.Text = e.NewSelection.PropertyDescriptor.Converter.ConvertToString(e.NewSelection.Value);
-                               if (e.NewSelection.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
+                       if (property_grid.SelectedGridItem == entry) {
+                               SuspendLayout ();
+                               grid_textbox.Visible = false;
+                               if (entry.IsResetable || !entry.HasDefaultValue)
                                        grid_textbox.Font = bold_font;
                                else
                                        grid_textbox.Font = this.Font;
+
+                               if (entry.IsReadOnly) {
+                                       grid_textbox.DropDownButtonVisible = false;
+                                       grid_textbox.DialogButtonVisible = false;
+                                       grid_textbox.ReadOnly = true;
+                                       grid_textbox.ForeColor = SystemColors.GrayText;
+                               } else {
+                                       grid_textbox.DropDownButtonVisible = entry.AcceptedValues != null || 
+                                               entry.EditorStyle == UITypeEditorEditStyle.DropDown;
+                                       grid_textbox.DialogButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.Modal;
+                                       grid_textbox.ForeColor = SystemColors.ControlText;
+                                       grid_textbox.ReadOnly = !entry.IsEditable;
+                               }
+                               UpdateGridTextBoxBounds (entry);
+                               grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText;
+                               grid_textbox.Visible = true;
+                               InvalidateItem (entry);
+                               ResumeLayout (false);
+                       } else {
+                               grid_textbox.Visible = false;
                        }
+               }
 
-                       Invalidate(/*clip*/this.ClientRectangle);
-                       Update();
+               private void UpdateGridTextBoxBounds (GridEntry entry)
+               {
+                       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);
                }
 
-               private void HandlePropertyValueChanged(object s, PropertyValueChangedEventArgs e) {
-                       if (e.ChangedItem.PropertyDescriptor != null) {
-                               grid_textbox.Text = e.ChangedItem.PropertyDescriptor.Converter.ConvertToString(e.ChangedItem.Value);
-                               if (e.ChangedItem.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
-                                       grid_textbox.Font = bold_font;
-                               else
-                                       grid_textbox.Font = this.Font;
+               // Calculates the sum of the heights of all items before the one
+               //
+               private bool CalculateItemY (GridEntry entry, GridItemCollection items, ref int y)
+               {
+                       foreach (GridItem item in items) {
+                               if (item == entry)
+                                       return true;
+                               y += row_height;
+                               if (item.Expandable && item.Expanded)
+                                       if (CalculateItemY (entry, item.GridItems, ref y))
+                                               return true;
                        }
+                       return false;
                }
-               
 
-               
-               #endregion
-
-               #region IWindowsFormsEditorService Members
+               private void ScrollToItem (GridEntry item)
+               {
+                       if (item == null)
+                               return;
 
-               public void CloseDropDown() {
-                       dropdown_form.Hide();
+                       int itemY = -vbar.Value*row_height;
+                       int value = vbar.Value;;
+                       CalculateItemY (item, property_grid.RootGridItem.GridItems, ref itemY);
+                       if (itemY < 0) // the new item is above the viewable area
+                               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)
+                               vbar.Value = value;
                }
 
-               public void DropDownControl(Control control) {
-                       Object  queue_id;
+               internal void SelectItem (GridEntry oldItem, GridEntry newItem) 
+               {
+                       if (oldItem != null)
+                               InvalidateItemLabel (oldItem);
+                       if (newItem != null) {
+                               UpdateItem (newItem);
+                               ScrollToItem (newItem);
+                       } else
+                               grid_textbox.Visible = false;
+               }
 
-                       dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
-                       dropdown_form.Size = control.Size;
-                       control.Dock = DockStyle.Fill;
-                       dropdown_form.Controls.Clear();
-                       dropdown_form.Controls.Add(control);
-                       dropdown_form.Location = PointToScreen(new Point(SplitterLocation,grid_textbox.Location.Y+row_height));
-                       dropdown_form.Width = Width - SplitterLocation;
+               internal void UpdateView ()
+               {
+                       UpdateScrollBar ();
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate ();
+                       Update ();
+               }
 
-                       dropdown_form.Show();
-                       System.Windows.Forms.MSG msg = new MSG();
-                       queue_id = XplatUI.StartLoop(Thread.CurrentThread);
-                       while (XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0) && dropdown_form.Visible) {
-                               XplatUI.TranslateMessage(ref msg);
-                               XplatUI.DispatchMessage(ref msg);
-                       }
+               internal void ExpandItem (GridEntry item)
+               {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
-               public System.Windows.Forms.DialogResult ShowDialog(Form dialog) {
-                       return dialog.ShowDialog(this);
+               internal void CollapseItem (GridEntry item)
+               {
+                       UpdateItem ((GridEntry)property_grid.SelectedGridItem);
+                       Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
                }
 
-               #endregion
+               private void ShowDropDownControl (Control control, bool block) 
+               {
+                       Object  queue_id;
 
-               #region Internal Classes
-               internal class ITypeDescriptorContextImpl : System.ComponentModel.ITypeDescriptorContext {
-                       private PropertyGrid property_grid;
-                       public ITypeDescriptorContextImpl(PropertyGrid propertyGrid) {
-                               property_grid = propertyGrid;
-                       }
-                       #region ITypeDescriptorContext Members
+                       Form owner = FindForm ();
 
-                       public void OnComponentChanged() {
-                               // TODO:  Add SystemComp.OnComponentChanged implementation
-                       }
+                       Point location;
+                       dropdown_form.Size = control.Size;
+                       control.Dock = DockStyle.Fill;
+                       dropdown_form.Controls.Add (control);
+                       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;
 
-                       public IContainer Container {
-                               get {
-                                       return property_grid as IContainer;
-                               }
-                       }
+                       owner.AddOwnedForm (dropdown_form);
 
-                       public bool OnComponentChanging() {
-                               // TODO:  Add SystemComp.OnComponentChanging implementation
-                               return false;
-                       }
+                       dropdown_form.Show ();
 
-                       public object Instance {
-                               get {
-                                       return property_grid.SelectedGridItem.Value;
+                       if (dropdown_form.Location != location) {
+                               dropdown_form.Location = location;
+                       }
+                       if (block) {
+                               System.Windows.Forms.MSG msg = new MSG ();
+                               queue_id = XplatUI.StartLoop (Thread.CurrentThread);
+                               while (dropdown_form.Visible && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) {
+                                       switch (msg.message) {
+                                               case Msg.WM_NCLBUTTONDOWN:
+                                           case Msg.WM_NCMBUTTONDOWN:
+                                           case Msg.WM_NCRBUTTONDOWN:
+                                           case Msg.WM_LBUTTONDOWN:
+                                           case Msg.WM_MBUTTONDOWN:
+                                           case Msg.WM_RBUTTONDOWN:
+                                               if (!HwndInControl (dropdown_form, msg.hwnd))
+                                                               CloseDropDown ();
+                                               break;
+                                               case Msg.WM_ACTIVATE:
+                                               case Msg.WM_NCPAINT:
+                                                       if (owner.window.Handle == msg.hwnd)
+                                                               CloseDropDown ();
+                                               break;                                          
+                                       }
+                                       XplatUI.TranslateMessage (ref msg);
+                                       XplatUI.DispatchMessage (ref msg);
                                }
+                               XplatUI.EndLoop (Thread.CurrentThread);                 
                        }
+               }
 
-                       public PropertyDescriptor PropertyDescriptor {
-                               get {
-                                       return property_grid.SelectedGridItem.PropertyDescriptor;
+               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);
                        }
+               }
 
-                       #endregion
+               private bool HwndInControl (Control c, IntPtr hwnd)
+               {
+                       if (hwnd == c.window.Handle)
+                               return true;
+                       foreach (Control cc in c.Controls.GetAllControls ()) {
+                               if (HwndInControl (cc, hwnd))
+                                       return true;
+                       }
+                       return false;
+               }
+               #endregion
 
-                       #region IServiceProvider Members
+               #region IWindowsFormsEditorService Members
 
-                       public object GetService(Type serviceType) {
-                               // TODO:  Add SystemComp.GetService implementation
-                               return null;
-                       }
+               public void CloseDropDown () {
+                       Control c = dropdown_form.Controls[0];
+                       c.Capture = false;
+                       dropdown_form.Hide ();
+                       dropdown_form.Controls.Clear ();
+               }
 
-                       #endregion
+               public void DropDownControl (Control control) {
+                       ShowDropDownControl (control, true);
+               }
 
+               public System.Windows.Forms.DialogResult ShowDialog (Form dialog) {
+                       return dialog.ShowDialog (this);
                }
 
+               #endregion
 
-               
                /*
                        class ComboListBox
                */
                internal class PropertyGridDropDown : Form {
                        protected override CreateParams CreateParams {
                                get {
-                                       CreateParams cp = base.CreateParams;                            
+                                       CreateParams cp = base.CreateParams;
                                        cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN));
                                        cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);                            
                                        return cp;
@@ -734,7 +1027,5 @@ namespace System.Windows.Forms.PropertyGridInternal {
                        }
 
                }
-
-               #endregion
        }
 }