Click here to Skip to main content
15,897,273 members
Articles / Programming Languages / C#

WYSIWYG Color and Font CommonDialogs

Rate me:
Please Sign up or sign in to vote.
3.74/5 (8 votes)
7 Jun 2006CPOL2 min read 46K   336   18  
Enhancing user pleasure, or how to get the current user choice from a running dialog.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

// RightToCopy & PublishAndPerish: OrlandoCurioso 2005

// default template file, include file: Platform SDK/Include/Color.dlg, ColorDlg.h

namespace OC.Windows.Forms
{
	/// <summary>
	/// ColorDialog enhanced to provide current user choice, while running.
	/// Caveat: Needs FullOpen == true for WYSIWYG functionality.
	/// </summary>
	public partial class ocColorDialog : ColorDialog, IColorChangeNotify
	{
		/// <summary>
		/// Occurs when user chooses color in open ColorDialog.
		/// </summary>
		[DescriptionAttribute("Occurs when user chooses color in open ColorDialog.")]
		public event EventHandler<ColorChangedEventArgs> ColorChanged;

		public ocColorDialog() : base()
		{
			base.AllowFullOpen = true;
			base.FullOpen = true;
		}

		#region Interop

		#region Constants ColorDlg.h

		//private const int COLOR_HUE = 703;		// Edit
		//private const int COLOR_SAT = 704;		// Edit
		//private const int COLOR_LUM = 705;		// Edit
		private const int COLOR_RED = 706;		  // Edit
		private const int COLOR_GREEN = 707;		// Edit
		private const int COLOR_BLUE = 708;		 // Edit
		private const int COLOR_CURRENT = 709;
		//private const int COLOR_RAINBOW = 710;
		private const int COLOR_ADD = 712;		  // Button: "&Add Custom Colors"
		private const int COLOR_MIX = 719;		  // Button: "&Define Colors >>"
		//private const int COLOR_BOX1 = 720;	   // Static: basic colors
		//private const int COLOR_CUSTOM1 = 721;	// Static: custom colors

		//private const int COLOR_HUEACCEL = 723;   // Label Edit
		//private const int COLOR_SATACCEL = 724;   // Label Edit
		//private const int COLOR_LUMACCEL = 725;   // Label Edit
		//private const int COLOR_REDACCEL = 726;   // Label Edit
		//private const int COLOR_GREENACCEL = 727; // Label Edit
		//private const int COLOR_BLUEACCEL = 728;  // Label Edit

		#endregion

		#region Constants CommDlg.h

		//private const int CC_ENABLETEMPLATEHANDLE = 0x00000040;

		//private const int CDM_SETDEFAULTFOCUS = 0x451;

		//private const string COLOROKSTRINGW = "commdlg_ColorOK";
		//private const string SETRGBSTRINGW = "commdlg_SetRGBColor";

		#endregion

		[DllImport("user32.dll")]
		private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);

		[DllImport("user32.dll")]
		static extern uint GetDlgItemInt(IntPtr hDlg, int nIDDlgItem, IntPtr lpTranslated, bool bSigned);

		[DllImport("user32.dll")]
		private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

		private const int WM_DESTROY = 0x0002;
		private const int WM_PAINT = 0x000F;
		private const int WM_INITDIALOG = 0x0110;
		private const int WM_COMMAND = 0x0111;

		private const int BN_CLICKED = 0;

		#endregion

		#region Fields

		private IntPtr hDlg;
		private ColorLabelWnd colorLabelWnd;
		private Color lastColor;
		private bool _UseCancelEvent;
		private bool _SerializeCustom;

		#endregion

		/// <summary>
		/// Gets or sets the set of custom colors shown in the dialog box. The default value is null.
		/// Base.CustomColors is an int array.
		/// </summary>
		[Browsable(false), DesignerSerializationVisibility(0)]
		public new Color[] CustomColors
		{
			get
			{
				if (base.CustomColors == null) return null;
				Converter<int, Color> conv = delegate(int clr) { return ColorTranslator.FromWin32(clr); };
				return Array.ConvertAll<int, System.Drawing.Color>(base.CustomColors, conv);
			}
			set
			{
				_SerializeCustom = false;
				Converter<Color, int> conv = delegate(Color clr) { return ColorTranslator.ToWin32(clr); };
				base.CustomColors = Array.ConvertAll<System.Drawing.Color, int>(value, conv);
			}
		}

		[Browsable(false), DefaultValue(false)]
		public bool ShouldSerializeCustomColors
		{
			get { return _SerializeCustom; }
			set { _SerializeCustom = value; }
		}

		/// <summary>
		/// If user cancels, reset client to initial color by single ColorChanged event.
		/// </summary>
		[DefaultValue(false), DescriptionAttribute("If user cancels, reset client to initial color by single ColorChanged event.")]
		public bool UseCancelEvent
		{
			get { return _UseCancelEvent; }
			set { _UseCancelEvent = value; }
		}

		public override bool AllowFullOpen
		{
			set
			{
				Debug.Assert(value == true, "WYSIWYG functionality only with FullOpen set");
				base.AllowFullOpen = value;
			}
		}

		public override bool FullOpen
		{
			set
			{
				Debug.Assert(value == true, "WYSIWYG functionality only with FullOpen set");
				base.FullOpen = value;
			}
		}

		protected override bool RunDialog(IntPtr hwndOwner)
		{
			_SerializeCustom = false;

			lastColor = base.Color;

			bool result = base.RunDialog(hwndOwner);

			if (_UseCancelEvent && !result && ColorChanged != null)
			{
				// user cancelled, reset client
				ColorChanged(this, new ColorChangedEventArgs(base.Color));
			}

			return result;
		}

		protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
		{
			switch (msg)
			{
				case WM_INITDIALOG:

					this.hDlg = hWnd;

					// get handle of Color Label
					IntPtr hChild = GetDlgItem(hWnd, COLOR_CURRENT);

					// start subclassing child
					colorLabelWnd = new ColorLabelWnd(this);
					colorLabelWnd.AssignHandle(hChild);

					// hide useless button (always disabled for FullOpen)
					ShowWindow(GetDlgItem(hWnd, COLOR_MIX), 0);	// SW_HIDE == 0
					break;

				case WM_COMMAND:
					// wParam: The low-order word contains the button's control identifier. The high-order word specifies the notification message.

					int wp = wparam.ToInt32();

					if (LOWORD(wp) == COLOR_ADD && HIWORD(wp) == BN_CLICKED)
					{
						_SerializeCustom = true;
					}

					break;

				case WM_DESTROY:

					// stop subclassing child
					colorLabelWnd.ReleaseHandle();
					this.hDlg = IntPtr.Zero;
					break;
			}

			return base.HookProc(hWnd, msg, wparam, lparam);
		}

		protected static int LOWORD(int dword)
		{
			return (dword & 0xffff);
		}

		protected static int HIWORD(int dword)
		{
			return ((dword >> 16) & 0xffff);
		}

		protected Color getColor()
		{
			// color from RGB editboxes
			int r = (int)GetDlgItemInt(this.hDlg, COLOR_RED, IntPtr.Zero, false);
			int g = (int)GetDlgItemInt(this.hDlg, COLOR_GREEN, IntPtr.Zero, false);
			int b = (int)GetDlgItemInt(this.hDlg, COLOR_BLUE, IntPtr.Zero, false);

			return Color.FromArgb(r, g, b);
		}

		#region IColorChangeNotify Members

		void IColorChangeNotify.ColorChangeNotify()
		{
			Color newColor = getColor();

			// Filter out unwanted events by comparing with stored color
			if (newColor != lastColor)
			{
				if (ColorChanged != null)
				{
					ColorChanged(this, new ColorChangedEventArgs(newColor));
				}
				lastColor = newColor;
			}
		}

		#endregion

		// Intercepts the WM_PAINT window message of the Color label.
		private class ColorLabelWnd : NativeWindow
		{
			public ColorLabelWnd(IColorChangeNotify dialog)
				: base()
			{
				this.dialog = dialog;
			}

			private IColorChangeNotify dialog;

			protected override void WndProc(ref Message m)
			{
				base.WndProc(ref m);

				// label has repainted, may indicate that user chose new color
				if (m.Msg == WM_PAINT)
				{
					dialog.ColorChangeNotify();
				}
			}
		}
	}

	public interface IColorChangeNotify
	{
		void ColorChangeNotify();
	}

	public class ColorChangedEventArgs : EventArgs
	{
		public ColorChangedEventArgs(Color currentColor)
		{
			_CurrentColor = currentColor;
		}
		private Color _CurrentColor;

		public Color CurrentColor
		{
			get { return _CurrentColor; }
		}
	}

}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions