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 Novell, Inc. (http://www.novell.com)
23 // Jonathan Chambers (jonathan.chambers@ansys.com)
30 using System.Collections;
32 using System.Drawing.Design;
33 using System.ComponentModel;
34 using System.Windows.Forms.Design;
36 namespace System.Windows.Forms.PropertyGridInternal
38 internal class PropertyGridView : System.Windows.Forms.ScrollableControl, IWindowsFormsEditorService
41 #region Private Members
42 private const int V_INDENT = 16;
43 private const int ROW_HEIGHT = 16;
44 private const int RESIZE_WIDTH = 3;
45 private const int BUTTON_WIDTH = 25;
46 private PropertyGridTextBox grid_textbox;
47 private PropertyGrid property_grid;
48 private bool resizing_grid;
49 private int splitter_location;
50 private int open_grid_item_count = -1;
51 private int skipped_grid_items;
52 private PropertyGridDropDown dropdown_form;
53 private bool dropdown_form_showing;
54 private Form dialog_form;
55 private VScrollBar vbar;
59 public PropertyGridView (PropertyGrid propertyGrid)
61 property_grid = propertyGrid;
63 property_grid.SelectedGridItemChanged+=new SelectedGridItemChangedEventHandler(HandleSelectedGridItemChanged);
64 property_grid.PropertyValueChanged+=new PropertyValueChangedEventHandler(HandlePropertyValueChanged);
66 this.BackColor = Color.Beige;
67 grid_textbox = new PropertyGridTextBox();
68 grid_textbox.DropDownButtonClicked +=new EventHandler(DropDownButtonClicked);
69 grid_textbox.DialogButtonClicked +=new EventHandler(DialogButtonClicked);
72 dropdown_form = new PropertyGridDropDown();
73 dropdown_form.FormBorderStyle = FormBorderStyle.None;
74 dropdown_form.ShowInTaskbar = false;
76 dialog_form = new Form();
77 //dialog_form.FormBorderStyle = FormBorderStyle.None;
81 grid_textbox.Visible = true;
82 grid_textbox.Font = this.Font;//new Font(this.Font,FontStyle.Bold);
83 grid_textbox.BackColor = this.BackColor;
84 // Not working at all, used to??
85 grid_textbox.Validating += new CancelEventHandler(TextBoxValidating);
87 vbar = new VScrollBar();
89 vbar.Scroll+=new ScrollEventHandler(HandleScroll);
90 vbar.Dock = DockStyle.Right;
91 this.Controls.Add(vbar);
93 splitter_location = 65;
94 resizing_grid = false;
96 ForeColorChanged+=new EventHandler(RedrawEvent);
97 BackColorChanged+=new System.EventHandler(RedrawEvent);
98 FontChanged+=new EventHandler(RedrawEvent);
99 SizeChanged+=new EventHandler(RedrawEvent);
101 SetStyle(ControlStyles.DoubleBuffer, true);
102 SetStyle(ControlStyles.UserPaint, true);
103 SetStyle(ControlStyles.AllPaintingInWmPaint, true);
104 SetStyle(ControlStyles.ResizeRedraw, false);
105 SetStyle(ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, false);
110 #region Protected Instance Methods
112 protected override void OnPaint(PaintEventArgs e)
114 if (property_grid.SelectedGridItem != null && property_grid.SelectedGridItem.GridItemType == GridItemType.Property)
116 this.Controls.Add(grid_textbox);
117 if (!grid_textbox.Focused)
118 grid_textbox.Focus();
122 this.Controls.Remove(grid_textbox);
125 // Decide if we need a scrollbar
126 open_grid_item_count = 0;
131 e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
134 // can we use the transform
135 //pevent.Graphics.TranslateTransform(0, -vbar.Value*ROW_HEIGHT);
136 int yLoc = -vbar.Value*ROW_HEIGHT;
137 DrawGridItems(property_grid.grid_items, e, 1, ref yLoc);
140 e.Graphics.DrawRectangle(SystemPens.ControlDark, 0,0,Width-1,Height-1 );
150 protected override void OnMouseMove (MouseEventArgs e)
154 splitter_location = Math.Max(e.X,V_INDENT);
157 base.OnMouseMove (e);
160 private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y)
162 foreach (GridItem child_grid_item in grid_items)
164 if (y > child_grid_item.Top && y < child_grid_item.Top + ROW_HEIGHT)
166 return child_grid_item;
168 GridItem foundItem = GetSelectedGridItem(child_grid_item.GridItems, y);
169 if (foundItem != null)
175 protected override void OnMouseDown (MouseEventArgs e)
177 if (e.X > splitter_location - RESIZE_WIDTH && e.X < splitter_location + RESIZE_WIDTH)
179 resizing_grid = true;
183 GridItem foundItem = GetSelectedGridItem(property_grid.grid_items, e.Y);
185 if (foundItem != null)
187 if (foundItem.Expandable)
189 if (foundItem.PlusMinusBounds.Contains(e.X,e.Y))
191 foundItem.Expanded = !foundItem.Expanded;
194 this.property_grid.SelectedGridItem = foundItem;
197 base.OnMouseDown (e);
201 protected override void OnMouseUp (MouseEventArgs e)
203 resizing_grid = false;
207 protected override void OnKeyDown (KeyEventArgs e)
214 #region Private Helper Methods
216 private void UpdateScrollBar()
218 int visible_rows = this.ClientRectangle.Height/ROW_HEIGHT;
219 if (open_grid_item_count > visible_rows)
222 vbar.SmallChange = 1;
224 vbar.Maximum = open_grid_item_count-1;
225 vbar.LargeChange = visible_rows;
229 vbar.Visible = false;
234 private GridItem GetGridItemAt (int y)
241 private void DrawGrid(PaintEventArgs pevent, int yLoc)
243 Pen pen = ThemeEngine.Current.ResPool.GetPen(property_grid.LineColor);
244 // vertical divider line
245 pevent.Graphics.DrawLine(pen, splitter_location, 0, splitter_location, yLoc);
250 pevent.Graphics.DrawLine(pen, 0, yLoc, ClientRectangle.Width, yLoc);
255 private void DrawGridItems(GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc)
257 foreach (GridItem grid_item in grid_items)
259 DrawGridItem (grid_item, pevent, depth, ref yLoc);
260 if (grid_item.Expanded)
261 DrawGridItems(grid_item.GridItems, pevent, depth, ref yLoc);
265 private void DrawGridItemLabel(GridItem grid_item, PaintEventArgs pevent, Rectangle rect)
268 if (grid_item.Parent != null && grid_item.Parent.GridItemType != GridItemType.Category)
271 Font font = this.Font;
272 Brush brush = SystemBrushes.WindowText;
273 if (grid_item.GridItemType == GridItemType.Category)
275 font = new Font(font, FontStyle.Bold);
276 brush = SystemBrushes.ControlDark;
279 if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category)
281 pevent.Graphics.FillRectangle (SystemBrushes.Highlight, rect);
283 brush = SystemBrushes.HighlightText;
287 pevent.Graphics.DrawString(grid_item.Label,font,brush,new Rectangle(x, rect.Y + 2,x-rect.X+rect.Width,rect.Height-2));
290 private void DrawGridItemValue(GridItem grid_item, PaintEventArgs pevent, Rectangle rect)
293 if (grid_item.PropertyDescriptor != null)
296 bool paintsValue = false;
297 UITypeEditor editor = null;
298 object temp = grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
299 editor = (UITypeEditor)temp;//grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
302 paintsValue = editor.GetPaintValueSupported();
305 if (grid_item == property_grid.SelectedGridItem)
307 grid_textbox.DropDownButtonVisible = false;
308 grid_textbox.DialogButtonVisible = false;
311 UITypeEditorEditStyle style = editor.GetEditStyle();
315 case UITypeEditorEditStyle.DropDown:
316 grid_textbox.DropDownButtonVisible = true;
318 case UITypeEditorEditStyle.Modal:
319 grid_textbox.DialogButtonVisible = true;
327 if (grid_item.PropertyDescriptor.Converter != null)
329 if (grid_item.PropertyDescriptor.Converter.GetStandardValuesSupported())
332 grid_textbox.DropDownButtonVisible = true;
333 grid_textbox.ReadOnly = true;
338 System.Console.WriteLine("Converter not available for type {0}",grid_item.PropertyDescriptor.PropertyType);
350 int xLoc = splitter_location+1;
353 pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(Color.Black), splitter_location+2,rect.Y+2, 20, ROW_HEIGHT-4);
356 editor.PaintValue(grid_item.Value, pevent.Graphics, new Rectangle(splitter_location+3,rect.Y+3, 19, ROW_HEIGHT-5));
360 System.Console.WriteLine(ex.Message);
361 System.Console.WriteLine("Paint Value failed for type {0}",grid_item.PropertyDescriptor.PropertyType);
362 // design time stuff is not playing nice
367 Font font = this.Font;
370 if (grid_item.PropertyDescriptor.Converter != null)
372 string value = grid_item.PropertyDescriptor.Converter.ConvertToString(grid_item.Value);
373 if (grid_item.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
374 font = new Font(font, FontStyle.Bold);
376 pevent.Graphics.DrawString(value,font,SystemBrushes.WindowText,new RectangleF(xLoc,rect.Y+2, ClientRectangle.Width-(xLoc), ROW_HEIGHT));
380 System.Console.WriteLine("No converter for type {0}",grid_item.PropertyDescriptor.PropertyType);
387 if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category)
389 grid_textbox.Location = new Point(xLoc, rect.Top);
390 grid_textbox.Size = new Size(ClientRectangle.Width-xLoc,ROW_HEIGHT);
395 private void DrawGridItem (GridItem grid_item, PaintEventArgs pevent, int depth, ref int yLoc)
397 if (yLoc > -ROW_HEIGHT && yLoc < ClientRectangle.Height)
401 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), 0,yLoc,V_INDENT, ROW_HEIGHT);
403 if (grid_item.Expandable)
405 grid_item.PlusMinusBounds = DrawPlusMinus(pevent, 3, yLoc+3, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
408 if (grid_item.GridItemType == GridItemType.Category)
410 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), ROW_HEIGHT);
413 DrawGridItemLabel(grid_item, pevent, new Rectangle(V_INDENT,yLoc, splitter_location-V_INDENT, ROW_HEIGHT));
414 DrawGridItemValue(grid_item, pevent, new Rectangle(splitter_location+2,yLoc, ClientRectangle.Width-splitter_location-2, ROW_HEIGHT));
419 grid_item.Top = yLoc;
421 open_grid_item_count++;
424 private Rectangle DrawPlusMinus (PaintEventArgs pevent, int x, int y, bool expanded, bool category)
426 Rectangle bounds = new Rectangle(x, y, 8, 8);
427 if (!category) pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush(Color.White), bounds);
428 pevent.Graphics.DrawRectangle (SystemPens.ControlDark, bounds);
429 pevent.Graphics.DrawLine (SystemPens.ControlDark, x+2, y+4, x + 6, y+4);
431 pevent.Graphics.DrawLine (SystemPens.ControlDark, x+4, y+2, x+4, y+6);
438 #region Event Handling
439 private void RedrawEvent (object sender, System.EventArgs e)
444 private void TextBoxValidating (object sender, CancelEventArgs e)
446 if (this.property_grid.SelectedGridItem != null)
448 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
453 if (desc.Converter != null)
455 SetPropertyValue(desc.Converter.ConvertFromString(grid_textbox.Text));
459 System.Console.WriteLine("No converter for type {0}",desc.PropertyType);
464 Console.WriteLine("Error converting string");
475 private void dropdown_form_Deactivate (object sender, EventArgs e)
477 dropdown_form_showing = false;
478 dropdown_form.Hide();
479 //dropdown_form = new Form();
482 private void listBox_SelectedIndexChanged (object sender, EventArgs e)
484 if (this.property_grid.SelectedGridItem != null)
486 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
489 SetPropertyValue(((ListBox)sender).SelectedItem);
492 dropdown_form.Hide();
493 //dropdown_form = new Form();
497 private void SetPropertyValue(object newVal)
499 if (this.property_grid.SelectedGridItem != null)
501 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
504 desc.SetValue(property_grid.SelectedObject, newVal);
509 private void DropDownButtonClicked (object sender, EventArgs e)
511 if (property_grid.SelectedGridItem.PropertyDescriptor.GetEditor(typeof(UITypeEditor)) == null)
513 //dropdown_form.FormBorderStyle = FormBorderStyle.None;
514 dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
515 ListBox listBox = new ListBox();
516 listBox.Dock = DockStyle.Fill;
517 listBox.SelectedIndexChanged +=new EventHandler(listBox_SelectedIndexChanged);
518 foreach (object obj in property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValues())
519 listBox.Items.Add(obj);
520 dropdown_form.Controls.Clear();
521 dropdown_form.Controls.Add(listBox);
522 dropdown_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
523 dropdown_form.Width = grid_textbox.Width;
524 dropdown_form.Show();
528 UITypeEditor editor = (UITypeEditor)property_grid.SelectedGridItem.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
529 System.ComponentModel.Design.ServiceContainer service_container = new System.ComponentModel.Design.ServiceContainer();
530 service_container.AddService(typeof(System.Windows.Forms.Design.IWindowsFormsEditorService), this);
531 SetPropertyValue(editor.EditValue(new ITypeDescriptorContextImpl(this.property_grid), service_container,property_grid.SelectedGridItem.Value));
535 private void DialogButtonClicked(object sender, EventArgs e)
537 //dialog_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
538 //dropdown_form.Width = grid_textbox.Width;
542 private void HandleScroll(object sender, ScrollEventArgs e)
547 if (e.NewValue == vbar.Value)return;
549 if (e.NewValue > vbar.Maximum-ClientRectangle.Height/ROW_HEIGHT)
551 e.NewValue = vbar.Maximum-ClientRectangle.Height/ROW_HEIGHT+1;
552 if (e.NewValue == vbar.Value)return;
557 case ScrollEventType.SmallDecrement:
558 XplatUI.ScrollWindow(Handle, 0, ROW_HEIGHT, false);
559 grid_textbox.Top += ROW_HEIGHT;
560 Invalidate(ClientRectangle);
561 //Invalidate(new Rectangle(0,0,ClientRectangle.Width,ROW_HEIGHT));
563 case ScrollEventType.SmallIncrement:
564 XplatUI.ScrollWindow(Handle, 0, -ROW_HEIGHT, false);
565 grid_textbox.Top -= ROW_HEIGHT;
566 Invalidate(ClientRectangle);
567 //Invalidate(new Rectangle(0,ClientRectangle.Bottom-ROW_HEIGHT,ClientRectangle.Width,ROW_HEIGHT));
569 case ScrollEventType.LargeDecrement:
570 XplatUI.ScrollWindow(Handle, 0, ROW_HEIGHT, false);
571 Invalidate(ClientRectangle);
573 case ScrollEventType.LargeIncrement:
574 XplatUI.ScrollWindow(Handle, 0, -ROW_HEIGHT, false);
575 Invalidate(ClientRectangle);
577 case ScrollEventType.ThumbTrack:
578 XplatUI.ScrollWindow(Handle, 0, -(vbar.Value-e.NewValue), false);
579 Invalidate(ClientRectangle);
581 case ScrollEventType.ThumbPosition:
582 Invalidate(ClientRectangle);
588 private void HandleSelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
590 // Region not working correctly
591 //Region clip = new Region();
592 //if (property_grid.SelectedGridItem != null)
593 // clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, ROW_HEIGHT));
594 // clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, ROW_HEIGHT));
596 if (e.NewSelection.PropertyDescriptor != null)
598 grid_textbox.Text = e.NewSelection.PropertyDescriptor.Converter.ConvertToString(e.NewSelection.Value);
599 if (e.NewSelection.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
600 grid_textbox.Font = new Font(this.Font, FontStyle.Bold);
602 grid_textbox.Font = this.Font;
605 Invalidate(/*clip*/this.ClientRectangle);
609 private void HandlePropertyValueChanged(object s, PropertyValueChangedEventArgs e)
611 if (e.ChangedItem.PropertyDescriptor != null)
613 grid_textbox.Text = e.ChangedItem.PropertyDescriptor.Converter.ConvertToString(e.ChangedItem.Value);
614 if (e.ChangedItem.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
615 grid_textbox.Font = new Font(this.Font, FontStyle.Bold);
617 grid_textbox.Font = this.Font;
621 #region IWindowsFormsEditorService Members
623 public void CloseDropDown()
625 dropdown_form_showing = false;
626 dropdown_form.Hide();
629 public void DropDownControl(Control control)
631 //dropdown_form.FormBorderStyle = FormBorderStyle.None;
632 dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
633 dropdown_form.Size = control.Size;
634 control.Dock = DockStyle.Fill;
635 dropdown_form.Controls.Clear();
636 dropdown_form.Controls.Add(control);
637 dropdown_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
638 dropdown_form.Width = grid_textbox.Width;
640 dropdown_form_showing = true;
641 dropdown_form.Show();
642 System.Windows.Forms.MSG msg = new MSG();
643 while (XplatUI.GetMessage(ref msg, IntPtr.Zero, 0, 0) && dropdown_form_showing)
645 XplatUI.TranslateMessage(ref msg);
646 XplatUI.DispatchMessage(ref msg);
650 public System.Windows.Forms.DialogResult ShowDialog(Form dialog)
652 return dialog.ShowDialog(this);
657 #region DropDownForm Class
658 #endregion DropDownForm Class
660 #region Internal Classes
661 internal class ITypeDescriptorContextImpl : System.ComponentModel.ITypeDescriptorContext
663 private PropertyGrid property_grid;
664 public ITypeDescriptorContextImpl(PropertyGrid propertyGrid)
666 property_grid = propertyGrid;
668 #region ITypeDescriptorContext Members
670 public void OnComponentChanged()
672 // TODO: Add SystemComp.OnComponentChanged implementation
675 public IContainer Container
679 return property_grid as IContainer;
683 public bool OnComponentChanging()
685 // TODO: Add SystemComp.OnComponentChanging implementation
689 public object Instance
693 return property_grid.SelectedGridItem.Value;
697 public PropertyDescriptor PropertyDescriptor
701 return property_grid.SelectedGridItem.PropertyDescriptor;
707 #region IServiceProvider Members
709 public object GetService(Type serviceType)
711 // TODO: Add SystemComp.GetService implementation
724 internal class PropertyGridDropDown : Form
726 protected override CreateParams CreateParams
730 CreateParams cp = base.CreateParams;
731 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_VISIBLE | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN));
732 cp.ExStyle |= (int)(WindowStyles.WS_EX_TOOLWINDOW | WindowStyles.WS_EX_TOPMOST);