Advertisement
Jimi2000

WinForms ColorEditor

Dec 10th, 2022
691
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 46.86 KB | Software | 0 0
  1. namespace System.Drawing.Design {
  2.  
  3.     using Accessibility;
  4.     using Microsoft.Win32;
  5.     using System;
  6.     using System.Collections;
  7.     using System.ComponentModel;
  8.     using System.Diagnostics;
  9.     using System.Diagnostics.CodeAnalysis;
  10.     using System.Drawing;
  11.     using System.Globalization;
  12.     using System.IO;
  13.     using System.Reflection;
  14.     using System.Runtime.InteropServices;
  15.     using System.Runtime.Serialization.Formatters;
  16.     using System.Windows.Forms;
  17.     using System.Windows.Forms.ComponentModel;
  18.     using System.Windows.Forms.Design;
  19.  
  20.     ///  
  21.     ///
  22.     ///  
  23.     ///     Provides an editor for visually picking a color.
  24.     ///
  25.     [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
  26.     public class ColorEditor : UITypeEditor {
  27.  
  28.         private ColorUI colorUI;
  29.  
  30.         ///
  31.         ///  
  32.         ///     Edits the given object value using the editor style
  33.         ///     provided by ColorEditor.GetEditStyle.
  34.         ///
  35.         [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
  36.         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust.
  37.         public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
  38.  
  39.             object returnValue = value;
  40.  
  41.             if (provider != null) {
  42.                 IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
  43.  
  44.                 if (edSvc != null) {
  45.                     if (colorUI == null) {
  46.                         colorUI = new ColorUI(this);
  47.                     }
  48.                     colorUI.Start(edSvc, value);
  49.                     edSvc.DropDownControl(colorUI);
  50.  
  51.                     if (colorUI.Value != null && ((Color) colorUI.Value) != Color.Empty) {
  52.                             value = colorUI.Value;
  53.                     }
  54.  
  55.  
  56.                     colorUI.End();
  57.                 }
  58.             }
  59.  
  60.             return value;
  61.         }
  62.  
  63.         ///
  64.         ///  
  65.         ///     Gets the editing style of the Edit method. If the method
  66.         ///     is not supported, this will return UITypeEditorEditStyle.None.
  67.         ///  
  68.         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust.
  69.         public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
  70.             return UITypeEditorEditStyle.DropDown;
  71.         }
  72.  
  73.         ///  
  74.         ///  
  75.         ///     Gets a value indicating if this editor supports the painting of a representation
  76.         ///     of an object's value.
  77.         ///
  78.         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust.
  79.         public override bool GetPaintValueSupported(ITypeDescriptorContext context) {
  80.             return true;
  81.         }
  82.  
  83.         ///  
  84.         ///
  85.         ///     Paints a representative value of the given object to the provided
  86.         ///     canvas. Painting should be done within the boundaries of the
  87.         ///     provided rectangle.
  88.         ///
  89.         [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
  90.         [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  91.         [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")] //Benign code
  92.         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] // everything in this assembly is full trust.
  93.         public override void PaintValue(PaintValueEventArgs e) {
  94.             if (e.Value is Color) {
  95.                 Color color = (Color)e.Value;
  96.                 SolidBrush b = new SolidBrush(color);
  97.                 e.Graphics.FillRectangle(b, e.Bounds);
  98.                 b.Dispose();
  99.             }
  100.         }
  101.  
  102.         ///
  103.         ///     A control to display the color palette.
  104.         ///
  105.         private class ColorPalette : Control {
  106.  
  107.             public const int CELLS_ACROSS = 8;
  108.             public const int CELLS_DOWN = 8;
  109.             public const int CELLS_CUSTOM = 16; // last cells
  110.             public const int CELLS = CELLS_ACROSS * CELLS_DOWN;
  111.             public const int CELL_SIZE = 16;
  112.             public const int MARGIN = 8;
  113.  
  114.             private static readonly int[] staticCells = new int[] {
  115.                 0x00ffffff, 0x00c0c0ff, 0x00c0e0ff, 0x00c0ffff,
  116.                 0x00c0ffc0, 0x00ffffc0, 0x00ffc0c0, 0x00ffc0ff,
  117.  
  118.                 0x00e0e0e0, 0x008080ff, 0x0080c0ff, 0x0080ffff,
  119.                 0x0080ff80, 0x00ffff80, 0x00ff8080, 0x00ff80ff,
  120.  
  121.                 0x00c0c0c0, 0x000000ff, 0x000080ff, 0x0000ffff,
  122.                 0x0000ff00, 0x00ffff00, 0x00ff0000, 0x00ff00ff,
  123.  
  124.                 0x00808080, 0x000000c0, 0x000040c0, 0x0000c0c0,
  125.                 0x0000c000, 0x00c0c000, 0x00c00000, 0x00c000c0,
  126.  
  127.                 0x00404040, 0x00000080, 0x00004080, 0x00008080,
  128.                 0x00008000, 0x00808000, 0x00800000, 0x00800080,
  129.  
  130.                 0x00000000, 0x00000040, 0x00404080, 0x00004040,
  131.                 0x00004000, 0x00404000, 0x00400000, 0x00400040
  132.             };
  133.  
  134.             private Color[] staticColors;
  135.             private Color selectedColor;
  136.             private Point focus = new Point(0, 0);
  137.             private Color[] customColors;
  138.             private EventHandler onPicked;
  139.             private ColorUI colorUI;
  140.  
  141.             public ColorPalette(ColorUI colorUI, Color[] customColors) {
  142.                 this.colorUI = colorUI;
  143.                 SetStyle(ControlStyles.Opaque, true);
  144.  
  145.                 BackColor = SystemColors.Control;
  146.  
  147.                 Size = new Size(CELLS_ACROSS * (CELL_SIZE + MARGIN) + MARGIN + 2,
  148.                                 CELLS_DOWN * (CELL_SIZE + MARGIN) + MARGIN + 2);
  149.  
  150.                 staticColors = new Color[CELLS - CELLS_CUSTOM];
  151.  
  152.                 for (int i = 0; i < staticCells.Length; i++)
  153.                     staticColors[i] = ColorTranslator.FromOle(staticCells[i]);
  154.  
  155.                 this.customColors = customColors;
  156.             }
  157.  
  158.             [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  159.             public Color[] CustomColors {
  160.                 get { return customColors;}
  161.             }
  162.  
  163.             internal int FocusedCell {
  164.                 get {
  165.                     return Get1DFrom2D(focus);
  166.                 }
  167.             }
  168.  
  169.             public Color SelectedColor {
  170.                 get {
  171.                     return selectedColor;
  172.                 }
  173.                 set {
  174.                     if (!value.Equals(selectedColor)) {
  175.                         InvalidateSelection();
  176.                         selectedColor = value;
  177.  
  178.                         SetFocus(GetCellFromColor(value));
  179.                         InvalidateSelection();
  180.                     }
  181.                 }
  182.             }
  183.  
  184.             public event EventHandler Picked {
  185.                 add {
  186.                     onPicked += value;
  187.                 }
  188.                 remove {
  189.                     onPicked -= value;
  190.                 }
  191.             }
  192.  
  193.             protected override AccessibleObject CreateAccessibilityInstance() {
  194.                 return new ColorPaletteAccessibleObject(this);
  195.             }
  196.  
  197.             protected void OnPicked(EventArgs e) {
  198.                 if (onPicked != null) {
  199.                     onPicked(this, e);
  200.                 }
  201.             }
  202.  
  203.             static private void FillRectWithCellBounds(int across, int down, ref Rectangle rect) {
  204.  
  205.                 rect.X = MARGIN + across * (CELL_SIZE + MARGIN);
  206.                 rect.Y = MARGIN + down * (CELL_SIZE + MARGIN);
  207.                 rect.Width = CELL_SIZE;
  208.                 rect.Height = CELL_SIZE;
  209.             }
  210.  
  211.             private Point GetCellFromColor(Color c) {
  212.                 for (int y = 0; y < CELLS_DOWN; y++) {
  213.                     for (int x = 0; x < CELLS_ACROSS; x++) {
  214.                         if (GetColorFromCell(x, y).Equals(c)) {
  215.                             return new Point(x, y);
  216.                         }
  217.                     }
  218.                 }
  219.                 return Point.Empty;
  220.             }
  221.  
  222.             private Color GetColorFromCell(int across, int down) {
  223.                 return GetColorFromCell(Get1DFrom2D(across, down));
  224.             }
  225.  
  226.             private Color GetColorFromCell(int index) {
  227.  
  228.                 if (index < CELLS - CELLS_CUSTOM)
  229.                     return staticColors[index];
  230.                 else
  231.                     return customColors[index - CELLS + CELLS_CUSTOM];
  232.             }
  233.  
  234.             static private Point GetCell2DFromLocationMouse(int x, int y) {
  235.  
  236.                 int across = x / (CELL_SIZE + MARGIN);
  237.                 int down = y / (CELL_SIZE + MARGIN);
  238.  
  239.                 // Check if we're outside the cells
  240.                 //
  241.                 if (across < 0 || down < 0 || across >= CELLS_ACROSS || down >= CELLS_DOWN) {
  242.                     return new Point(-1, -1);
  243.                 }
  244.  
  245.                 // Check if we're in the margin
  246.                 //
  247.                 if ((x - (CELL_SIZE + MARGIN) * across) < MARGIN ||
  248.                     (y - (CELL_SIZE + MARGIN) * down) < MARGIN) {
  249.                     return new Point(-1, -1);
  250.                 }
  251.  
  252.                 return new Point(across, down);
  253.             }
  254.  
  255.             static private int GetCellFromLocationMouse(int x, int y) {
  256.                 return Get1DFrom2D(GetCell2DFromLocationMouse(x, y));
  257.             }
  258.  
  259.             static private int Get1DFrom2D(Point pt) {
  260.                 return Get1DFrom2D(pt.X, pt.Y);
  261.             }
  262.  
  263.             static private int Get1DFrom2D(int x, int y) {
  264.                 if (x == -1 || y == -1) {
  265.                     return -1;
  266.                 }
  267.                 return x + CELLS_ACROSS*y;
  268.             }
  269.  
  270.             static internal Point Get2DFrom1D(int cell) {
  271.                 int x = cell % CELLS_ACROSS;
  272.                 int y = cell / CELLS_ACROSS;
  273.                 return new Point(x, y);
  274.             }
  275.  
  276.             private void InvalidateSelection() {
  277.                 for (int y = 0; y < CELLS_DOWN; y++) {
  278.                     for (int x = 0; x < CELLS_ACROSS; x++) {
  279.                         if (SelectedColor.Equals(GetColorFromCell(x, y))) {
  280.                             Rectangle r = new Rectangle();
  281.                             FillRectWithCellBounds(x, y, ref r);
  282.                             Invalidate(Rectangle.Inflate(r, 5, 5));
  283.                             break;
  284.                         }
  285.                     }
  286.                 }
  287.             }
  288.             private void InvalidateFocus() {
  289.                 Rectangle r = new Rectangle();
  290.                 FillRectWithCellBounds(focus.X, focus.Y, ref r);
  291.                 Invalidate(Rectangle.Inflate(r, 5, 5));
  292.                 UnsafeNativeMethods.NotifyWinEvent((int)AccessibleEvents.Focus, new HandleRef(this, this.Handle), UnsafeNativeMethods.OBJID_CLIENT, 1 + Get1DFrom2D(focus.X, focus.Y));
  293.             }
  294.  
  295.             protected override bool IsInputKey(System.Windows.Forms.Keys keyData) {
  296.                 switch (keyData) {
  297.                     case Keys.Left:
  298.                     case Keys.Right:
  299.                     case Keys.Up:
  300.                     case Keys.Down:
  301.                     case Keys.Enter:
  302.                         return true;
  303.  
  304.                         // If we don't do this in ProcessDialogKey, VS will take it from us (ASURT 37231)
  305.                     case Keys.F2:
  306.                         return false;
  307.                 }
  308.                 return base.IsInputKey(keyData);
  309.             }
  310.  
  311.             protected virtual void LaunchDialog(int customIndex) {
  312.                 Invalidate();
  313.                 colorUI.EditorService.CloseDropDown(); // It will be closed anyway as soon as it sees the WM_ACTIVATE
  314.                 CustomColorDialog dialog = new CustomColorDialog();
  315.  
  316.                 IntPtr hwndFocus = UnsafeNativeMethods.GetFocus();
  317.                 try {
  318.  
  319.                     DialogResult result = dialog.ShowDialog();
  320.                     if (result != DialogResult.Cancel) {
  321.                         Color color = dialog.Color;
  322.                         customColors[customIndex] = dialog.Color;
  323.                         SelectedColor = customColors[customIndex];
  324.                         OnPicked(EventArgs.Empty);
  325.                     }
  326.  
  327.                     dialog.Dispose();
  328.                 }
  329.                 finally {
  330.                     if (hwndFocus != IntPtr.Zero) {
  331.                         UnsafeNativeMethods.SetFocus(new HandleRef(null, hwndFocus));
  332.                     }
  333.                 }
  334.             }
  335.  
  336.             protected override void OnGotFocus(EventArgs e) {
  337.                 base.OnGotFocus(e);
  338.                 InvalidateFocus();
  339.             }
  340.  
  341.             protected override void OnKeyDown(KeyEventArgs e) {
  342.                 base.OnKeyDown(e);
  343.                 switch (e.KeyCode) {
  344.                     case Keys.Enter:
  345.                         SelectedColor = GetColorFromCell(focus.X, focus.Y);
  346.                         InvalidateFocus();
  347.                         OnPicked(EventArgs.Empty);
  348.                         break;
  349.                     case Keys.Space:
  350.                         SelectedColor = GetColorFromCell(focus.X, focus.Y);
  351.                         InvalidateFocus();
  352.                         break;
  353.                     case Keys.Left:
  354.                         SetFocus(new Point(focus.X - 1, focus.Y));
  355.                         break;
  356.                     case Keys.Right:
  357.                         SetFocus(new Point(focus.X + 1, focus.Y));
  358.                         break;
  359.                     case Keys.Up:
  360.                         SetFocus(new Point(focus.X, focus.Y - 1));
  361.                         break;
  362.                     case Keys.Down:
  363.                         SetFocus(new Point(focus.X, focus.Y + 1));
  364.                         break;
  365.                 }
  366.             }
  367.             protected override void OnLostFocus(EventArgs e) {
  368.                 base.OnLostFocus(e);
  369.                 InvalidateFocus();
  370.             }
  371.  
  372.             protected override void OnMouseDown(MouseEventArgs me) {
  373.                 base.OnMouseDown(me);
  374.                 if (me.Button == MouseButtons.Left) {
  375.                     Point cell2D = GetCell2DFromLocationMouse(me.X,me.Y);
  376.  
  377.                     if (cell2D.X != -1 && cell2D.Y != -1 && cell2D != focus) {
  378.                         SetFocus(cell2D);
  379.                     }
  380.                 }
  381.  
  382.             }
  383.             protected override void OnMouseMove(MouseEventArgs me) {
  384.                 base.OnMouseMove(me);
  385.                 if (me.Button == MouseButtons.Left &&
  386.                     Bounds.Contains(me.X, me.Y)) {
  387.                     Point cell2D = GetCell2DFromLocationMouse(me.X,me.Y);
  388.  
  389.                     if (cell2D.X != -1 && cell2D.Y != -1 && cell2D != focus) {
  390.                         SetFocus(cell2D);
  391.                     }
  392.                 }
  393.             }
  394.             protected override void OnMouseUp(MouseEventArgs me) {
  395.                 base.OnMouseUp(me);
  396.  
  397.                 if (me.Button == MouseButtons.Left) {
  398.                     Point cell2D = GetCell2DFromLocationMouse(me.X,me.Y);
  399.                     if (cell2D.X != -1 && cell2D.Y != -1) {
  400.                         SetFocus(cell2D);
  401.                         SelectedColor = GetColorFromCell(focus.X, focus.Y);
  402.                         OnPicked(EventArgs.Empty);
  403.                     }
  404.                 }
  405.                 else if (me.Button == MouseButtons.Right) {
  406.                     int cell = GetCellFromLocationMouse(me.X,me.Y);
  407.                     if (cell != -1 && cell >= (CELLS - CELLS_CUSTOM) && cell < CELLS) {
  408.                         LaunchDialog(cell - CELLS + CELLS_CUSTOM);
  409.                     }
  410.                 }
  411.             }
  412.  
  413.             protected override void OnPaint(PaintEventArgs pe) {
  414.  
  415.                 Graphics g = pe.Graphics;
  416.                 g.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
  417.                 Rectangle rect = new Rectangle();
  418.  
  419.                 rect.Width = CELL_SIZE;
  420.                 rect.Height = CELL_SIZE;
  421.                 rect.X = MARGIN;
  422.                 rect.Y = MARGIN;
  423.                 bool drawSelected =false;
  424.  
  425.                 for (int y = 0; y < CELLS_DOWN; y++) {
  426.                     for (int x = 0; x < CELLS_ACROSS; x++) {
  427.  
  428.                         Color cur = GetColorFromCell(Get1DFrom2D(x,y));
  429.  
  430.                         FillRectWithCellBounds(x, y, ref rect);
  431.  
  432.                         if (cur.Equals(SelectedColor) && !drawSelected) {
  433.                             ControlPaint.DrawBorder(g, Rectangle.Inflate(rect, 3, 3), SystemColors.ControlText, ButtonBorderStyle.Solid);
  434.                             drawSelected = true;
  435.                         }
  436.  
  437.                         if (focus.X == x && focus.Y == y && Focused) {
  438.                             ControlPaint.DrawFocusRectangle(g, Rectangle.Inflate(rect, 5, 5), SystemColors.ControlText, SystemColors.Control);
  439.                         }
  440.  
  441.  
  442.                         ControlPaint.DrawBorder(g, Rectangle.Inflate(rect, 2, 2),
  443.                                                 SystemColors.Control, 2, ButtonBorderStyle.Inset,
  444.                                                 SystemColors.Control, 2, ButtonBorderStyle.Inset,
  445.                                                 SystemColors.Control, 2, ButtonBorderStyle.Inset,
  446.                                                 SystemColors.Control, 2, ButtonBorderStyle.Inset);
  447.                         PaintValue(cur,g,rect);
  448.                     }
  449.                 }
  450.             }
  451.  
  452.             static private void PaintValue(Color color, Graphics g, Rectangle rect) {
  453.                 g.FillRectangle(new SolidBrush(color), rect);
  454.             }
  455.  
  456.             protected override bool ProcessDialogKey(Keys keyData) {
  457.                 if (keyData == Keys.F2) { // no ctrl, alt, shift...
  458.                     int cell = Get1DFrom2D(focus.X, focus.Y);
  459.                     if (cell >= (CELLS - CELLS_CUSTOM) && cell < CELLS) {
  460.                         LaunchDialog(cell - CELLS + CELLS_CUSTOM);
  461.                         return true;
  462.                     }
  463.                 }
  464.  
  465.                 return base.ProcessDialogKey(keyData);
  466.             }
  467.  
  468.             private void SetFocus(Point newFocus) {
  469.                 // Make sure newFocus is within correct range of cells
  470.                 //
  471.                 if (newFocus.X < 0) {
  472.                     newFocus.X = 0;
  473.                 }
  474.                 if (newFocus.Y < 0) {
  475.                     newFocus.Y = 0;
  476.                 }
  477.                 if (newFocus.X >= CELLS_ACROSS) {
  478.                     newFocus.X = CELLS_ACROSS - 1;
  479.                 }
  480.                 if (newFocus.Y >= CELLS_DOWN) {
  481.                     newFocus.Y = CELLS_DOWN - 1;
  482.                 }
  483.  
  484.                 if (focus != newFocus) {
  485.                     InvalidateFocus();
  486.                     focus = newFocus;
  487.                     InvalidateFocus();
  488.                 }
  489.             }
  490.  
  491.             ///
  492.             [ComVisible(true)]
  493.             public class ColorPaletteAccessibleObject : ControlAccessibleObject {
  494.                 private ColorCellAccessibleObject[] cells;
  495.  
  496.                 ///  
  497.                 public ColorPaletteAccessibleObject(ColorPalette owner) : base(owner) {
  498.                     cells = new ColorCellAccessibleObject[CELLS_ACROSS * CELLS_DOWN];
  499.                 }
  500.  
  501.                 internal ColorPalette ColorPalette {
  502.                     get {
  503.                         return (ColorPalette)Owner;
  504.                     }
  505.                 }
  506.  
  507.                 ///
  508.                 public override int GetChildCount() {
  509.                     return CELLS_ACROSS * CELLS_DOWN;
  510.                 }
  511.  
  512.                 ///  
  513.                 public override AccessibleObject GetChild(int id) {
  514.                     if (id < 0 || id >= CELLS_ACROSS * CELLS_DOWN) {
  515.                         return null;
  516.                     }
  517.  
  518.                     if (cells[id] == null) {
  519.                         cells[id] = new ColorCellAccessibleObject(this, ColorPalette.GetColorFromCell(id), id);
  520.                     }
  521.                     return cells[id];
  522.                 }
  523.  
  524.                 ///  
  525.                 public override AccessibleObject HitTest(int x, int y) {
  526.                     // Convert from screen to client coordinates
  527.                     //
  528.                     NativeMethods.POINT pt = new NativeMethods.POINT(x, y);
  529.                     UnsafeNativeMethods.ScreenToClient(new HandleRef(ColorPalette, ColorPalette.Handle), pt);
  530.  
  531.                     int cell = ColorPalette.GetCellFromLocationMouse(pt.x, pt.y);
  532.                     if (cell != -1) {
  533.                         return GetChild(cell);
  534.                     }
  535.  
  536.                     return base.HitTest(x, y);
  537.                 }
  538.  
  539.                 ///  
  540.                 [ComVisible(true)]
  541.                 public class ColorCellAccessibleObject : AccessibleObject {
  542.                     private Color color;
  543.                     private ColorPaletteAccessibleObject parent;
  544.                     private int cell;
  545.  
  546.                     ///
  547.                     public ColorCellAccessibleObject(ColorPaletteAccessibleObject parent, Color color, int cell) {
  548.                         this.color = color;
  549.                         this.parent = parent;
  550.                         this.cell = cell;
  551.                     }
  552.  
  553.                     ///  
  554.                     public override Rectangle Bounds {
  555.                         get {
  556.                             Point cellPt = ColorPalette.Get2DFrom1D(cell);
  557.                             Rectangle rect = new Rectangle();
  558.                             ColorPalette.FillRectWithCellBounds(cellPt.X, cellPt.Y, ref rect);
  559.  
  560.                             // Translate rect to screen coordinates
  561.                             //
  562.                             NativeMethods.POINT pt = new NativeMethods.POINT(rect.X, rect.Y);
  563.                             UnsafeNativeMethods.ClientToScreen(new HandleRef(parent.ColorPalette, parent.ColorPalette.Handle), pt);
  564.  
  565.                             return new Rectangle(pt.x, pt.y, rect.Width, rect.Height);
  566.                         }
  567.                     }
  568.  
  569.                     ///  
  570.                     public override string Name {
  571.                         get {
  572.                             return color.ToString();
  573.                         }
  574.                     }
  575.  
  576.                     ///
  577.                     public override AccessibleObject Parent {
  578.                         get {
  579.                             return parent;
  580.                         }
  581.                     }
  582.  
  583.                     ///
  584.                     public override AccessibleRole Role {
  585.                         get {
  586.                             return AccessibleRole.Cell;
  587.                         }
  588.                     }
  589.  
  590.                     ///
  591.                     public override AccessibleStates State {
  592.                         get {
  593.                             AccessibleStates state = base.State;
  594.                             if (this.cell == parent.ColorPalette.FocusedCell) {
  595.                                 state |= AccessibleStates.Focused;
  596.                             }
  597.                             return state;
  598.                         }
  599.                     }
  600.  
  601.                     ///
  602.                     public override string Value {
  603.                         get {
  604.                             return color.ToString();
  605.                         }
  606.                     }
  607.                 }
  608.             }
  609.         }
  610.  
  611.         ///  
  612.         ///      Editor UI for the color editor.
  613.         ///  
  614.         private class ColorUI : Control {
  615.  
  616.             private ColorEditor editor;
  617.             private IWindowsFormsEditorService edSvc;
  618.             private object value;
  619.             private ColorEditorTabControl tabControl;
  620.             private TabPage systemTabPage;
  621.             private TabPage commonTabPage;
  622.             private TabPage paletteTabPage;
  623.             private ListBox lbSystem;
  624.             private ListBox lbCommon;
  625.             private ColorPalette pal;
  626.             private object[] systemColorConstants;
  627.             private object[] colorConstants;
  628.             private Color[] customColors;
  629.             private bool commonHeightSet;
  630.             private bool systemHeightSet;
  631.  
  632.             ///  
  633.             ///
  634.             ///  
  635.             public ColorUI(ColorEditor editor) {
  636.                 this.editor = editor;
  637.                 InitializeComponent();
  638.                 AdjustListBoxItemHeight();
  639.             }
  640.  
  641.             ///  
  642.             ///
  643.             ///      Array of standard colors.
  644.             ///
  645.             private object[] ColorValues {
  646.                 get {
  647.                     if (colorConstants == null) {
  648.                         colorConstants = GetConstants(typeof(Color));
  649.                     }
  650.  
  651.                     return colorConstants;
  652.                 }
  653.             }
  654.  
  655.             ///
  656.             ///  
  657.             ///      Retrieves the array of custom colors for our use.
  658.             ///  
  659.             [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  660.             private Color[] CustomColors {
  661.                 get {
  662.                     if (customColors == null) {
  663.                         customColors = new Color[ColorPalette.CELLS_CUSTOM];
  664.                         for (int i = 0; i < ColorPalette.CELLS_CUSTOM; i++) {
  665.                             customColors[i] = Color.White;
  666.                         }
  667.                     }
  668.                     return customColors;
  669.                 }
  670.  
  671.                 set {
  672.                     this.customColors = value;
  673.                     pal = null;
  674.                 }
  675.             }
  676.  
  677.             ///  
  678.             ///
  679.             ///      Allows someone else to close our dropdown.
  680.             ///
  681.             public IWindowsFormsEditorService EditorService {
  682.                 get {
  683.                     return edSvc;
  684.                 }
  685.             }
  686.  
  687.             ///
  688.             ///  
  689.             ///      Array of system colors.
  690.             ///
  691.             private object[] SystemColorValues {
  692.                 get {
  693.                     if (systemColorConstants == null) {
  694.                         systemColorConstants = GetConstants(typeof(SystemColors));
  695.                     }
  696.  
  697.                     return systemColorConstants;
  698.                 }
  699.             }
  700.  
  701.             ///  
  702.             ///
  703.             ///  
  704.             public object Value {
  705.                 get {
  706.                     return value;
  707.                 }
  708.             }
  709.  
  710.             ///  
  711.             ///
  712.             ///  
  713.             public void End() {
  714.                 edSvc = null;
  715.                 value = null;
  716.             }
  717.  
  718.             private void AdjustColorUIHeight() {
  719.                 // Compute the default size for the color UI
  720.                 //
  721.                 Size size = pal.Size;
  722.                 Rectangle rectItemSize = tabControl.GetTabRect(0);
  723.                 int CMARGIN = 0;
  724.                 this.Size = new Size(size.Width + 2*CMARGIN, size.Height + 2*CMARGIN + rectItemSize.Height);
  725.                 tabControl.Size = this.Size;
  726.             }
  727.  
  728.             private void AdjustListBoxItemHeight() {
  729.                 lbSystem.ItemHeight = Font.Height + 2;
  730.                 lbCommon.ItemHeight = Font.Height + 2;
  731.             }
  732.  
  733.             ///  
  734.             ///
  735.             ///      Takes the given color and looks for an instance in the ColorValues table.
  736.             ///
  737.             private Color GetBestColor(Color color) {
  738.                 object[] colors = ColorValues;
  739.                 int rgb = color.ToArgb();
  740.                 for (int i = 0; i < colors.Length; i++) {
  741.                     if (((Color)colors[i]).ToArgb() == rgb) {
  742.                         return(Color)colors[i];
  743.                     }
  744.                 }
  745.                 return color;
  746.             }
  747.  
  748.             ///  
  749.             ///  
  750.             ///      Retrieves an array of color constants for the given object.
  751.             ///  
  752.             static private object[] GetConstants(Type enumType) {
  753.                 MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.Static;
  754.                 PropertyInfo[] props = enumType.GetProperties();
  755.  
  756.                 ArrayList colorList = new ArrayList();
  757.  
  758.                 for (int i = 0; i < props.Length; i++) {
  759.                     PropertyInfo prop = props[i];
  760.                     if (prop.PropertyType == typeof(Color)) {
  761.                         MethodInfo method = prop.GetGetMethod();
  762.                         if (method != null && (method.Attributes & attrs) == attrs) {
  763.                             object[] tempIndex = null;
  764.                             colorList.Add(prop.GetValue(null, tempIndex));
  765.                         }
  766.                     }
  767.                 }
  768.  
  769.                 return colorList.ToArray();
  770.             }
  771.  
  772.             ///
  773.             ///  
  774.             ///
  775.             private void InitializeComponent() {
  776.                 paletteTabPage = new TabPage(SR.GetString(SR.ColorEditorPaletteTab));
  777.                 commonTabPage = new TabPage(SR.GetString(SR.ColorEditorStandardTab));
  778.                 systemTabPage = new TabPage(SR.GetString(SR.ColorEditorSystemTab));
  779.  
  780.                 AccessibleName = SR.GetString(SR.ColorEditorAccName);
  781.  
  782.                 tabControl = new ColorEditorTabControl();
  783.                 tabControl.TabPages.Add(paletteTabPage);
  784.                 tabControl.TabPages.Add(commonTabPage);
  785.                 tabControl.TabPages.Add(systemTabPage);
  786.                 tabControl.TabStop = false;
  787.                 tabControl.SelectedTab = systemTabPage;
  788.                 tabControl.SelectedIndexChanged += new EventHandler(this.OnTabControlSelChange);
  789.                 tabControl.Dock = DockStyle.Fill;
  790.                 tabControl.Resize += new EventHandler(this.OnTabControlResize);
  791.  
  792.                 lbSystem = new ColorEditorListBox();
  793.                 lbSystem.DrawMode = DrawMode.OwnerDrawFixed;
  794.                 lbSystem.BorderStyle = BorderStyle.FixedSingle;
  795.                 lbSystem.IntegralHeight = false;
  796.                 lbSystem.Sorted = false;
  797.                 lbSystem.Click += new EventHandler(this.OnListClick);
  798.                 lbSystem.DrawItem += new DrawItemEventHandler(this.OnListDrawItem);
  799.                 lbSystem.KeyDown += new KeyEventHandler(this.OnListKeyDown);
  800.                 lbSystem.Dock = DockStyle.Fill;
  801.                 lbSystem.FontChanged += new EventHandler( this.OnFontChanged );
  802.  
  803.                 lbCommon = new ColorEditorListBox();
  804.                 lbCommon.DrawMode = DrawMode.OwnerDrawFixed;
  805.                 lbCommon.BorderStyle = BorderStyle.FixedSingle;
  806.                 lbCommon.IntegralHeight = false;
  807.                 lbCommon.Sorted = false;
  808.                 lbCommon.Click += new EventHandler(this.OnListClick);
  809.                 lbCommon.DrawItem += new DrawItemEventHandler(this.OnListDrawItem);
  810.                 lbCommon.KeyDown += new KeyEventHandler(this.OnListKeyDown);
  811.                 lbCommon.Dock = DockStyle.Fill;
  812.  
  813.                 Array.Sort(ColorValues, new StandardColorComparer());
  814.                 Array.Sort(SystemColorValues, new SystemColorComparer());
  815.  
  816.                 lbCommon.Items.Clear();
  817.                 foreach(object color in ColorValues) {
  818.                     lbCommon.Items.Add(color);
  819.                 }
  820.                 lbSystem.Items.Clear();
  821.                 foreach(object color in SystemColorValues) {
  822.                     lbSystem.Items.Add(color);
  823.                 }
  824.  
  825.                 pal = new ColorPalette(this, CustomColors);
  826.                 pal.Picked += new EventHandler(this.OnPalettePick);
  827.  
  828.                 paletteTabPage.Controls.Add(pal);
  829.                 systemTabPage.Controls.Add(lbSystem);
  830.                 commonTabPage.Controls.Add(lbCommon);
  831.  
  832.                 this.Controls.Add(tabControl);
  833.             }
  834.  
  835.             protected override void OnGotFocus(EventArgs e) {
  836.                 base.OnGotFocus(e);
  837.                 OnTabControlSelChange(this, EventArgs.Empty);
  838.             }
  839.  
  840.             private void OnFontChanged( object sender, EventArgs e ) {
  841.                 commonHeightSet = systemHeightSet = false;
  842.             }
  843.  
  844.             ///
  845.             ///  
  846.             ///
  847.             [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
  848.             private void OnListClick(object sender, EventArgs e) {
  849.                 ListBox lb = (ListBox)sender;
  850.                 if (lb.SelectedItem != null)
  851.                 {
  852.                     value = (Color)lb.SelectedItem;
  853.                 }
  854.                 edSvc.CloseDropDown();
  855.             }
  856.  
  857.             ///  
  858.             ///
  859.             ///  
  860.             private void OnListDrawItem(object sender, DrawItemEventArgs die) {
  861.                 ListBox lb = (ListBox)sender;
  862.                 object value = lb.Items[die.Index];
  863.                 Font font = Font;
  864.  
  865.                 if (lb == lbCommon && !commonHeightSet) {
  866.                     lb.ItemHeight = lb.Font.Height;
  867.                     commonHeightSet = true;
  868.                 }
  869.                 else if (lb == lbSystem && !systemHeightSet) {
  870.                     lb.ItemHeight = lb.Font.Height;
  871.                     systemHeightSet = true;
  872.                 }
  873.  
  874.                 Graphics graphics = die.Graphics;
  875.                 die.DrawBackground();
  876.  
  877.                 editor.PaintValue(value, graphics, new Rectangle(die.Bounds.X + 2, die.Bounds.Y + 2, 22, die.Bounds.Height - 4));
  878.                 graphics.DrawRectangle(SystemPens.WindowText, new Rectangle(die.Bounds.X + 2, die.Bounds.Y + 2, 22 - 1, die.Bounds.Height - 4 - 1));
  879.                 Brush foreBrush = new SolidBrush(die.ForeColor);
  880.                 graphics.DrawString(((Color)value).Name, font, foreBrush, die.Bounds.X + 26, die.Bounds.Y);
  881.                 foreBrush.Dispose();
  882.             }
  883.  
  884.             ///  
  885.             ///
  886.             ///  
  887.             private void OnListKeyDown(object sender, KeyEventArgs ke) {
  888.                 if (ke.KeyCode == Keys.Return) {
  889.                     OnListClick(sender, EventArgs.Empty);
  890.                 }
  891.             }
  892.  
  893.             ///  
  894.             ///
  895.             ///  
  896.             private void OnPalettePick(object sender, EventArgs e) {
  897.                 ColorPalette p = (ColorPalette)sender;
  898.                 value = GetBestColor(p.SelectedColor);
  899.                 edSvc.CloseDropDown();
  900.             }
  901.  
  902.             protected override void OnFontChanged(EventArgs e) {
  903.                 base.OnFontChanged(e);
  904.                 AdjustListBoxItemHeight();
  905.                 AdjustColorUIHeight();
  906.             }
  907.  
  908.             ///  
  909.             ///
  910.             ///  
  911.             private void OnTabControlResize(object sender, EventArgs e) {
  912.                 Rectangle rectTabControl = tabControl.TabPages[0].ClientRectangle;
  913.                 Rectangle rectItemSize = tabControl.GetTabRect(1);
  914.                 rectTabControl.Y = 0;
  915.                 rectTabControl.Height -= rectTabControl.Y;
  916.                 int CMARGIN = 2;
  917.                 lbSystem.SetBounds(CMARGIN, rectTabControl.Y + 2*CMARGIN,
  918.                                    rectTabControl.Width - CMARGIN,
  919.                                    pal.Size.Height - rectItemSize.Height + 2*CMARGIN);
  920.                 lbCommon.Bounds = lbSystem.Bounds;
  921.                 pal.Location = new Point(0, rectTabControl.Y);
  922.             }
  923.  
  924.             private void OnTabControlSelChange(object sender, EventArgs e) {
  925.                 TabPage selectedPage = tabControl.SelectedTab;
  926.  
  927.                 if (selectedPage!= null && selectedPage.Controls.Count > 0) {
  928.                     selectedPage.Controls[0].Focus();
  929.                 }
  930.             }
  931.  
  932.             protected override bool ProcessDialogKey(Keys keyData) {
  933.                 // We treat tab characters as switching tab pages.  In most other contexts,
  934.                 // ctrl-tab switches tab pages, but I couldn't get that to work, and besides,
  935.                 // then there would be nothing for tab to do in this editor.
  936.                 if ((keyData & Keys.Alt) == 0
  937.                     && (keyData & Keys.Control) == 0
  938.                     && (keyData & Keys.KeyCode) == Keys.Tab) {
  939.  
  940.                     // Logic taken straight out of TabBase
  941.                     bool forward = (keyData & Keys.Shift) == 0;
  942.                     int sel = tabControl.SelectedIndex;
  943.                     if (sel != -1) {
  944.                         int count = tabControl.TabPages.Count;
  945.                         if (forward)
  946.                             sel = (sel + 1) % count;
  947.                         else
  948.                             sel = (sel + count - 1) % count;
  949.                         tabControl.SelectedTab = tabControl.TabPages[sel];
  950.  
  951.                         return true;
  952.                     }
  953.                 }
  954.                 return base.ProcessDialogKey(keyData);
  955.             }
  956.  
  957.             ///
  958.             ///  
  959.             ///
  960.             public void Start(IWindowsFormsEditorService edSvc, object value) {
  961.                 this.edSvc = edSvc;
  962.                 this.value = value;
  963.  
  964.                 AdjustColorUIHeight();
  965.  
  966.                 // Now look for the current color so we can select the proper tab.
  967.                 //
  968.                 if (value != null) {
  969.                     object[] values = ColorValues;
  970.                     TabPage selectedTab = paletteTabPage;
  971.  
  972.                     for (int i = 0; i < values.Length; i++) {
  973.                         if (values[i].Equals(value)) {
  974.                             lbCommon.SelectedItem = value;
  975.                             selectedTab = commonTabPage;
  976.                             break;
  977.                         }
  978.                     }
  979.  
  980.                     if (selectedTab == paletteTabPage) {
  981.                         values = SystemColorValues;
  982.                         for (int i = 0; i < values.Length; i++) {
  983.                             if (values[i].Equals(value)) {
  984.                                 lbSystem.SelectedItem = value;
  985.                                 selectedTab = systemTabPage;
  986.                                 break;
  987.                             }
  988.                         }
  989.                     }
  990.  
  991.                     tabControl.SelectedTab = selectedTab;
  992.                 }
  993.             }
  994.  
  995.  
  996.             private class ColorEditorListBox : ListBox {
  997.                 protected override bool IsInputKey(System.Windows.Forms.Keys keyData) {
  998.                     switch (keyData) {
  999.                         case Keys.Return:
  1000.                             return true;
  1001.                     }
  1002.                     return base.IsInputKey(keyData);
  1003.                 }
  1004.             }
  1005.  
  1006.             private class ColorEditorTabControl : TabControl {
  1007.                 public ColorEditorTabControl() : base() {
  1008.                 }
  1009.  
  1010.                 protected override void OnGotFocus(EventArgs e) {
  1011.                     TabPage selectedTab = this.SelectedTab;
  1012.                     if (selectedTab != null && selectedTab.Controls.Count > 0) {
  1013.                         selectedTab.Controls[0].Focus();
  1014.                     }
  1015.                 }
  1016.             }
  1017.         }
  1018.  
  1019.         ///  
  1020.         ///
  1021.         ///  
  1022.         private class CustomColorDialog : ColorDialog {
  1023.  
  1024.             private const int COLOR_HUE = 703;
  1025.             private const int COLOR_SAT = 704;
  1026.             private const int COLOR_LUM = 705;
  1027.             private const int COLOR_RED = 706;
  1028.             private const int COLOR_GREEN = 707;
  1029.             private const int COLOR_BLUE = 708;
  1030.             private const int COLOR_ADD = 712;
  1031.             private const int COLOR_MIX = 719;
  1032.  
  1033.             private IntPtr hInstance;
  1034.  
  1035.             public CustomColorDialog() {
  1036.                 // colordlg.data was copied from VB6's dlg-4300.dlg
  1037.                 Stream stream = typeof(ColorEditor).Module.Assembly.GetManifestResourceStream(typeof(ColorEditor), "colordlg.data");
  1038.  
  1039.                 int size = (int)(stream.Length - stream.Position);
  1040.                 byte[] buffer = new byte[size];
  1041.                 stream.Read(buffer, 0, size);
  1042.  
  1043.                 hInstance = Marshal.AllocHGlobal(size);
  1044.                 Marshal.Copy(buffer,0,hInstance,size);
  1045.             }
  1046.  
  1047.             protected override IntPtr Instance {
  1048.                 get {
  1049.                     Debug.Assert(hInstance != IntPtr.Zero, "Dialog has been disposed");
  1050.                     return hInstance;
  1051.                 }
  1052.             }
  1053.  
  1054.             protected override int Options {
  1055.                 get {
  1056.                     return NativeMethods.CC_FULLOPEN | NativeMethods.CC_ENABLETEMPLATEHANDLE;
  1057.                 }
  1058.             }
  1059.  
  1060.             protected override void Dispose(bool disposing) {
  1061.                 try {
  1062.                     if (hInstance != IntPtr.Zero) {
  1063.                         Marshal.FreeHGlobal(hInstance);
  1064.                         hInstance = IntPtr.Zero;
  1065.                     }
  1066.                 }
  1067.                 finally {
  1068.                     base.Dispose(disposing);
  1069.                 }
  1070.             }
  1071.  
  1072.             protected override IntPtr HookProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) {
  1073.  
  1074.                 switch (msg) {
  1075.                     case NativeMethods.WM_INITDIALOG:
  1076.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_HUE,   NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1077.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_SAT,   NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1078.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_LUM,   NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1079.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_RED,   NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1080.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_GREEN, NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1081.                         NativeMethods.SendDlgItemMessage(hwnd, COLOR_BLUE,  NativeMethods.EM_SETMARGINS, (IntPtr)(NativeMethods.EC_LEFTMARGIN|NativeMethods.EC_RIGHTMARGIN), IntPtr.Zero);
  1082.                         IntPtr hwndCtl = NativeMethods.GetDlgItem(hwnd,COLOR_MIX);
  1083.                         NativeMethods.EnableWindow(hwndCtl, false);
  1084.                         NativeMethods.SetWindowPos(hwndCtl, IntPtr.Zero, 0, 0, 0, 0, NativeMethods.SWP_HIDEWINDOW);
  1085.                         hwndCtl = NativeMethods.GetDlgItem(hwnd,NativeMethods.IDOK);
  1086.                         NativeMethods.EnableWindow(hwndCtl, false);
  1087.                         NativeMethods.SetWindowPos(hwndCtl, IntPtr.Zero, 0, 0, 0, 0, NativeMethods.SWP_HIDEWINDOW);
  1088.                         this.Color = Color.Empty;
  1089.                         break;
  1090.                     case NativeMethods.WM_COMMAND:
  1091.                         switch (NativeMethods.Util.LOWORD((int)wParam)) {
  1092.                             case COLOR_ADD:
  1093.                                 byte red, green, blue;
  1094.                                 bool[] err = new bool[1];
  1095.                                 red = (byte)NativeMethods.GetDlgItemInt(hwnd, COLOR_RED, err, false);
  1096.                                 Debug.Assert(!err[0], "Couldn't find dialog member COLOR_RED");
  1097.                                 green = (byte)NativeMethods.GetDlgItemInt(hwnd, COLOR_GREEN, err, false);
  1098.                                 Debug.Assert(!err[0], "Couldn't find dialog member COLOR_GREEN");
  1099.                                 blue = (byte)NativeMethods.GetDlgItemInt(hwnd, COLOR_BLUE, err, false);
  1100.                                 Debug.Assert(!err[0], "Couldn't find dialog member COLOR_BLUE");
  1101.                                 this.Color = Color.FromArgb(red,green,blue);
  1102.                                 NativeMethods.PostMessage(hwnd, NativeMethods.WM_COMMAND, (IntPtr)NativeMethods.Util.MAKELONG(NativeMethods.IDOK,0),NativeMethods.GetDlgItem(hwnd,NativeMethods.IDOK));
  1103.                 break;
  1104.                         }
  1105.                         break;
  1106.                 }
  1107.                 return base.HookProc(hwnd,msg,wParam,lParam);
  1108.             }
  1109.         }
  1110.  
  1111.         ///  
  1112.         ///
  1113.         ///      Comparer for system colors.
  1114.         ///
  1115.         private class SystemColorComparer : IComparer {
  1116.             [SuppressMessage("Microsoft.Globalization", "CA130:UseOrdinalStringComparison")]
  1117.             public int Compare(object x, object y) {
  1118.                 return String.Compare(((Color)x).Name, ((Color)y).Name, false, CultureInfo.InvariantCulture);
  1119.             }
  1120.         }
  1121.  
  1122.         ///
  1123.         ///
  1124.         ///      Comparer for standard colors
  1125.         ///
  1126.         private class StandardColorComparer : IComparer {
  1127.             public int Compare(object x, object y) {
  1128.                 Color left = (Color)x;
  1129.                 Color right = (Color)y;
  1130.  
  1131.                 if (left.A < right.A) {
  1132.                     return -1;
  1133.                 }
  1134.                 else if (left.A > right.A) {
  1135.                     return 1;
  1136.                 }
  1137.                 else {
  1138.                     if ((float)left.GetHue() < (float)right.GetHue()) {
  1139.                         return -1;
  1140.                     }
  1141.                     else if ((float)left.GetHue() > (float)right.GetHue()) {
  1142.                         return 1;
  1143.                     }
  1144.                     else {
  1145.                         if ((float)left.GetSaturation() < (float)right.GetSaturation()) {
  1146.                             return -1;
  1147.                         }
  1148.                         else if ((float)left.GetSaturation() > (float)right.GetSaturation()) {
  1149.                             return 1;
  1150.                         }
  1151.                         else {
  1152.                             if ((float)left.GetBrightness() < (float)right.GetBrightness()) {
  1153.                                 return -1;
  1154.                             }
  1155.                             else if ((float)left.GetBrightness() > (float)right.GetBrightness()) {
  1156.                                 return 1;
  1157.                             }
  1158.                             else {
  1159.                                 return 0;
  1160.                             }
  1161.                         }
  1162.                     }
  1163.                 }
  1164.             }
  1165.         }
  1166.     }
  1167. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement