1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com)
23 // Jonathan Chambers (jonathan.chambers@ansys.com)
24 // Ivan N. Zlatev (contact@i-nz.net)
31 using System.Collections;
32 using System.ComponentModel.Design;
34 using System.Drawing.Design;
35 using System.ComponentModel;
36 using System.Threading;
37 using System.Windows.Forms.Design;
39 namespace System.Windows.Forms.PropertyGridInternal {
40 internal class PropertyGridView : ScrollableControl, IWindowsFormsEditorService {
42 #region Private Members
43 private const int V_INDENT = 16;
44 private const int ENTRY_SPACING = 2;
45 private const int RESIZE_WIDTH = 3;
46 private const int BUTTON_WIDTH = 25;
47 private const int VALUE_PAINT_WIDTH = 19;
48 private const int VALUE_PAINT_INDENT = 27;
49 private double splitter_percent = .5;
50 private int row_height;
51 private int font_height_padding = 3;
52 private PropertyGridTextBox grid_textbox;
53 private PropertyGrid property_grid;
54 private bool resizing_grid;
55 private PropertyGridDropDown dropdown_form;
56 private Form dialog_form;
57 private ImplicitVScrollBar vbar;
58 private StringFormat string_format;
59 private Font bold_font;
60 private Brush inactive_text_brush;
64 public PropertyGridView (PropertyGrid propertyGrid) {
65 property_grid = propertyGrid;
67 string_format = new StringFormat ();
68 string_format.FormatFlags = StringFormatFlags.NoWrap;
69 string_format.Trimming = StringTrimming.None;
71 grid_textbox = new PropertyGridTextBox ();
72 grid_textbox.DropDownButtonClicked +=new EventHandler (DropDownButtonClicked);
73 grid_textbox.DialogButtonClicked +=new EventHandler (DialogButtonClicked);
75 dropdown_form = new PropertyGridDropDown ();
76 dropdown_form.FormBorderStyle = FormBorderStyle.None;
77 dropdown_form.StartPosition = FormStartPosition.Manual;
78 dropdown_form.ShowInTaskbar = false;
80 dialog_form = new Form ();
81 dialog_form.StartPosition = FormStartPosition.Manual;
82 dialog_form.FormBorderStyle = FormBorderStyle.None;
83 dialog_form.ShowInTaskbar = false;
85 row_height = Font.Height + font_height_padding;
87 grid_textbox.Visible = false;
88 grid_textbox.Font = this.Font;
89 grid_textbox.BackColor = SystemColors.Window;
90 // Not working at all, used to??
91 // grid_textbox.Validating += new CancelEventHandler (TextBoxValidating);
92 grid_textbox.ToggleValue+=new EventHandler (grid_textbox_ToggleValue);
93 this.Controls.Add (grid_textbox);
95 vbar = new ImplicitVScrollBar ();
98 vbar.ValueChanged+=new EventHandler (VScrollBar_HandleValueChanged);
99 vbar.Dock = DockStyle.Right;
100 this.Controls.AddImplicit (vbar);
102 resizing_grid = false;
104 bold_font = new Font (this.Font, FontStyle.Bold);
105 inactive_text_brush = new SolidBrush (ThemeEngine.Current.ColorGrayText);
107 ForeColorChanged+=new EventHandler (RedrawEvent);
108 BackColorChanged+=new System.EventHandler (RedrawEvent);
109 FontChanged+=new EventHandler (RedrawEvent);
111 SetStyle (ControlStyles.Selectable, true);
112 SetStyle (ControlStyles.DoubleBuffer, true);
113 SetStyle (ControlStyles.UserPaint, true);
114 SetStyle (ControlStyles.AllPaintingInWmPaint, true);
115 SetStyle (ControlStyles.ResizeRedraw, true);
120 #region Protected Instance Methods
122 protected override void OnFontChanged (EventArgs e) {
123 base.OnFontChanged (e);
125 bold_font = new Font (this.Font, FontStyle.Bold);
126 row_height = Font.Height + font_height_padding;
129 private void InvalidateItemLabel (GridEntry item)
131 Invalidate (new Rectangle (0, ((GridEntry)item).Top, SplitterLocation, row_height));
134 private void InvalidateItem (GridEntry item)
139 Rectangle rect = new Rectangle (0, item.Top, Width, row_height);
143 rect = new Rectangle (0, item.Top + row_height, Width,
144 Height - (item.Top + row_height));
149 protected override void OnDoubleClick (EventArgs e)
151 if (property_grid.SelectedGridItem != null && property_grid.SelectedGridItem.Expandable)
152 property_grid.SelectedGridItem.Expanded = !property_grid.SelectedGridItem.Expanded;
154 ToggleValue ((GridEntry)property_grid.SelectedGridItem);
157 protected override void OnPaint (PaintEventArgs e)
160 e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
162 int yLoc = -vbar.Value*row_height;
163 if (property_grid.RootGridItem != null)
164 DrawGridItems (property_grid.RootGridItem.GridItems, e, 1, ref yLoc);
169 protected override void OnMouseWheel (MouseEventArgs e)
171 if (vbar == null || !vbar.Visible)
174 vbar.Value = Math.Min (vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - vbar.SmallChange);
176 vbar.Value = Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines);
177 base.OnMouseWheel (e);
181 protected override void OnMouseMove (MouseEventArgs e) {
182 if (property_grid.RootGridItem == null)
186 int loc = Math.Max (e.X,2*V_INDENT);
187 SplitterPercent = 1.0*loc/Width;
189 if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH)
190 this.Cursor = Cursors.SizeWE;
192 this.Cursor = Cursors.Default;
193 base.OnMouseMove (e);
196 protected override void OnMouseDown (MouseEventArgs e)
198 base.OnMouseDown (e);
199 if (property_grid.RootGridItem == null)
202 if (!TrySetEntry ((GridEntry)property_grid.SelectedGridItem, grid_textbox.Text)) {
207 if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) {
208 resizing_grid = true;
211 int offset = -vbar.Value*row_height;
212 GridItem foundItem = GetSelectedGridItem (property_grid.RootGridItem.GridItems, e.Y, ref offset);
214 if (foundItem != null) {
215 if (foundItem.Expandable && ((GridEntry)foundItem).PlusMinusBounds.Contains (e.X, e.Y))
216 foundItem.Expanded = !foundItem.Expanded;
218 this.property_grid.SelectedGridItem = foundItem;
219 if (!GridLabelHitTest (e.X)) {
220 // send mouse down so we get the carret under cursor
221 grid_textbox.SendMouseDown (PointToScreen (e.Location));
227 protected override void OnMouseUp (MouseEventArgs e) {
228 resizing_grid = false;
232 protected override void OnResize (EventArgs e) {
234 if (property_grid.SelectedGridItem != null) { // initialized already
236 // MS scrolls to the currently selected item on resize, even
237 // when it's not in the visible area.
239 ScrollToItem ((GridEntry)property_grid.SelectedGridItem);
243 private void UnfocusSelection ()
248 private void FocusSelection ()
250 Select (grid_textbox);
253 protected override bool ProcessDialogKey (Keys keyData) {
254 GridEntry selectedItem = (GridEntry) property_grid.SelectedGridItem;
255 if (selectedItem != null
256 && grid_textbox.Visible) {
259 if (TrySetEntry (selectedItem, grid_textbox.Text))
263 if (selectedItem.IsEditable)
264 UpdateItem (selectedItem); // reset value
274 return base.ProcessDialogKey (keyData);
277 private bool TrySetEntry (GridEntry entry, object value)
279 if (entry == null || grid_textbox.Text.Equals (entry.ValueText))
282 if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) ||
283 !entry.IsMerged || entry.HasMergedValue ||
284 (!entry.HasMergedValue && grid_textbox.Text != String.Empty)) {
286 bool changed = entry.SetValue (value, out error);
287 if (!changed && error != null) {
288 if (property_grid.ShowError (error, MessageBoxButtons.OKCancel) == DialogResult.Cancel)
289 UpdateItem (entry); // restore value, repaint, etc
297 protected override bool IsInputKey (Keys keyData) {
315 private GridEntry MoveUpFromItem (GridEntry item, int up_count)
317 GridItemCollection items;
320 /* move back up the visible rows (and up the hierarchy as necessary) until
321 up_count == 0, or we reach the top of the display */
322 while (up_count > 0) {
323 items = item.Parent != null ? item.Parent.GridItems : property_grid.RootGridItem.GridItems;
324 index = items.IndexOf (item);
327 if (item.Parent.GridItemType == GridItemType.Root) // we're at the top row
329 item = (GridEntry)item.Parent;
333 GridEntry prev_item = (GridEntry)items[index-1];
334 if (prev_item.Expandable && prev_item.Expanded) {
335 item = (GridEntry)prev_item.GridItems[prev_item.GridItems.Count - 1];
346 private GridEntry MoveDownFromItem (GridEntry item, int down_count)
348 while (down_count > 0) {
349 /* if we're a parent node and we're expanded, move to our first child */
350 if (item.Expandable && item.Expanded) {
351 item = (GridEntry)item.GridItems[0];
355 GridItem searchItem = item;
356 GridItemCollection searchItems = searchItem.Parent.GridItems;
357 int searchIndex = searchItems.IndexOf (searchItem);
359 while (searchIndex == searchItems.Count - 1) {
360 searchItem = searchItem.Parent;
362 if (searchItem == null || searchItem.Parent == null)
365 searchItems = searchItem.Parent.GridItems;
366 searchIndex = searchItems.IndexOf (searchItem);
369 if (searchIndex == searchItems.Count - 1) {
370 /* if we got all the way back to the root with no nodes after
371 us, the original item was the last one */
375 item = (GridEntry)searchItems[searchIndex+1];
384 protected override void OnKeyDown (KeyEventArgs e)
386 GridEntry selectedItem = (GridEntry)property_grid.SelectedGridItem;
388 if (selectedItem == null) {
389 /* XXX not sure what MS does, but at least we shouldn't crash */
394 if (!TrySetEntry (selectedItem, grid_textbox.Text)) {
399 switch (e.KeyData & Keys.KeyCode) {
402 if (SplitterLocation > 2 * V_INDENT)
403 SplitterPercent -= 0.01;
409 /* if the node is expandable and is expanded, collapse it.
410 otherwise, act just like the user pressed up */
411 if (selectedItem.Expandable && selectedItem.Expanded) {
412 selectedItem.Expanded = false;
421 if (SplitterLocation < Width)
422 SplitterPercent += 0.01;
428 /* if the node is expandable and not expanded, expand it.
429 otherwise, act just like the user pressed down */
430 if (selectedItem.Expandable && !selectedItem.Expanded) {
431 selectedItem.Expanded = true;
439 /* toggle the expanded state of the selected item */
440 if (selectedItem.Expandable) {
441 selectedItem.Expanded = !selectedItem.Expanded;
446 property_grid.SelectedGridItem = MoveUpFromItem (selectedItem, 1);
450 property_grid.SelectedGridItem = MoveDownFromItem (selectedItem, 1);
454 property_grid.SelectedGridItem = MoveUpFromItem (selectedItem, vbar.LargeChange);
458 property_grid.SelectedGridItem = MoveDownFromItem (selectedItem, vbar.LargeChange);
462 /* find the last, most deeply nested visible item */
463 GridEntry item = (GridEntry)property_grid.RootGridItem.GridItems[property_grid.RootGridItem.GridItems.Count - 1];
464 while (item.Expandable && item.Expanded)
465 item = (GridEntry)item.GridItems[item.GridItems.Count - 1];
466 property_grid.SelectedGridItem = item;
470 property_grid.SelectedGridItem = property_grid.RootGridItem.GridItems[0];
480 #region Private Helper Methods
482 private int SplitterLocation {
484 return (int)(splitter_percent*Width);
488 private double SplitterPercent {
490 int old_splitter_location = SplitterLocation;
492 splitter_percent = Math.Max (Math.Min (value, .9),.1);
494 if (old_splitter_location != SplitterLocation) {
495 int x = old_splitter_location > SplitterLocation ? SplitterLocation : old_splitter_location;
496 Invalidate (new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height));
497 UpdateItem ((GridEntry)property_grid.SelectedGridItem);
501 return splitter_percent;
505 private bool GridLabelHitTest (int x)
507 if (0 <= x && x <= splitter_percent * this.Width)
512 private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y, ref int current) {
513 foreach (GridItem child_grid_item in grid_items) {
514 if (y > current && y < current + row_height) {
515 return child_grid_item;
517 current += row_height;
518 if (child_grid_item.Expanded) {
519 GridItem foundItem = GetSelectedGridItem (child_grid_item.GridItems, y, ref current);
520 if (foundItem != null)
527 private int GetVisibleItemsCount (GridEntry entry)
533 foreach (GridEntry e in entry.GridItems) {
535 if (e.Expandable && e.Expanded)
536 count += GetVisibleItemsCount (e);
541 private int GetVisibleRowsCount ()
543 return this.Height / row_height;
546 private void UpdateScrollBar ()
548 if (property_grid.RootGridItem == null)
551 int visibleRows = GetVisibleRowsCount ();
552 int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
553 if (openedItems > visibleRows) {
555 vbar.SmallChange = 1;
557 vbar.Maximum = openedItems - 1;
558 vbar.LargeChange = visibleRows;
561 vbar.Visible = false;
563 UpdateGridTextBoxBounds ((GridEntry)property_grid.SelectedGridItem);
566 // private bool GetScrollBarVisible ()
568 // if (property_grid.RootGridItem == null)
571 // int visibleRows = GetVisibleRowsCount ();
572 // int openedItems = GetVisibleItemsCount ((GridEntry)property_grid.RootGridItem);
573 // if (openedItems > visibleRows)
579 private void DrawGridItems (GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) {
580 foreach (GridItem grid_item in grid_items) {
581 DrawGridItem ((GridEntry)grid_item, pevent, depth, ref yLoc);
582 if (grid_item.Expanded)
583 DrawGridItems (grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
587 private void DrawGridItemLabel (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) {
588 Font font = this.Font;
591 if (grid_item.GridItemType == GridItemType.Category) {
593 brush = SystemBrushes.ControlText;
595 pevent.Graphics.DrawString (grid_item.Label, font, brush, rect.X + 1, rect.Y + ENTRY_SPACING);
596 if (grid_item == property_grid.SelectedGridItem) {
597 SizeF size = pevent.Graphics.MeasureString (grid_item.Label, font);
598 ControlPaint.DrawFocusRectangle (pevent.Graphics, new Rectangle (rect.X + 1, rect.Y+ENTRY_SPACING, (int)size.Width, (int)size.Height));
602 if (grid_item == property_grid.SelectedGridItem) {
603 Rectangle highlight = rect;
605 highlight.X -= V_INDENT;
606 highlight.Width += V_INDENT;
608 pevent.Graphics.FillRectangle (SystemBrushes.Highlight, highlight);
610 brush = SystemBrushes.HighlightText;
613 brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
616 pevent.Graphics.DrawString (grid_item.Label, font, brush,
617 new Rectangle (rect.X + 1, rect.Y + ENTRY_SPACING, rect.Width - ENTRY_SPACING, rect.Height - ENTRY_SPACING),
621 private void DrawGridItemValue (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect)
623 if (grid_item.PropertyDescriptor == null)
626 int xLoc = SplitterLocation+ENTRY_SPACING;
627 if (grid_item.PaintValueSupported) {
628 pevent.Graphics.DrawRectangle (Pens.Black, SplitterLocation + ENTRY_SPACING,
629 rect.Y + 2, VALUE_PAINT_WIDTH + 1, row_height - ENTRY_SPACING*2);
630 grid_item.PaintValue (pevent.Graphics,
631 new Rectangle (SplitterLocation + ENTRY_SPACING + 1,
632 rect.Y + ENTRY_SPACING + 1,
633 VALUE_PAINT_WIDTH, row_height - (ENTRY_SPACING*2 +1)));
634 xLoc += VALUE_PAINT_INDENT;
637 Font font = this.Font;
638 if (grid_item.IsResetable || !grid_item.HasDefaultValue)
640 Brush brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText;
641 string valueText = grid_item.IsMerged && !grid_item.HasMergedValue ? String.Empty : grid_item.ValueText;
642 pevent.Graphics.DrawString (valueText, font,
644 new RectangleF (xLoc + ENTRY_SPACING, rect.Y + ENTRY_SPACING,
645 ClientRectangle.Width-(xLoc), row_height - ENTRY_SPACING*2),
649 private void DrawGridItem (GridEntry grid_item, PaintEventArgs pevent, int depth, ref int yLoc) {
650 if (yLoc > -row_height && yLoc < ClientRectangle.Height) {
652 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor),
653 0, yLoc, V_INDENT, row_height);
655 if (grid_item.GridItemType == GridItemType.Category) {
656 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.CategoryForeColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), row_height);
659 DrawGridItemLabel (grid_item, pevent,
661 new Rectangle (depth * V_INDENT, yLoc, SplitterLocation - depth * V_INDENT, row_height));
662 DrawGridItemValue (grid_item, pevent,
664 new Rectangle (SplitterLocation + ENTRY_SPACING , yLoc,
665 ClientRectangle.Width - SplitterLocation - ENTRY_SPACING - (vbar.Visible ? vbar.Width : 0),
668 if (grid_item.GridItemType != GridItemType.Category) {
669 Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.LineColor);
670 // vertical divider line
671 pevent.Graphics.DrawLine (pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height);
673 // draw the horizontal line
674 pevent.Graphics.DrawLine (pen, 0, yLoc + row_height, ClientRectangle.Width, yLoc + row_height);
677 if (grid_item.Expandable) {
678 int y = yLoc + row_height / 2 - ENTRY_SPACING + 1;
679 grid_item.PlusMinusBounds = DrawPlusMinus (pevent.Graphics, (depth - 1) * V_INDENT + ENTRY_SPACING + 1,
680 y, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
684 grid_item.Top = yLoc;
688 private Rectangle DrawPlusMinus (Graphics g, int x, int y, bool expanded, bool category) {
689 Rectangle bounds = new Rectangle (x, y, 8, 8);
690 if (!category) g.FillRectangle (Brushes.White, bounds);
691 Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.ViewForeColor);
692 g.DrawRectangle (pen, bounds);
693 g.DrawLine (pen, x+2, y+4, x + 6, y+4);
695 g.DrawLine (pen, x+4, y+2, x+4, y+6);
702 #region Event Handling
703 private void RedrawEvent (object sender, System.EventArgs e)
708 // private void TextBoxValidating (object sender, CancelEventArgs e)
710 // GridEntry entry = (GridEntry) property_grid.SelectedGridItem;
711 // if (entry != null && entry.IsEditable)
712 // TrySetEntry (entry, grid_textbox.Text);
717 private void listBox_MouseUp (object sender, MouseEventArgs e) {
718 AcceptListBoxSelection (sender);
721 private void listBox_KeyDown (object sender, KeyEventArgs e)
723 switch (e.KeyData & Keys.KeyCode) {
725 AcceptListBoxSelection (sender);
733 void AcceptListBoxSelection (object sender)
735 GridEntry entry = this.property_grid.SelectedGridItem as GridEntry;
737 grid_textbox.Text = (string) ((ListBox) sender).SelectedItem;
738 if (TrySetEntry (entry, (string) ((ListBox) sender).SelectedItem))
744 private void DropDownButtonClicked (object sender, EventArgs e)
746 GridEntry entry = property_grid.SelectedGridItem as GridEntry;
750 if (entry.HasCustomEditor) {
751 entry.EditValue ((IWindowsFormsEditorService) this);
753 if (dropdown_form.Visible) {
757 ICollection std_values = entry.AcceptedValues;
758 if (std_values != null) {
759 ListBox listBox = new ListBox ();
760 listBox.BorderStyle = BorderStyle.FixedSingle;
761 int selected_index = 0;
763 foreach (object obj in std_values) {
764 listBox.Items.Add (obj);
765 if (entry.ValueText != null && entry.ValueText.Equals (obj))
769 listBox.Height = row_height * Math.Min (listBox.Items.Count, 15);
770 listBox.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0);
771 listBox.KeyDown += new KeyEventHandler (listBox_KeyDown);
772 listBox.MouseUp+=new MouseEventHandler (listBox_MouseUp);
773 if (std_values.Count > 0)
774 listBox.SelectedIndex = selected_index;
775 DropDownControl (listBox);
781 private void DialogButtonClicked (object sender, EventArgs e)
783 GridEntry entry = property_grid.SelectedGridItem as GridEntry;
784 if (entry != null && entry.HasCustomEditor)
785 entry.EditValue ((IWindowsFormsEditorService) this);
788 private void VScrollBar_HandleValueChanged (object sender, EventArgs e)
793 private void grid_textbox_ToggleValue (object sender, EventArgs args)
795 ToggleValue ((GridEntry)property_grid.SelectedGridItem);
798 private void ToggleValue (GridEntry entry)
800 if (entry != null && !entry.IsReadOnly && entry.GridItemType == GridItemType.Property)
801 entry.ToggleValue ();
804 internal void UpdateItem (GridEntry entry)
806 if (entry == null || entry.GridItemType == GridItemType.Category ||
807 entry.GridItemType == GridItemType.Root) {
808 grid_textbox.Visible = false;
809 InvalidateItem (entry);
813 if (property_grid.SelectedGridItem == entry) {
815 grid_textbox.Visible = false;
816 if (entry.IsResetable || !entry.HasDefaultValue)
817 grid_textbox.Font = bold_font;
819 grid_textbox.Font = this.Font;
821 if (entry.IsReadOnly) {
822 grid_textbox.DropDownButtonVisible = false;
823 grid_textbox.DialogButtonVisible = false;
824 grid_textbox.ReadOnly = true;
825 grid_textbox.ForeColor = SystemColors.GrayText;
827 grid_textbox.DropDownButtonVisible = entry.AcceptedValues != null ||
828 entry.EditorStyle == UITypeEditorEditStyle.DropDown;
829 grid_textbox.DialogButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.Modal;
830 grid_textbox.ForeColor = SystemColors.ControlText;
831 grid_textbox.ReadOnly = !entry.IsEditable;
833 UpdateGridTextBoxBounds (entry);
834 grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText;
835 grid_textbox.Visible = true;
836 InvalidateItem (entry);
837 ResumeLayout (false);
839 grid_textbox.Visible = false;
843 private void UpdateGridTextBoxBounds (GridEntry entry)
845 int y = -vbar.Value*row_height;
846 CalculateItemY (entry, property_grid.RootGridItem.GridItems, ref y);
847 int x = SplitterLocation + ENTRY_SPACING + (entry.PaintValueSupported ? VALUE_PAINT_INDENT : 0);
848 grid_textbox.SetBounds (x + ENTRY_SPACING, y + ENTRY_SPACING,
849 ClientRectangle.Width - ENTRY_SPACING - x - (vbar.Visible ? vbar.Width : 0),
850 row_height - ENTRY_SPACING);
853 // Calculates the sum of the heights of all items before the one
855 private bool CalculateItemY (GridEntry entry, GridItemCollection items, ref int y)
857 foreach (GridItem item in items) {
861 if (item.Expandable && item.Expanded)
862 if (CalculateItemY (entry, item.GridItems, ref y))
868 private void ScrollToItem (GridEntry item)
873 int itemY = -vbar.Value*row_height;
874 int value = vbar.Value;;
875 CalculateItemY (item, property_grid.RootGridItem.GridItems, ref itemY);
876 if (itemY < 0) // the new item is above the viewable area
877 value += itemY / row_height;
878 else if (itemY + row_height > Height) // the new item is below the viewable area
879 value += ((itemY + row_height) - Height) / row_height + 1;
880 if (value >= vbar.Minimum && value <= vbar.Maximum)
884 internal void SelectItem (GridEntry oldItem, GridEntry newItem)
887 InvalidateItemLabel (oldItem);
888 if (newItem != null) {
889 UpdateItem (newItem);
890 ScrollToItem (newItem);
892 grid_textbox.Visible = false;
895 internal void UpdateView ()
898 UpdateItem ((GridEntry)property_grid.SelectedGridItem);
903 internal void ExpandItem (GridEntry item)
905 UpdateItem ((GridEntry)property_grid.SelectedGridItem);
906 Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
909 internal void CollapseItem (GridEntry item)
911 UpdateItem ((GridEntry)property_grid.SelectedGridItem);
912 Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top));
915 private void ShowDropDownControl (Control control, bool block)
919 Form owner = FindForm ();
922 dropdown_form.Size = control.Size;
923 control.Dock = DockStyle.Fill;
924 dropdown_form.Controls.Add (control);
925 dropdown_form.Width = Math.Max (ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0),
927 dropdown_form.Location = PointToScreen (new Point (grid_textbox.Right - control.Width, grid_textbox.Location.Y + row_height));
928 RepositionInScreenWorkingArea (dropdown_form);
929 location = dropdown_form.Location;
931 owner.AddOwnedForm (dropdown_form);
933 dropdown_form.Show ();
935 if (dropdown_form.Location != location) {
936 dropdown_form.Location = location;
939 System.Windows.Forms.MSG msg = new MSG ();
940 queue_id = XplatUI.StartLoop (Thread.CurrentThread);
941 while (dropdown_form.Visible && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) {
942 switch (msg.message) {
943 case Msg.WM_NCLBUTTONDOWN:
944 case Msg.WM_NCMBUTTONDOWN:
945 case Msg.WM_NCRBUTTONDOWN:
946 case Msg.WM_LBUTTONDOWN:
947 case Msg.WM_MBUTTONDOWN:
948 case Msg.WM_RBUTTONDOWN:
949 if (!HwndInControl (dropdown_form, msg.hwnd))
952 case Msg.WM_ACTIVATE:
954 if (owner.window.Handle == msg.hwnd)
958 XplatUI.TranslateMessage (ref msg);
959 XplatUI.DispatchMessage (ref msg);
961 XplatUI.EndLoop (Thread.CurrentThread);
965 private void RepositionInScreenWorkingArea (Form form)
967 Rectangle workingArea = Screen.FromControl (form).WorkingArea;
968 if (!workingArea.Contains (form.Bounds)) {
973 if (form.Location.X < workingArea.X)
976 if (form.Location.Y + form.Size.Height > workingArea.Height) {
977 Point aboveTextBox = PointToScreen (new Point (grid_textbox.Right - form.Width, grid_textbox.Location.Y));
978 y = aboveTextBox.Y - form.Size.Height;
981 form.Location = new Point (x, y);
985 private bool HwndInControl (Control c, IntPtr hwnd)
987 if (hwnd == c.window.Handle)
989 foreach (Control cc in c.Controls.GetAllControls ()) {
990 if (HwndInControl (cc, hwnd))
997 #region IWindowsFormsEditorService Members
999 public void CloseDropDown () {
1000 Control c = dropdown_form.Controls[0];
1002 dropdown_form.Hide ();
1003 dropdown_form.Controls.Clear ();
1006 public void DropDownControl (Control control) {
1007 ShowDropDownControl (control, true);
1010 public System.Windows.Forms.DialogResult ShowDialog (Form dialog) {
1011 return dialog.ShowDialog (this);
1019 internal class PropertyGridDropDown : Form {
1020 protected override CreateParams CreateParams {
1022 CreateParams cp = base.CreateParams;
1023 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN));
1024 cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);