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;
56 private StringFormat stringFormat;
60 public PropertyGridView (PropertyGrid propertyGrid)
62 property_grid = propertyGrid;
64 property_grid.SelectedGridItemChanged+=new SelectedGridItemChangedEventHandler(HandleSelectedGridItemChanged);
65 property_grid.PropertyValueChanged+=new PropertyValueChangedEventHandler(HandlePropertyValueChanged);
67 stringFormat = new StringFormat();
68 stringFormat.FormatFlags = StringFormatFlags.NoWrap;
69 stringFormat.Trimming = StringTrimming.None;
71 this.BackColor = Color.Beige;
72 grid_textbox = new PropertyGridTextBox();
73 grid_textbox.DropDownButtonClicked +=new EventHandler(DropDownButtonClicked);
74 grid_textbox.DialogButtonClicked +=new EventHandler(DialogButtonClicked);
77 dropdown_form = new PropertyGridDropDown();
78 dropdown_form.FormBorderStyle = FormBorderStyle.None;
79 dropdown_form.ShowInTaskbar = false;
81 dialog_form = new Form();
82 //dialog_form.FormBorderStyle = FormBorderStyle.None;
86 grid_textbox.Visible = false;
87 grid_textbox.Font = this.Font;//new Font(this.Font,FontStyle.Bold);
88 grid_textbox.BackColor = this.BackColor;
89 // Not working at all, used to??
90 grid_textbox.Validating += new CancelEventHandler(TextBoxValidating);
91 this.Controls.Add(grid_textbox);
93 vbar = new VScrollBar();
95 vbar.Scroll+=new ScrollEventHandler(HandleScroll);
96 vbar.Dock = DockStyle.Right;
97 this.Controls.Add(vbar);
99 splitter_location = 65;
100 resizing_grid = false;
102 ForeColorChanged+=new EventHandler(RedrawEvent);
103 BackColorChanged+=new System.EventHandler(RedrawEvent);
104 FontChanged+=new EventHandler(RedrawEvent);
105 SizeChanged+=new EventHandler(RedrawEvent);
107 SetStyle(ControlStyles.DoubleBuffer, true);
108 SetStyle(ControlStyles.UserPaint, true);
109 SetStyle(ControlStyles.AllPaintingInWmPaint, true);
110 SetStyle(ControlStyles.ResizeRedraw, false);
111 SetStyle(ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, false);
116 #region Protected Instance Methods
118 protected override void OnPaint(PaintEventArgs e)
120 if (property_grid.SelectedGridItem != null && property_grid.SelectedGridItem.GridItemType == GridItemType.Property)
122 grid_textbox.Visible = true;
123 if (!grid_textbox.Focused)
124 grid_textbox.Focus();
128 grid_textbox.Visible = false;
131 // Decide if we need a scrollbar
132 open_grid_item_count = 0;
137 e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
140 // can we use the transform
141 //pevent.Graphics.TranslateTransform(0, -vbar.Value*ROW_HEIGHT);
142 int yLoc = -vbar.Value*ROW_HEIGHT;
143 DrawGridItems(property_grid.grid_items, e, 1, ref yLoc);
146 e.Graphics.DrawRectangle(SystemPens.ControlDark, 0,0,Width-1,Height-1 );
156 protected override void OnMouseMove (MouseEventArgs e)
161 splitter_location = Math.Max(e.X,2*V_INDENT);
164 if (e.X > splitter_location - RESIZE_WIDTH && e.X < splitter_location + RESIZE_WIDTH)
165 this.Cursor = Cursors.SizeWE;
167 this.Cursor = Cursors.Default;
168 base.OnMouseMove (e);
171 private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y, ref int current)
173 foreach (GridItem child_grid_item in grid_items)
175 if (y > current && y < current + ROW_HEIGHT)
177 return child_grid_item;
179 current += ROW_HEIGHT;
180 if (child_grid_item.Expanded)
182 GridItem foundItem = GetSelectedGridItem(child_grid_item.GridItems, y, ref current);
183 if (foundItem != null)
190 protected override void OnMouseDown (MouseEventArgs e)
192 if (e.X > splitter_location - RESIZE_WIDTH && e.X < splitter_location + RESIZE_WIDTH)
194 resizing_grid = true;
198 int offset = -vbar.Value*ROW_HEIGHT;
199 GridItem foundItem = GetSelectedGridItem(property_grid.grid_items, e.Y, ref offset);
201 if (foundItem != null)
203 if (foundItem.Expandable)
205 if (e.X >=3 && e.X <= 11 && (e.Y % ROW_HEIGHT >= 3 && e.Y % ROW_HEIGHT <= 11))
207 foundItem.Expanded = !foundItem.Expanded;
211 this.property_grid.SelectedGridItem = foundItem;
214 base.OnMouseDown (e);
218 protected override void OnMouseUp (MouseEventArgs e)
220 resizing_grid = false;
224 protected override void OnKeyDown (KeyEventArgs e)
231 #region Private Helper Methods
233 private void UpdateScrollBar()
235 int visible_rows = this.ClientRectangle.Height/ROW_HEIGHT;
236 if (open_grid_item_count > visible_rows)
239 vbar.SmallChange = 1;
241 vbar.Maximum = open_grid_item_count-1;
242 vbar.LargeChange = visible_rows;
246 vbar.Visible = false;
251 private GridItem GetGridItemAt (int y)
258 private void DrawGrid(PaintEventArgs pevent, int yLoc)
260 Pen pen = ThemeEngine.Current.ResPool.GetPen(property_grid.LineColor);
261 // vertical divider line
262 pevent.Graphics.DrawLine(pen, splitter_location, 0, splitter_location, yLoc);
267 pevent.Graphics.DrawLine(pen, 0, yLoc, ClientRectangle.Width, yLoc);
272 private void DrawGridItems(GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc)
274 foreach (GridItem grid_item in grid_items)
276 DrawGridItem (grid_item, pevent, depth, ref yLoc);
277 if (grid_item.Expanded)
278 DrawGridItems(grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc);
282 private void DrawGridItemLabel(GridItem grid_item, PaintEventArgs pevent, Rectangle rect)
285 if (grid_item.Parent != null && grid_item.Parent.GridItemType != GridItemType.Category)
288 Font font = this.Font;
289 Brush brush = SystemBrushes.WindowText;
290 if (grid_item.GridItemType == GridItemType.Category)
292 font = new Font(font, FontStyle.Bold);
293 brush = SystemBrushes.ControlDark;
296 if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category)
298 pevent.Graphics.FillRectangle (SystemBrushes.Highlight, rect);
300 brush = SystemBrushes.HighlightText;
304 pevent.Graphics.DrawString(grid_item.Label,font,brush,new Rectangle(x, rect.Y + 2,x-rect.X+rect.Width-2,rect.Height-2),stringFormat);
307 private void DrawGridItemValue(GridItem grid_item, PaintEventArgs pevent, Rectangle rect)
310 if (grid_item.PropertyDescriptor != null)
313 bool paintsValue = false;
314 UITypeEditor editor = null;
315 object temp = grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
316 editor = (UITypeEditor)temp;//grid_item.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
319 paintsValue = editor.GetPaintValueSupported();
322 if (grid_item == property_grid.SelectedGridItem)
324 grid_textbox.ReadOnly = false;
325 grid_textbox.DropDownButtonVisible = false;
326 grid_textbox.DialogButtonVisible = false;
329 UITypeEditorEditStyle style = editor.GetEditStyle();
333 case UITypeEditorEditStyle.DropDown:
334 grid_textbox.DropDownButtonVisible = true;
336 case UITypeEditorEditStyle.Modal:
337 grid_textbox.DialogButtonVisible = true;
345 if (grid_item.PropertyDescriptor.Converter != null)
347 if (grid_item.PropertyDescriptor.Converter.GetStandardValuesSupported())
350 grid_textbox.DropDownButtonVisible = true;
351 grid_textbox.ReadOnly = true;
356 System.Console.WriteLine("Converter not available for type {0}",grid_item.PropertyDescriptor.PropertyType);
368 int xLoc = splitter_location+1;
371 pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(Color.Black), splitter_location+2,rect.Y+2, 20, ROW_HEIGHT-4);
374 editor.PaintValue(grid_item.Value, pevent.Graphics, new Rectangle(splitter_location+3,rect.Y+3, 19, ROW_HEIGHT-5));
378 System.Console.WriteLine(ex.Message);
379 System.Console.WriteLine("Paint Value failed for type {0}",grid_item.PropertyDescriptor.PropertyType);
380 // design time stuff is not playing nice
385 Font font = this.Font;
388 if (grid_item.PropertyDescriptor.Converter != null)
390 string value = grid_item.PropertyDescriptor.Converter.ConvertToString(grid_item.Value);
391 if (grid_item.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
392 font = new Font(font, FontStyle.Bold);
394 pevent.Graphics.DrawString(value,font,SystemBrushes.WindowText,new RectangleF(xLoc,rect.Y+2, ClientRectangle.Width-(xLoc), ROW_HEIGHT),stringFormat);
398 System.Console.WriteLine("No converter for type {0}",grid_item.PropertyDescriptor.PropertyType);
405 if (grid_item == property_grid.SelectedGridItem && grid_item.GridItemType != GridItemType.Category)
407 grid_textbox.SetBounds(xLoc, rect.Top, ClientRectangle.Width-xLoc - (vbar.Visible ? vbar.Width: 0),ROW_HEIGHT);
412 private void DrawGridItem (GridItem grid_item, PaintEventArgs pevent, int depth, ref int yLoc)
414 if (yLoc > -ROW_HEIGHT && yLoc < ClientRectangle.Height)
418 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), 0,yLoc,V_INDENT, ROW_HEIGHT);
420 if (grid_item.Expandable)
422 grid_item.PlusMinusBounds = DrawPlusMinus(pevent, 3, yLoc+3, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category);
425 if (grid_item.GridItemType == GridItemType.Category)
427 pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), ROW_HEIGHT);
430 DrawGridItemLabel(grid_item, pevent, new Rectangle(depth*V_INDENT,yLoc, splitter_location-depth*V_INDENT, ROW_HEIGHT));
431 DrawGridItemValue(grid_item, pevent, new Rectangle(splitter_location+2,yLoc, ClientRectangle.Width-splitter_location-2, ROW_HEIGHT));
436 grid_item.Top = yLoc;
438 open_grid_item_count++;
441 private Rectangle DrawPlusMinus (PaintEventArgs pevent, int x, int y, bool expanded, bool category)
443 Rectangle bounds = new Rectangle(x, y, 8, 8);
444 if (!category) pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush(Color.White), bounds);
445 pevent.Graphics.DrawRectangle (SystemPens.ControlDark, bounds);
446 pevent.Graphics.DrawLine (SystemPens.ControlDark, x+2, y+4, x + 6, y+4);
448 pevent.Graphics.DrawLine (SystemPens.ControlDark, x+4, y+2, x+4, y+6);
455 #region Event Handling
456 private void RedrawEvent (object sender, System.EventArgs e)
461 private void TextBoxValidating (object sender, CancelEventArgs e)
463 if (this.property_grid.SelectedGridItem != null)
465 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
470 if (desc.Converter != null)
472 SetPropertyValue(desc.Converter.ConvertFromString(grid_textbox.Text));
476 System.Console.WriteLine("No converter for type {0}",desc.PropertyType);
481 Console.WriteLine("Error converting string");
492 private void dropdown_form_Deactivate (object sender, EventArgs e)
494 dropdown_form_showing = false;
495 dropdown_form.Hide();
496 //dropdown_form = new Form();
499 private void listBox_SelectedIndexChanged (object sender, EventArgs e)
501 if (this.property_grid.SelectedGridItem != null)
503 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
506 SetPropertyValue(((ListBox)sender).SelectedItem);
509 dropdown_form.Hide();
510 //dropdown_form = new Form();
514 private void SetPropertyValue(object newVal)
516 if (this.property_grid.SelectedGridItem != null)
518 PropertyDescriptor desc = property_grid.SelectedGridItem.PropertyDescriptor;
521 desc.SetValue(property_grid.SelectedObject, newVal);
526 private void DropDownButtonClicked (object sender, EventArgs e)
528 if (property_grid.SelectedGridItem.PropertyDescriptor.GetEditor(typeof(UITypeEditor)) == null)
530 //dropdown_form.FormBorderStyle = FormBorderStyle.None;
531 dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
532 ListBox listBox = new ListBox();
533 listBox.Dock = DockStyle.Fill;
534 listBox.SelectedIndexChanged +=new EventHandler(listBox_SelectedIndexChanged);
535 foreach (object obj in property_grid.SelectedGridItem.PropertyDescriptor.Converter.GetStandardValues())
536 listBox.Items.Add(obj);
537 dropdown_form.Controls.Clear();
538 dropdown_form.Controls.Add(listBox);
539 dropdown_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
540 dropdown_form.Width = grid_textbox.Width;
541 dropdown_form.Show();
545 UITypeEditor editor = (UITypeEditor)property_grid.SelectedGridItem.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
546 System.ComponentModel.Design.ServiceContainer service_container = new System.ComponentModel.Design.ServiceContainer();
547 service_container.AddService(typeof(System.Windows.Forms.Design.IWindowsFormsEditorService), this);
548 SetPropertyValue(editor.EditValue(new ITypeDescriptorContextImpl(this.property_grid), service_container,property_grid.SelectedGridItem.Value));
552 private void DialogButtonClicked(object sender, EventArgs e)
554 //dialog_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
555 //dropdown_form.Width = grid_textbox.Width;
559 private void HandleScroll(object sender, ScrollEventArgs e)
564 if (e.NewValue == vbar.Value)return;
566 if (e.NewValue > vbar.Maximum-ClientRectangle.Height/ROW_HEIGHT)
568 e.NewValue = vbar.Maximum-ClientRectangle.Height/ROW_HEIGHT+1;
569 if (e.NewValue == vbar.Value)return;
574 case ScrollEventType.SmallDecrement:
575 XplatUI.ScrollWindow(Handle, 0, ROW_HEIGHT, false);
576 grid_textbox.Top += ROW_HEIGHT;
577 Invalidate(ClientRectangle);
578 //Invalidate(new Rectangle(0,0,ClientRectangle.Width,ROW_HEIGHT));
580 case ScrollEventType.SmallIncrement:
581 XplatUI.ScrollWindow(Handle, 0, -ROW_HEIGHT, false);
582 grid_textbox.Top -= ROW_HEIGHT;
583 Invalidate(ClientRectangle);
584 //Invalidate(new Rectangle(0,ClientRectangle.Bottom-ROW_HEIGHT,ClientRectangle.Width,ROW_HEIGHT));
586 case ScrollEventType.LargeDecrement:
587 XplatUI.ScrollWindow(Handle, 0, ROW_HEIGHT, false);
588 Invalidate(ClientRectangle);
590 case ScrollEventType.LargeIncrement:
591 XplatUI.ScrollWindow(Handle, 0, -ROW_HEIGHT, false);
592 Invalidate(ClientRectangle);
594 case ScrollEventType.ThumbTrack:
595 XplatUI.ScrollWindow(Handle, 0, -(vbar.Value-e.NewValue), false);
596 Invalidate(ClientRectangle);
598 case ScrollEventType.ThumbPosition:
599 Invalidate(ClientRectangle);
605 private void HandleSelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
607 // Region not working correctly
608 //Region clip = new Region();
609 //if (property_grid.SelectedGridItem != null)
610 // clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, ROW_HEIGHT));
611 // clip.Union(new Rectangle(0,property_grid.SelectedGridItem.Top, ClientRectangle.Width, ROW_HEIGHT));
613 if (e.NewSelection.PropertyDescriptor != null)
615 grid_textbox.Text = e.NewSelection.PropertyDescriptor.Converter.ConvertToString(e.NewSelection.Value);
616 if (e.NewSelection.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
617 grid_textbox.Font = new Font(this.Font, FontStyle.Bold);
619 grid_textbox.Font = this.Font;
622 Invalidate(/*clip*/this.ClientRectangle);
626 private void HandlePropertyValueChanged(object s, PropertyValueChangedEventArgs e)
628 if (e.ChangedItem.PropertyDescriptor != null)
630 grid_textbox.Text = e.ChangedItem.PropertyDescriptor.Converter.ConvertToString(e.ChangedItem.Value);
631 if (e.ChangedItem.PropertyDescriptor.CanResetValue(property_grid.SelectedObject))
632 grid_textbox.Font = new Font(this.Font, FontStyle.Bold);
634 grid_textbox.Font = this.Font;
638 #region IWindowsFormsEditorService Members
640 public void CloseDropDown()
642 dropdown_form_showing = false;
643 dropdown_form.Hide();
646 public void DropDownControl(Control control)
648 //dropdown_form.FormBorderStyle = FormBorderStyle.None;
649 dropdown_form.Deactivate +=new EventHandler(dropdown_form_Deactivate);
650 dropdown_form.Size = control.Size;
651 control.Dock = DockStyle.Fill;
652 dropdown_form.Controls.Clear();
653 dropdown_form.Controls.Add(control);
654 dropdown_form.Location = PointToScreen(new Point(grid_textbox.Location.X,grid_textbox.Location.Y+ROW_HEIGHT));
655 dropdown_form.Width = grid_textbox.Width;
657 dropdown_form_showing = true;
658 dropdown_form.Show();
659 System.Windows.Forms.MSG msg = new MSG();
660 while (XplatUI.GetMessage(ref msg, IntPtr.Zero, 0, 0) && dropdown_form_showing)
662 XplatUI.TranslateMessage(ref msg);
663 XplatUI.DispatchMessage(ref msg);
667 public System.Windows.Forms.DialogResult ShowDialog(Form dialog)
669 return dialog.ShowDialog(this);
674 #region DropDownForm Class
675 #endregion DropDownForm Class
677 #region Internal Classes
678 internal class ITypeDescriptorContextImpl : System.ComponentModel.ITypeDescriptorContext
680 private PropertyGrid property_grid;
681 public ITypeDescriptorContextImpl(PropertyGrid propertyGrid)
683 property_grid = propertyGrid;
685 #region ITypeDescriptorContext Members
687 public void OnComponentChanged()
689 // TODO: Add SystemComp.OnComponentChanged implementation
692 public IContainer Container
696 return property_grid as IContainer;
700 public bool OnComponentChanging()
702 // TODO: Add SystemComp.OnComponentChanging implementation
706 public object Instance
710 return property_grid.SelectedGridItem.Value;
714 public PropertyDescriptor PropertyDescriptor
718 return property_grid.SelectedGridItem.PropertyDescriptor;
724 #region IServiceProvider Members
726 public object GetService(Type serviceType)
728 // TODO: Add SystemComp.GetService implementation
741 internal class PropertyGridDropDown : Form
743 protected override CreateParams CreateParams
747 CreateParams cp = base.CreateParams;
748 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_VISIBLE | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN));
749 cp.ExStyle |= (int)(WindowStyles.WS_EX_TOOLWINDOW | WindowStyles.WS_EX_TOPMOST);