PropertyGridView.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  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:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  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.
  19. //
  20. // Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com)
  21. //
  22. // Authors:
  23. // Jonathan Chambers (jonathan.chambers@ansys.com)
  24. // Ivan N. Zlatev (contact@i-nz.net)
  25. //
  26. //
  27. // NOT COMPLETE
  28. using CustomControls;
  29. using System.Collections;
  30. using System.ComponentModel;
  31. using System.Drawing;
  32. using System.Drawing.Design;
  33. using System.Windows.Forms.Design;
  34. namespace System.Windows.Forms.PropertyGridInternal
  35. {
  36. internal class PropertyGridView : UserControl, IWindowsFormsEditorService
  37. {
  38. #region Private Members
  39. private const char PASSWORD_PAINT_CHAR = '\u25cf'; // the dot char
  40. private const char PASSWORD_TEXT_CHAR = '*';
  41. private int V_INDENT = 16; // dpi dependent
  42. private const int ENTRY_SPACING = 2;
  43. private const int RESIZE_WIDTH = 3;
  44. private int VALUE_PAINT_WIDTH = 19; // dpi dependent
  45. private int VALUE_PAINT_INDENT = 22; // dpi dependent
  46. private int BOOL_PAINT_WIDTH = 11;
  47. private int BOOL_PAINT_INDENT = 15;
  48. private double splitter_percent = .5;
  49. private int row_height;
  50. private int font_height_padding = 3;
  51. private PropertyGridTextBox grid_textbox;
  52. private PropertyGrid property_grid;
  53. private bool resizing_grid;
  54. private VScrollBar vbar;
  55. private StringFormat string_format;
  56. private Font bold_font;
  57. private Brush inactive_text_brush;
  58. private ListBox dropdown_list;
  59. private Drawing.Point last_click;
  60. private ToolStripDropDown dropdown;
  61. #endregion
  62. #region Contructors
  63. public PropertyGridView(PropertyGrid propertyGrid)
  64. {
  65. property_grid = propertyGrid;
  66. this.Font = new Font("Segoe UI", 8.5f);
  67. bold_font = new Font(this.Font, Drawing.FontStyle.Bold);
  68. row_height = Font.Height + font_height_padding;
  69. string_format = new StringFormat();
  70. string_format.FormatFlags = StringFormatFlags.NoWrap;
  71. string_format.Trimming = StringTrimming.None;
  72. grid_textbox = new PropertyGridTextBox();
  73. grid_textbox.DropDownButtonClicked += DropDownButtonClicked;
  74. grid_textbox.DialogButtonClicked += DialogButtonClicked;
  75. vbar = new VScrollBar();
  76. vbar.Visible = false;
  77. vbar.Value = 0;
  78. vbar.ValueChanged += VScrollBar_HandleValueChanged;
  79. vbar.Dock = DockStyle.Right;
  80. this.Controls.Add(vbar);
  81. grid_textbox.Visible = false;
  82. grid_textbox.Font = this.Font;
  83. grid_textbox.BackColor = Drawing.SystemColors.Window;
  84. grid_textbox.ToggleValue += grid_textbox_ToggleValue;
  85. grid_textbox.KeyDown += grid_textbox_KeyDown;
  86. grid_textbox.MouseEnter += (s, e) => this.Cursor = Cursors.Default; // fix issue with splitter cursor
  87. grid_textbox.Validate += grid_textbox_Validate;
  88. this.Controls.Add(grid_textbox);
  89. resizing_grid = false;
  90. inactive_text_brush = new SolidBrush(Drawing.SystemColors.GrayText);
  91. BackColorChanged += new System.EventHandler(RedrawEvent);
  92. SetStyle(ControlStyles.Selectable, true);
  93. SetStyle(ControlStyles.DoubleBuffer, true);
  94. SetStyle(ControlStyles.UserPaint, true);
  95. SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  96. SetStyle(ControlStyles.ResizeRedraw, true);
  97. UpdateDpiDependencies();
  98. }
  99. #endregion
  100. private GridEntry RootGridItem
  101. {
  102. get { return (GridEntry)property_grid.RootGridItem; }
  103. }
  104. private GridEntry SelectedGridItem
  105. {
  106. get { return (GridEntry)property_grid.SelectedGridItem; }
  107. set { property_grid.SelectedGridItem = value; }
  108. }
  109. #region Protected Instance Methods
  110. protected override void OnFontChanged(EventArgs e)
  111. {
  112. base.OnFontChanged(e);
  113. bold_font = new Font(this.Font, Drawing.FontStyle.Bold);
  114. row_height = Font.Height + font_height_padding;
  115. }
  116. protected override void OnRightToLeftChanged(EventArgs e)
  117. {
  118. base.OnRightToLeftChanged(e);
  119. if (RightToLeft == RightToLeft.Yes)
  120. {
  121. string_format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
  122. vbar.Dock = DockStyle.Left;
  123. }
  124. else
  125. {
  126. string_format.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
  127. vbar.Dock = DockStyle.Right;
  128. }
  129. }
  130. private void InvalidateItemLabel(GridEntry item)
  131. {
  132. Invalidate(new Rectangle(0, item.Top, SplitterLocation, row_height));
  133. }
  134. private void InvalidateItem(GridEntry item)
  135. {
  136. if (item == null)
  137. return;
  138. Rectangle rect = new Rectangle(0, item.Top, Width, row_height);
  139. Invalidate(rect);
  140. if (item.Expanded)
  141. {
  142. rect = new Rectangle(0, item.Top + row_height, Width,
  143. Height - (item.Top + row_height));
  144. Invalidate(rect);
  145. }
  146. }
  147. // [+] expanding is handled in OnMouseDown, so in order to prevent
  148. // duplicate expanding ignore it here.
  149. //
  150. protected override void OnDoubleClick(EventArgs e)
  151. {
  152. if (this.SelectedGridItem != null && this.SelectedGridItem.Expandable &&
  153. !this.SelectedGridItem.PlusMinusBounds.Contains(last_click))
  154. this.SelectedGridItem.Expanded = !this.SelectedGridItem.Expanded;
  155. else
  156. ToggleValue(this.SelectedGridItem);
  157. }
  158. protected override void OnPaint(PaintEventArgs e)
  159. {
  160. // Background
  161. e.Graphics.FillRectangle(ResPool.GetSolidBrush(BackColor), ClientRectangle);
  162. int yLoc = -vbar.Value * row_height;
  163. if (this.RootGridItem != null)
  164. DrawGridItems(this.RootGridItem.GridItems, e, 1, ref yLoc);
  165. if (property_grid.BorderStyle != BorderStyle.None)
  166. this.DrawVisualStyleBorder(e.Graphics, new Rectangle(0, 0, Width - 1, Height - 1));
  167. UpdateScrollBar();
  168. }
  169. protected override void OnMouseWheel(MouseEventArgs e)
  170. {
  171. if (vbar == null || !vbar.Visible)
  172. return;
  173. if (e.Delta < 0)
  174. vbar.Value = Math.Min(vbar.Maximum - GetVisibleRowsCount() + 1, vbar.Value + 3);
  175. else
  176. vbar.Value = Math.Max(0, vbar.Value - 3);
  177. base.OnMouseWheel(e);
  178. }
  179. protected override void OnMouseMove(MouseEventArgs e)
  180. {
  181. if (this.RootGridItem == null)
  182. return;
  183. if (resizing_grid)
  184. {
  185. int loc = Math.Max(e.X, 2 * V_INDENT);
  186. SplitterPercent = 1.0 * loc / Width;
  187. }
  188. if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH)
  189. this.Cursor = Cursors.VSplit;
  190. else
  191. this.Cursor = Cursors.Default;
  192. base.OnMouseMove(e);
  193. }
  194. protected override void OnMouseDown(MouseEventArgs e)
  195. {
  196. base.OnMouseDown(e);
  197. last_click = e.Location;
  198. if (this.RootGridItem == null)
  199. return;
  200. if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH)
  201. {
  202. resizing_grid = true;
  203. }
  204. else
  205. {
  206. int offset = -vbar.Value * row_height;
  207. GridItem foundItem = GetSelectedGridItem(this.RootGridItem.GridItems, e.Y, ref offset);
  208. if (foundItem != null)
  209. {
  210. if (foundItem.Expandable && ((GridEntry)foundItem).PlusMinusBounds.Contains(e.X, e.Y))
  211. foundItem.Expanded = !foundItem.Expanded;
  212. this.SelectedGridItem = (GridEntry)foundItem;
  213. if (!GridLabelHitTest(e.X))
  214. {
  215. if (this.SelectedGridItem.IsBool)
  216. ToggleValue(this.SelectedGridItem);
  217. else
  218. {
  219. // send mouse down so we get the carret under cursor
  220. grid_textbox.SendMouseDown(e.X - grid_textbox.Left);
  221. }
  222. }
  223. }
  224. }
  225. }
  226. protected override void OnMouseUp(MouseEventArgs e)
  227. {
  228. resizing_grid = false;
  229. base.OnMouseUp(e);
  230. }
  231. protected override void OnResize(EventArgs e)
  232. {
  233. base.OnResize(e);
  234. if (this.SelectedGridItem != null) // initialized already
  235. UpdateView();
  236. }
  237. internal override void AfterDpiChange(float rescale)
  238. {
  239. UpdateDpiDependencies();
  240. base.AfterDpiChange(rescale);
  241. }
  242. private void UpdateDpiDependencies()
  243. {
  244. V_INDENT = _dpi(16);
  245. VALUE_PAINT_WIDTH = _dpi(19);
  246. VALUE_PAINT_INDENT = _dpi(22);
  247. BOOL_PAINT_WIDTH = _dpi(11);
  248. BOOL_PAINT_INDENT = _dpi(15);
  249. }
  250. private void UnfocusSelection()
  251. {
  252. Focus();
  253. }
  254. private void FocusSelection()
  255. {
  256. grid_textbox.Focus();
  257. }
  258. protected override bool ProcessDialogKey(Keys keyData)
  259. {
  260. GridEntry selectedItem = this.SelectedGridItem;
  261. if (selectedItem != null
  262. && grid_textbox.Visible)
  263. {
  264. switch (keyData)
  265. {
  266. case Keys.Enter:
  267. if (TrySetEntry(selectedItem, grid_textbox.Text))
  268. UnfocusSelection();
  269. return true;
  270. case Keys.Escape:
  271. if (selectedItem.IsEditable)
  272. UpdateItem(selectedItem); // reset value
  273. UnfocusSelection();
  274. return true;
  275. case Keys.Tab:
  276. FocusSelection();
  277. grid_textbox.SelectAll();
  278. return true;
  279. default:
  280. return false;
  281. }
  282. }
  283. return base.ProcessDialogKey(keyData);
  284. }
  285. private bool TrySetEntry(GridEntry entry, object value)
  286. {
  287. if (entry == null || grid_textbox.Text.Equals(entry.ValueText))
  288. return true;
  289. if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) ||
  290. !entry.IsMerged || entry.HasMergedValue ||
  291. (!entry.HasMergedValue && grid_textbox.Text != String.Empty))
  292. {
  293. string error = null;
  294. bool changed = entry.SetValue(value, out error);
  295. if (!changed && error != null)
  296. {
  297. if (property_grid.ShowError(error, MessageBoxButtons.OKCancel) == DialogResult.Cancel)
  298. {
  299. UpdateItem(entry); // restore value, repaint, etc
  300. UnfocusSelection();
  301. }
  302. return false;
  303. }
  304. else if (changed)
  305. {
  306. entry = SelectedGridItem;
  307. }
  308. }
  309. UpdateItem(entry); // restore value, repaint, etc
  310. return true;
  311. }
  312. protected override bool IsInputKey(Keys keyData)
  313. {
  314. switch (keyData)
  315. {
  316. case Keys.Left:
  317. case Keys.Right:
  318. case Keys.Enter:
  319. case Keys.Escape:
  320. case Keys.Up:
  321. case Keys.Down:
  322. case Keys.PageDown:
  323. case Keys.PageUp:
  324. case Keys.Home:
  325. case Keys.End:
  326. return true;
  327. default:
  328. return false;
  329. }
  330. }
  331. private GridEntry MoveUpFromItem(GridEntry item, int up_count)
  332. {
  333. GridItemCollection items;
  334. int index;
  335. /* move back up the visible rows (and up the hierarchy as necessary) until
  336. up_count == 0, or we reach the top of the display */
  337. while (up_count > 0)
  338. {
  339. items = item.Parent != null ? item.Parent.GridItems : this.RootGridItem.GridItems;
  340. index = items.IndexOf(item);
  341. if (index == 0)
  342. {
  343. if (item.Parent.GridItemType == GridItemType.Root) // we're at the top row
  344. return item;
  345. item = (GridEntry)item.Parent;
  346. up_count--;
  347. }
  348. else
  349. {
  350. GridEntry prev_item = (GridEntry)items[index - 1];
  351. if (prev_item.Expandable && prev_item.Expanded && prev_item.GridItems.Count > 0)
  352. {
  353. item = (GridEntry)prev_item.GridItems[prev_item.GridItems.Count - 1];
  354. }
  355. else
  356. {
  357. item = prev_item;
  358. }
  359. up_count--;
  360. }
  361. }
  362. return item;
  363. }
  364. private GridEntry MoveDownFromItem(GridEntry item, int down_count)
  365. {
  366. while (down_count > 0)
  367. {
  368. /* if we're a parent node and we're expanded, move to our first child */
  369. if (item.Expandable && item.Expanded && item.GridItems.Count > 0)
  370. {
  371. item = (GridEntry)item.GridItems[0];
  372. down_count--;
  373. }
  374. else
  375. {
  376. GridItem searchItem = item;
  377. GridItemCollection searchItems = searchItem.Parent.GridItems;
  378. int searchIndex = searchItems.IndexOf(searchItem);
  379. while (searchIndex == searchItems.Count - 1)
  380. {
  381. searchItem = searchItem.Parent;
  382. if (searchItem == null || searchItem.Parent == null)
  383. break;
  384. searchItems = searchItem.Parent.GridItems;
  385. searchIndex = searchItems.IndexOf(searchItem);
  386. }
  387. if (searchIndex == searchItems.Count - 1)
  388. {
  389. /* if we got all the way back to the root with no nodes after
  390. us, the original item was the last one */
  391. return item;
  392. }
  393. else
  394. {
  395. item = (GridEntry)searchItems[searchIndex + 1];
  396. down_count--;
  397. }
  398. }
  399. }
  400. return item;
  401. }
  402. protected override void OnKeyDown(KeyEventArgs e)
  403. {
  404. GridEntry selectedItem = this.SelectedGridItem;
  405. if (selectedItem == null)
  406. {
  407. /* XXX not sure what MS does, but at least we shouldn't crash */
  408. base.OnKeyDown(e);
  409. return;
  410. }
  411. switch (e.KeyData & Keys.KeyCode)
  412. {
  413. case Keys.Left:
  414. if (e.Control)
  415. {
  416. if (SplitterLocation > 2 * V_INDENT)
  417. SplitterPercent -= 0.01;
  418. e.Handled = true;
  419. break;
  420. }
  421. else
  422. {
  423. /* if the node is expandable and is expanded, collapse it.
  424. otherwise, act just like the user pressed up */
  425. if (selectedItem.Expandable && selectedItem.Expanded)
  426. {
  427. selectedItem.Expanded = false;
  428. e.Handled = true;
  429. break;
  430. }
  431. else
  432. goto case Keys.Up;
  433. }
  434. case Keys.Right:
  435. if (e.Control)
  436. {
  437. if (SplitterLocation < Width)
  438. SplitterPercent += 0.01;
  439. e.Handled = true;
  440. break;
  441. }
  442. else
  443. {
  444. /* if the node is expandable and not expanded, expand it.
  445. otherwise, act just like the user pressed down */
  446. if (selectedItem.Expandable && !selectedItem.Expanded)
  447. {
  448. selectedItem.Expanded = true;
  449. e.Handled = true;
  450. break;
  451. }
  452. else
  453. goto case Keys.Down;
  454. }
  455. case Keys.Enter:
  456. /* toggle the expanded state of the selected item */
  457. if (selectedItem.Expandable)
  458. {
  459. selectedItem.Expanded = !selectedItem.Expanded;
  460. }
  461. e.Handled = true;
  462. break;
  463. case Keys.Up:
  464. this.SelectedGridItem = MoveUpFromItem(selectedItem, 1);
  465. e.Handled = true;
  466. break;
  467. case Keys.Down:
  468. this.SelectedGridItem = MoveDownFromItem(selectedItem, 1);
  469. e.Handled = true;
  470. break;
  471. case Keys.PageUp:
  472. this.SelectedGridItem = MoveUpFromItem(selectedItem, vbar.LargeChange);
  473. e.Handled = true;
  474. break;
  475. case Keys.PageDown:
  476. this.SelectedGridItem = MoveDownFromItem(selectedItem, vbar.LargeChange);
  477. e.Handled = true;
  478. break;
  479. case Keys.End:
  480. /* find the last, most deeply nested visible item */
  481. GridEntry item = (GridEntry)this.RootGridItem.GridItems[this.RootGridItem.GridItems.Count - 1];
  482. while (item.Expandable && item.Expanded)
  483. item = (GridEntry)item.GridItems[item.GridItems.Count - 1];
  484. this.SelectedGridItem = item;
  485. e.Handled = true;
  486. break;
  487. case Keys.Home:
  488. this.SelectedGridItem = (GridEntry)this.RootGridItem.GridItems[0];
  489. e.Handled = true;
  490. break;
  491. }
  492. if (!e.Handled)
  493. {
  494. if (selectedItem != null && selectedItem.IsEditable && grid_textbox.Visible && Focused)
  495. {
  496. grid_textbox.Text = "";
  497. FocusSelection();
  498. }
  499. }
  500. base.OnKeyDown(e);
  501. }
  502. #endregion
  503. #region Private Helper Methods
  504. private int SplitterLocation
  505. {
  506. get
  507. {
  508. return (int)(splitter_percent * Width);
  509. }
  510. }
  511. private double SplitterPercent
  512. {
  513. set
  514. {
  515. int old_splitter_location = SplitterLocation;
  516. splitter_percent = Math.Max(Math.Min(value, .9), .1);
  517. if (old_splitter_location != SplitterLocation)
  518. {
  519. int x = old_splitter_location > SplitterLocation ? SplitterLocation : old_splitter_location;
  520. Invalidate(new Rectangle(x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height));
  521. UpdateItem(this.SelectedGridItem);
  522. }
  523. }
  524. get
  525. {
  526. return splitter_percent;
  527. }
  528. }
  529. private bool GridLabelHitTest(int x)
  530. {
  531. bool rtl = RightToLeft == RightToLeft.Yes;
  532. if (!rtl && x >= 0 && x <= SplitterLocation)
  533. return true;
  534. if (rtl && x >= SplitterLocation && x <= Width)
  535. return true;
  536. return false;
  537. }
  538. private GridItem GetSelectedGridItem(GridItemCollection grid_items, int y, ref int current)
  539. {
  540. foreach (GridItem child_grid_item in grid_items)
  541. {
  542. if (y > current && y < current + row_height)
  543. {
  544. return child_grid_item;
  545. }
  546. current += row_height;
  547. if (child_grid_item.Expanded)
  548. {
  549. GridItem foundItem = GetSelectedGridItem(child_grid_item.GridItems, y, ref current);
  550. if (foundItem != null)
  551. return foundItem;
  552. }
  553. }
  554. return null;
  555. }
  556. private int GetVisibleItemsCount(GridEntry entry)
  557. {
  558. if (entry == null)
  559. return 0;
  560. int count = 0;
  561. foreach (GridEntry e in entry.GridItems)
  562. {
  563. count += 1;
  564. if (e.Expandable && e.Expanded)
  565. count += GetVisibleItemsCount(e);
  566. }
  567. return count;
  568. }
  569. private int GetVisibleRowsCount()
  570. {
  571. if (Height <= 0)
  572. return 0;
  573. return (this.Height - this.Padding.Vertical) / row_height;
  574. }
  575. private void UpdateScrollBar()
  576. {
  577. if (this.RootGridItem == null)
  578. return;
  579. int visibleRows = GetVisibleRowsCount();
  580. int openedItems = GetVisibleItemsCount(this.RootGridItem);
  581. if (openedItems > visibleRows)
  582. {
  583. vbar.Visible = true;
  584. vbar.SmallChange = 1;
  585. vbar.LargeChange = visibleRows;
  586. vbar.Maximum = Math.Max(0, openedItems);
  587. }
  588. else
  589. {
  590. vbar.Value = 0;
  591. vbar.Visible = false;
  592. }
  593. UpdateGridTextBoxBounds(this.SelectedGridItem);
  594. }
  595. #region Drawing Code
  596. private void DrawGridItems(GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc)
  597. {
  598. foreach (GridItem grid_item in grid_items)
  599. {
  600. DrawGridItem((GridEntry)grid_item, pevent, depth, ref yLoc);
  601. if (grid_item.Expanded)
  602. DrawGridItems(grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth + 1, ref yLoc);
  603. }
  604. }
  605. private void DrawGridItemLabel(GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect)
  606. {
  607. bool rtl = RightToLeft == RightToLeft.Yes;
  608. Font font = this.Font;
  609. Brush brush;
  610. if (grid_item.GridItemType == GridItemType.Category)
  611. {
  612. font = bold_font;
  613. brush = ResPool.GetSolidBrush(property_grid.CategoryForeColor);
  614. }
  615. else
  616. {
  617. if (grid_item == this.SelectedGridItem)
  618. {
  619. Rectangle highlight = rect;
  620. if (depth > 1)
  621. {
  622. highlight.X -= rtl ? 0 : (depth - 1) * V_INDENT;
  623. highlight.Width += (depth - 1) * V_INDENT;
  624. }
  625. pevent.Graphics.FillRectangle(SystemBrushes.Highlight, highlight);
  626. // Label
  627. brush = SystemBrushes.HighlightText;
  628. }
  629. else
  630. {
  631. brush = grid_item.IsReadOnly && !grid_item.Expandable ? inactive_text_brush : SystemBrushes.ControlText;
  632. }
  633. }
  634. pevent.Graphics.DrawString(grid_item.Label, font, brush,
  635. new Rectangle(rect.X + 1, rect.Y + ENTRY_SPACING, rect.Width - ENTRY_SPACING, rect.Height - ENTRY_SPACING),
  636. string_format);
  637. }
  638. private void DrawBoolValue(GridEntry grid_item, Graphics g, Rectangle r)
  639. {
  640. if (grid_item.Value is bool b && b == true)
  641. {
  642. g.FillRectangle(Brushes.Gray, r);
  643. g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias;
  644. g.DrawLines(ResPool.GetPen(Color.White, _dpi(1f)), new PointF[]
  645. {
  646. new PointF(r.X + _dpi(2.5f), r.Y + r.Height / 2),
  647. new PointF(r.X + r.Width / 2 - _dpi(0.5f), r.Bottom - _dpi(4f)),
  648. new PointF(r.Right - _dpi(2.5f), r.Y + _dpi(3f))
  649. });
  650. g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.None;
  651. }
  652. g.DrawRectangle(Pens.Gray, r);
  653. }
  654. private void DrawPaintValue(GridEntry grid_item, Graphics g, Rectangle r)
  655. {
  656. grid_item.PaintValue(g, r);
  657. g.DrawRectangle(Pens.Black, r);
  658. }
  659. private void DrawGridItemValue(GridEntry grid_item, PaintEventArgs pevent, int y)
  660. {
  661. if (grid_item.PropertyDescriptor == null)
  662. return;
  663. bool rtl = RightToLeft == RightToLeft.Yes;
  664. int vBarWidth = vbar.Visible ? vbar.Width : 0;
  665. int xLoc = (rtl ? vBarWidth : SplitterLocation) + ENTRY_SPACING;
  666. int widthAdj = rtl ? 0 : vBarWidth;
  667. if (grid_item.IsBool)
  668. {
  669. int xRect = rtl ? SplitterLocation - BOOL_PAINT_INDENT : xLoc + _dpi(2);
  670. DrawBoolValue(grid_item, pevent.Graphics, new Rectangle(xRect, y + (row_height - BOOL_PAINT_WIDTH) / 2, BOOL_PAINT_WIDTH, BOOL_PAINT_WIDTH));
  671. xLoc += rtl ? 0 : BOOL_PAINT_INDENT;
  672. widthAdj += rtl ? BOOL_PAINT_INDENT : 0;
  673. }
  674. if (grid_item.PaintValueSupported)
  675. {
  676. int xRect = rtl ? SplitterLocation - VALUE_PAINT_WIDTH - ENTRY_SPACING * 2 : xLoc;
  677. DrawPaintValue(grid_item, pevent.Graphics, new Rectangle(xRect, y + 2, VALUE_PAINT_WIDTH + 1, row_height - ENTRY_SPACING * 2));
  678. xLoc += rtl ? 0 : VALUE_PAINT_INDENT;
  679. widthAdj += rtl ? VALUE_PAINT_INDENT + ENTRY_SPACING : 0;
  680. }
  681. Font font = this.Font;
  682. if (grid_item.IsResetable || !grid_item.HasDefaultValue)
  683. font = bold_font;
  684. Brush brush = grid_item.IsReadOnly && !grid_item.Expandable ? inactive_text_brush : SystemBrushes.ControlText;
  685. string valueText = String.Empty;
  686. if (!grid_item.IsMerged || grid_item.IsMerged && grid_item.HasMergedValue)
  687. {
  688. if (grid_item.IsPassword)
  689. valueText = new String(PASSWORD_PAINT_CHAR, grid_item.ValueText.Length);
  690. else
  691. valueText = grid_item.ValueText;
  692. }
  693. pevent.Graphics.DrawString(valueText, font, brush,
  694. new RectangleF(xLoc, y + ENTRY_SPACING, (rtl ? SplitterLocation - ENTRY_SPACING : Width) - xLoc - widthAdj - 2, row_height - ENTRY_SPACING * 2),
  695. string_format);
  696. }
  697. private void DrawGridItem(GridEntry grid_item, PaintEventArgs pevent, int depth, ref int yLoc)
  698. {
  699. bool rtl = RightToLeft == RightToLeft.Yes;
  700. if (yLoc > -row_height && yLoc < Height)
  701. {
  702. // Left column
  703. pevent.Graphics.FillRectangle(ResPool.GetSolidBrush(property_grid.LineColor),
  704. rtl ? Width - V_INDENT : 0, yLoc, V_INDENT, row_height);
  705. if (grid_item.GridItemType == GridItemType.Category)
  706. {
  707. var rect = new Rectangle(rtl ? 0 : depth * V_INDENT, yLoc, Width - (depth * V_INDENT), row_height);
  708. pevent.Graphics.FillRectangle(ResPool.GetSolidBrush(property_grid.LineColor), rect);
  709. DrawGridItemLabel(grid_item, pevent, depth, rect);
  710. }
  711. else
  712. {
  713. int labelWidth = (rtl ? Width - SplitterLocation : SplitterLocation) - depth * V_INDENT;
  714. DrawGridItemLabel(grid_item, pevent, depth,
  715. new Rectangle(rtl ? SplitterLocation : depth * V_INDENT, yLoc, labelWidth, row_height));
  716. DrawGridItemValue(grid_item, pevent, yLoc);
  717. Pen pen = ResPool.GetPen(property_grid.LineColor);
  718. // vertical divider line
  719. pevent.Graphics.DrawLine(pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height);
  720. // draw the horizontal line
  721. pevent.Graphics.DrawLine(pen, 0, yLoc + row_height, Width, yLoc + row_height);
  722. }
  723. if (grid_item.Expandable)
  724. {
  725. int y = yLoc + row_height / 2;
  726. grid_item.PlusMinusBounds = DrawPlusMinus(pevent.Graphics, rtl ? Width - (depth - 1) * V_INDENT - ENTRY_SPACING : (depth - 1) * V_INDENT,
  727. y, grid_item.Expanded, grid_item == this.SelectedGridItem, depth - 1);
  728. }
  729. }
  730. grid_item.Top = yLoc;
  731. yLoc += row_height;
  732. }
  733. private Rectangle DrawPlusMinus(Graphics g, int x, int y, bool expanded, bool selected, int level)
  734. {
  735. Color color = selected && level > 0 ? Drawing.SystemColors.HighlightText : property_grid.ViewForeColor;
  736. Pen pen = ResPool.GetPen(color, _dpi(1.5f));
  737. g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias;
  738. bool rtl = RightToLeft == RightToLeft.Yes;
  739. int _rtl = rtl ? -1 : 1;
  740. int _4 = _dpi(4);
  741. int _8 = _dpi(8);
  742. int _10 = _dpi(10);
  743. Rectangle bounds = new Rectangle(rtl ? x - _10 : x + _dpi(2), y - _4, _10, _10);
  744. if (!expanded)
  745. {
  746. x += _dpi(5) * _rtl;
  747. y -= _4;
  748. g.DrawLines(pen, new PointF[]
  749. {
  750. new PointF(x, y),
  751. new PointF(x + _4 * _rtl, y + _4),
  752. new PointF(x, y + _8)
  753. });
  754. }
  755. else
  756. {
  757. x += _dpi(3) * _rtl;
  758. y -= _dpi(1);
  759. g.DrawLines(pen, new PointF[]
  760. {
  761. new PointF(x, y),
  762. new PointF(x + _4 * _rtl, y + _4),
  763. new PointF(x + _8 * _rtl, y)
  764. });
  765. }
  766. g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.None;
  767. return bounds;
  768. }
  769. #endregion
  770. #region Event Handling
  771. private void RedrawEvent(object sender, System.EventArgs e)
  772. {
  773. Refresh();
  774. }
  775. #endregion
  776. private void listBox_MouseUp(object sender, MouseEventArgs e)
  777. {
  778. AcceptListBoxSelection(sender);
  779. }
  780. private void listBox_KeyDown(object sender, KeyEventArgs e)
  781. {
  782. switch (e.KeyData & Keys.KeyCode)
  783. {
  784. case Keys.Enter:
  785. AcceptListBoxSelection(sender);
  786. return;
  787. case Keys.Escape:
  788. CloseDropDown();
  789. return;
  790. }
  791. }
  792. private void AcceptListBoxSelection(object sender)
  793. {
  794. GridEntry entry = this.SelectedGridItem;
  795. if (entry != null)
  796. {
  797. grid_textbox.Text = (string)((ListBox)sender).SelectedItem;
  798. CloseDropDown();
  799. if (TrySetEntry(entry, grid_textbox.Text))
  800. UnfocusSelection();
  801. }
  802. }
  803. private void DropDownButtonClicked(object sender, EventArgs e)
  804. {
  805. DropDownEdit();
  806. }
  807. private void DropDownEdit()
  808. {
  809. GridEntry entry = this.SelectedGridItem;
  810. if (entry == null)
  811. return;
  812. if (dropdown != null && dropdown.Visible)
  813. {
  814. CloseDropDown();
  815. return;
  816. }
  817. if (entry.HasCustomEditor)
  818. {
  819. entry.EditValue(this);
  820. }
  821. else
  822. {
  823. ICollection std_values = entry.AcceptedValues;
  824. if (std_values != null)
  825. {
  826. if (dropdown_list == null)
  827. {
  828. dropdown_list = new ListBox();
  829. dropdown_list.BorderStyle = BorderStyle.None;
  830. dropdown_list.DrawMode = DrawMode.OwnerDrawFixed;
  831. dropdown_list.DrawItem += (s, e) =>
  832. {
  833. e.DrawBackground();
  834. TextRenderer.DrawText(e.Graphics, dropdown_list.Items[e.Index].ToString(), e.Font, e.Bounds, e.ForeColor, TextFormatFlags.VerticalCenter);
  835. };
  836. dropdown_list.KeyDown += new KeyEventHandler(listBox_KeyDown);
  837. dropdown_list.MouseUp += new MouseEventHandler(listBox_MouseUp);
  838. }
  839. float rescale = (float)dropdown_list.DeviceDpi / DeviceDpi;
  840. dropdown_list.Items.Clear();
  841. dropdown_list.ItemHeight = (int)(row_height * rescale);
  842. int selected_index = 0;
  843. int i = 0;
  844. string valueText = entry.ValueText;
  845. foreach (object obj in std_values)
  846. {
  847. dropdown_list.Items.Add(obj);
  848. if (valueText != null && valueText.Equals(obj))
  849. selected_index = i;
  850. i++;
  851. }
  852. dropdown_list.Height = dropdown_list.ItemHeight * Math.Min(dropdown_list.Items.Count, 10) + _dpi(2);
  853. dropdown_list.Width = Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0) - 1;
  854. if (std_values.Count > 0)
  855. dropdown_list.SelectedIndex = selected_index;
  856. DropDownControl(dropdown_list);
  857. }
  858. }
  859. }
  860. private void DialogButtonClicked(object sender, EventArgs e)
  861. {
  862. GridEntry entry = this.SelectedGridItem as GridEntry;
  863. if (entry != null && entry.HasCustomEditor)
  864. entry.EditValue((IWindowsFormsEditorService)this);
  865. }
  866. private void VScrollBar_HandleValueChanged(object sender, EventArgs e)
  867. {
  868. UpdateView();
  869. }
  870. private void grid_textbox_ToggleValue(object sender, EventArgs args)
  871. {
  872. ToggleValue(this.SelectedGridItem);
  873. }
  874. private void grid_textbox_KeyDown(object sender, KeyEventArgs e)
  875. {
  876. switch (e.KeyData & Keys.KeyCode)
  877. {
  878. case Keys.Down:
  879. if (e.Alt)
  880. {
  881. DropDownEdit();
  882. e.Handled = true;
  883. }
  884. break;
  885. }
  886. }
  887. private void grid_textbox_Validate(object sender, CancelEventArgs args)
  888. {
  889. if (!TrySetEntry(this.SelectedGridItem, grid_textbox.Text))
  890. args.Cancel = true;
  891. }
  892. private void ToggleValue(GridEntry entry)
  893. {
  894. if (entry != null && !entry.IsReadOnly && entry.GridItemType == GridItemType.Property)
  895. entry.ToggleValue();
  896. }
  897. internal void UpdateItem(GridEntry entry)
  898. {
  899. if (entry == null || entry.GridItemType == GridItemType.Category ||
  900. entry.GridItemType == GridItemType.Root)
  901. {
  902. grid_textbox.Visible = false;
  903. InvalidateItem(entry);
  904. return;
  905. }
  906. if (this.SelectedGridItem == entry)
  907. {
  908. SuspendLayout();
  909. grid_textbox.Visible = false;
  910. if (entry.IsResetable || !entry.HasDefaultValue)
  911. grid_textbox.Font = bold_font;
  912. else
  913. grid_textbox.Font = this.Font;
  914. if (entry.IsReadOnly)
  915. {
  916. grid_textbox.DropDownButtonVisible = false;
  917. grid_textbox.DialogButtonVisible = false;
  918. grid_textbox.ReadOnly = true;
  919. grid_textbox.ForeColor = entry.Expandable ? Drawing.SystemColors.ControlText : Drawing.SystemColors.GrayText;
  920. }
  921. else
  922. {
  923. grid_textbox.DropDownButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.DropDown || entry.AcceptedValues != null;
  924. grid_textbox.DialogButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.Modal;
  925. grid_textbox.ForeColor = Drawing.SystemColors.ControlText;
  926. grid_textbox.ReadOnly = !entry.IsEditable;
  927. }
  928. UpdateGridTextBoxBounds(entry);
  929. grid_textbox.PasswordChar = entry.IsPassword ? PASSWORD_TEXT_CHAR : '\0';
  930. grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText;
  931. grid_textbox.Visible = true;
  932. InvalidateItem(entry);
  933. ResumeLayout(false);
  934. }
  935. else
  936. {
  937. grid_textbox.Visible = false;
  938. }
  939. }
  940. private void UpdateGridTextBoxBounds(GridEntry entry)
  941. {
  942. if (entry == null || this.RootGridItem == null)
  943. return;
  944. bool rtl = RightToLeft == RightToLeft.Yes;
  945. int y = -vbar.Value * row_height;
  946. CalculateItemY(entry, this.RootGridItem.GridItems, ref y);
  947. int vbarWidth = vbar.Visible ? vbar.Width : 0;
  948. int pvWidth = ENTRY_SPACING;
  949. if (entry.PaintValueSupported)
  950. pvWidth += VALUE_PAINT_INDENT + (rtl ? ENTRY_SPACING : 0);
  951. if (entry.IsBool)
  952. pvWidth += BOOL_PAINT_INDENT + (rtl ? ENTRY_SPACING : 0);
  953. int x = rtl ? vbarWidth + 1 : SplitterLocation + pvWidth;
  954. int width = rtl ? SplitterLocation - x - pvWidth : Width - x - vbarWidth - 1;
  955. int height = row_height - 1;
  956. if (y == 0 && DeviceDpi > 120)
  957. {
  958. y = 1;
  959. height -= 1;
  960. }
  961. grid_textbox.SetBounds(x, y + 1, width, height);
  962. }
  963. // Calculates the sum of the heights of all items before the one
  964. //
  965. private bool CalculateItemY(GridEntry entry, GridItemCollection items, ref int y)
  966. {
  967. foreach (GridItem item in items)
  968. {
  969. if (item == entry)
  970. return true;
  971. y += row_height;
  972. if (item.Expandable && item.Expanded)
  973. if (CalculateItemY(entry, item.GridItems, ref y))
  974. return true;
  975. }
  976. return false;
  977. }
  978. private void ScrollToItem(GridEntry item)
  979. {
  980. if (item == null || this.RootGridItem == null)
  981. return;
  982. int itemY = -vbar.Value * row_height;
  983. int value = vbar.Value; ;
  984. CalculateItemY(item, this.RootGridItem.GridItems, ref itemY);
  985. if (itemY < 0) // the new item is above the viewable area
  986. value += itemY / row_height;
  987. else if (itemY + row_height > Height) // the new item is below the viewable area
  988. value += ((itemY + row_height) - Height) / row_height + 1;
  989. if (value >= vbar.Minimum && value <= vbar.Maximum)
  990. vbar.Value = value;
  991. }
  992. internal void SelectItem(GridEntry oldItem, GridEntry newItem)
  993. {
  994. if (oldItem != null)
  995. {
  996. InvalidateItemLabel(oldItem);
  997. }
  998. if (newItem != null)
  999. {
  1000. UpdateItem(newItem);
  1001. ScrollToItem(newItem);
  1002. }
  1003. else
  1004. {
  1005. grid_textbox.Visible = false;
  1006. vbar.Visible = false;
  1007. }
  1008. }
  1009. internal void UpdateView()
  1010. {
  1011. UpdateScrollBar();
  1012. Invalidate();
  1013. Update();
  1014. UpdateItem(this.SelectedGridItem);
  1015. }
  1016. internal void ExpandItem(GridEntry item)
  1017. {
  1018. UpdateItem(this.SelectedGridItem);
  1019. Invalidate(new Rectangle(0, item.Top, Width, Height - item.Top));
  1020. }
  1021. internal void CollapseItem(GridEntry item)
  1022. {
  1023. UpdateItem(this.SelectedGridItem);
  1024. Invalidate(new Rectangle(0, item.Top, Width, Height - item.Top));
  1025. }
  1026. private void ShowDropDownControl(Control control, bool resizeable)
  1027. {
  1028. float rescale = (float)control.DeviceDpi / this.DeviceDpi;
  1029. control.Width = (int)(Math.Max(grid_textbox.Width * rescale, control.Width));
  1030. control.Font = new Font(Font.FontFamily, Font.Size * rescale, Font.Style);
  1031. control.RightToLeft = RightToLeft;
  1032. dropdown = new ToolStripDropDown();
  1033. dropdown.Items.Add(new ToolStripControlHost(control));
  1034. if (resizeable)
  1035. {
  1036. dropdown.Items.Add(new ToolStripControlHost(new DropDownResizer(control)));
  1037. }
  1038. int x = 0;
  1039. if (RightToLeft == RightToLeft.Yes)
  1040. {
  1041. x = SystemInformation.MenuDropAlignment ? 0 : control.Width + _dpi(ENTRY_SPACING + 1);
  1042. }
  1043. else
  1044. {
  1045. x = SystemInformation.MenuDropAlignment ? grid_textbox.Width : (grid_textbox.Width - (int)(control.Width / rescale)) - _dpi(ENTRY_SPACING);
  1046. }
  1047. dropdown.Show(grid_textbox, x, row_height - 2);
  1048. dropdown.Closed += (s, e) =>
  1049. {
  1050. // control is reused so we need to detach it from parent
  1051. (s as ToolStripDropDown).Items.Clear();
  1052. // SWF consistency: return correct size to the calling code (in case we need to save the control size)
  1053. if (resizeable)
  1054. control.Size = new Drawing.Size((int)(control.Width * rescale), (int)(control.Height * rescale));
  1055. };
  1056. // return to the calling method when dropdown is closed
  1057. while (dropdown != null && dropdown.Visible)
  1058. {
  1059. Application.DoEvents();
  1060. }
  1061. dropdown = null;
  1062. }
  1063. #endregion
  1064. #region IWindowsFormsEditorService Members
  1065. public void CloseDropDown()
  1066. {
  1067. dropdown?.Close();
  1068. dropdown = null;
  1069. }
  1070. public void DropDownControl(Control control)
  1071. {
  1072. bool resizeable = this.SelectedGridItem != null ? SelectedGridItem.EditorResizeable : false;
  1073. ShowDropDownControl(control, resizeable);
  1074. }
  1075. public System.Windows.Forms.DialogResult ShowDialog(Form dialog)
  1076. {
  1077. return dialog.ShowDialog();
  1078. }
  1079. #endregion
  1080. private class DropDownResizer : UserControl
  1081. {
  1082. private Control otherControl;
  1083. protected override void OnMouseMove(MouseEventArgs e)
  1084. {
  1085. base.OnMouseMove(e);
  1086. int _16 = _dpi(16);
  1087. bool rtl = RightToLeft == RightToLeft.Yes;
  1088. if (e.Button == MouseButtons.None)
  1089. {
  1090. if (e.X < _16 && !rtl)
  1091. Cursor = Cursors.SizeNESW;
  1092. else if (e.X > Width - _16 && rtl)
  1093. Cursor = Cursors.SizeNWSE;
  1094. else
  1095. Cursor = Cursors.Default;
  1096. }
  1097. if (e.Button == MouseButtons.Left)
  1098. {
  1099. var popup = WpfHelper.FindParent<System.Windows.Controls.Primitives.Popup>(this.control);
  1100. if (Cursor == Cursors.SizeNESW)
  1101. {
  1102. if (!SystemInformation.MenuDropAlignment)
  1103. popup.HorizontalOffset += e.X / DpiScale;
  1104. Width -= e.X;
  1105. }
  1106. else if (Cursor == Cursors.SizeNWSE)
  1107. {
  1108. if (!SystemInformation.MenuDropAlignment)
  1109. popup.HorizontalOffset += (Width - e.X) / DpiScale;
  1110. Width = e.X;
  1111. }
  1112. otherControl.Width = Width;
  1113. otherControl.Height += e.Y;
  1114. }
  1115. }
  1116. protected override void OnPaint(PaintEventArgs e)
  1117. {
  1118. Graphics g = e.Graphics;
  1119. Pen p = Pens.Gray;
  1120. int _4 = _dpi(4);
  1121. int _8 = _dpi(8);
  1122. int _12 = _dpi(12);
  1123. int _16 = _dpi(16);
  1124. g.DrawLine(p, 0, 0, Width, 0);
  1125. if (RightToLeft == RightToLeft.Yes)
  1126. {
  1127. g.DrawLine(p, Width, _8, Width - _8, _16);
  1128. g.DrawLine(p, Width, _12, Width - _4, _16);
  1129. }
  1130. else
  1131. {
  1132. g.DrawLine(p, 0, _8, _8, _16);
  1133. g.DrawLine(p, 0, _12, _4, _16);
  1134. }
  1135. }
  1136. public DropDownResizer(Control otherControl)
  1137. {
  1138. this.otherControl = otherControl;
  1139. RightToLeft = otherControl.RightToLeft;
  1140. Height = _dpi(16);
  1141. Width = otherControl.Width;
  1142. }
  1143. }
  1144. }
  1145. }