parent
56f92c9422
commit
2707648b9e
@ -1,416 +1,416 @@ |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Drawing; |
||||
using System.Collections; |
||||
using System.ComponentModel; |
||||
using System.Windows.Forms; |
||||
using System.Data; |
||||
using System.Runtime.InteropServices; |
||||
using System.Text; |
||||
|
||||
namespace Opulos.Core.UI { |
||||
public class AlphaColorDialog : ColorDialog { |
||||
|
||||
///<summary>Event is fired after the color or alpha value are changed via any of the possible user-interface controls.</summary> |
||||
public event EventHandler ColorChanged; |
||||
|
||||
private Color _color = Color.Black; // currently selected color |
||||
private AlphaDialog dialogAlpha = null; |
||||
private AlphaColorPanel panelAlpha = null; |
||||
private Button btnAlpha = new Button { Text = "Alpha" }; |
||||
private IntPtr handle = IntPtr.Zero; // handle of this ColorDialog |
||||
private IntPtr hWndRed = IntPtr.Zero; // handles to TextBoxes |
||||
private IntPtr hWndGreen = IntPtr.Zero; |
||||
private IntPtr hWndBlue = IntPtr.Zero; |
||||
|
||||
public AlphaColorDialog() { |
||||
btnAlpha.Click += btnAlpha_Click; |
||||
} |
||||
|
||||
///<summary>The handle for the ColorDialog window.</summary> |
||||
public IntPtr Handle { |
||||
get { |
||||
return handle; |
||||
} |
||||
} |
||||
|
||||
void btnAlpha_Click(object sender, EventArgs e) { |
||||
if (dialogAlpha == null) { |
||||
dialogAlpha = new AlphaDialog(this); |
||||
panelAlpha = new AlphaColorPanel(); |
||||
panelAlpha.AlphaChanged += panelAlpha_AlphaChanged; |
||||
dialogAlpha.Controls.Add(panelAlpha); |
||||
dialogAlpha.Text = "Alpha"; |
||||
//dialogAlpha.StartPosition = FormStartPosition.CenterParent; // doesn't work |
||||
dialogAlpha.StartPosition = FormStartPosition.Manual; |
||||
dialogAlpha.ClientSize = panelAlpha.PreferredSize; |
||||
Size sz = dialogAlpha.Size; |
||||
RECT r = new RECT(); |
||||
GetWindowRect(handle, ref r); |
||||
dialogAlpha.Location = new Point(r.Left + ((r.Right - r.Left) - sz.Width) / 2, r.Top + ((r.Bottom - r.Top) - sz.Height) / 2); |
||||
} |
||||
|
||||
panelAlpha.Color = _color; |
||||
|
||||
if (!dialogAlpha.IsHandleCreated || !dialogAlpha.Visible) { |
||||
dialogAlpha.Visible = false; // sometimes IsHandleCreated is reset, so Visible must be reset |
||||
dialogAlpha.Show(new SimpleWindow { Handle = handle }); |
||||
} |
||||
else { |
||||
if (dialogAlpha.WindowState == FormWindowState.Minimized) |
||||
dialogAlpha.WindowState = FormWindowState.Normal; |
||||
|
||||
dialogAlpha.Activate(); |
||||
dialogAlpha.BringToFront(); |
||||
dialogAlpha.Focus(); |
||||
} |
||||
} |
||||
|
||||
void panelAlpha_AlphaChanged(object sender, EventArgs e) { |
||||
SetColorInternal(panelAlpha.Color); |
||||
} |
||||
|
||||
private static String GetWindowText(IntPtr hWnd) { |
||||
StringBuilder sb = new StringBuilder(256); |
||||
GetWindowText(hWnd, sb, sb.Capacity); |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
private class SimpleWindow : IWin32Window { |
||||
public IntPtr Handle { get; set; } |
||||
} |
||||
|
||||
private static Bitmap ConvertToBitmap(IntPtr hWnd) { |
||||
RECT r = new RECT(); |
||||
GetWindowRect(hWnd, ref r); |
||||
int w = r.Right - r.Left; |
||||
int h = r.Bottom - r.Top; |
||||
|
||||
Graphics g = Graphics.FromHwnd(hWnd); |
||||
Bitmap bmp = new Bitmap(w, h); |
||||
Graphics g2 = Graphics.FromImage(bmp); |
||||
IntPtr g2_hdc = g2.GetHdc(); |
||||
IntPtr g_hdc = g.GetHdc(); |
||||
BitBlt(g2_hdc, 0, 0, w, h, g_hdc, 0, 0, SRC); |
||||
g.ReleaseHdc(g_hdc); |
||||
g2.ReleaseHdc(g2_hdc); |
||||
g.Dispose(); |
||||
g2.Dispose(); |
||||
|
||||
return bmp; |
||||
} |
||||
|
||||
private struct IJL { |
||||
public int i; |
||||
public int j; |
||||
public int len; |
||||
|
||||
public override String ToString() { |
||||
return i + " " + j + " " + len; |
||||
} |
||||
} |
||||
|
||||
private static Color? FindSelectedColor(IntPtr hWnd) { |
||||
// This method assumes there is a bounding rectangle around a color swatch. |
||||
// The rectangle can be any color, but must be a single color. Since |
||||
// the rectangle surrounds the swatch, it must have a run of pixels that |
||||
// is longer than the run of pixels inside the swatch. Since it is |
||||
// a rectangle, and we are scanning from top to bottom (left to right would also work), |
||||
// then there must be exactly two runs that tie for longest. If two runs cannot |
||||
// be found, then there is no bounding rectangle. |
||||
|
||||
Bitmap bmp = ConvertToBitmap(hWnd); |
||||
int w = bmp.Width; |
||||
int h = bmp.Height; |
||||
Color bg = bmp.GetPixel(0, 0); |
||||
|
||||
IJL ijl = new IJL(); |
||||
IJL ijl0 = new IJL(); |
||||
IJL ijl1 = new IJL(); |
||||
int k = 0; |
||||
|
||||
for (int i = 0; i < w; i++) { |
||||
Color lastColor = Color.Empty; |
||||
for (int j = 0; j <= h; j++) { |
||||
Color c = (j == h ? Color.Empty : bmp.GetPixel(i, j)); |
||||
if (c == lastColor) { |
||||
ijl.len++; |
||||
} |
||||
else { |
||||
if (ijl.len < h) { |
||||
if (ijl.len > 1 && bg != lastColor) { |
||||
if (ijl.len > ijl0.len) { |
||||
ijl0 = ijl; |
||||
k = 0; |
||||
} |
||||
else if (ijl.len == ijl0.len) { |
||||
ijl1 = ijl; |
||||
k++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
ijl = new IJL(); |
||||
ijl.i = i; |
||||
ijl.j = j; |
||||
ijl.len = 1; |
||||
lastColor = c; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (k != 1) { |
||||
bmp.Dispose(); |
||||
return null; |
||||
} |
||||
|
||||
// k == 1 means there are exactly two runs of maximum length |
||||
int x = ijl0.i + (ijl1.i - ijl0.i) / 2; |
||||
int y = ijl0.j + ijl0.len / 2; |
||||
Color c1 = bmp.GetPixel(x, y); |
||||
bmp.Dispose(); |
||||
return c1; |
||||
} |
||||
|
||||
private Color GetColorInternal() { |
||||
int a = (panelAlpha != null ? panelAlpha.Alpha : 255); |
||||
String _r = GetWindowText(hWndRed); |
||||
if (_r.Length > 0) { |
||||
// Define Custom Colors UI is visible. |
||||
int r = int.Parse(_r); |
||||
int g = int.Parse(GetWindowText(hWndGreen)); |
||||
int b = int.Parse(GetWindowText(hWndBlue)); |
||||
return Color.FromArgb(a, r, g, b); |
||||
} |
||||
else { |
||||
// if the RGB text boxes aren't visible, then resort to trying to find |
||||
// the selected color by looking for the solid line rectangle that indicates the |
||||
// currently selected color. |
||||
Color? c = FindSelectedColor(GetDlgItem(handle, 0x02d0)); // Basic colors |
||||
if (!c.HasValue) |
||||
c = FindSelectedColor(GetDlgItem(handle, 0x02d1)); // Custom colors |
||||
|
||||
return c.HasValue ? Color.FromArgb(a, c.Value) : Color.FromArgb(a, Color.Black); |
||||
} |
||||
} |
||||
|
||||
private static bool AreEqual(Color c1, Color c2) { |
||||
// Color.Black != (255, 0, 0, 0) |
||||
return c1.A == c2.A && c1.R == c2.R && c1.G == c2.G && c1.B == c2.B; |
||||
} |
||||
|
||||
private void SetColorInternal(Color c) { |
||||
if (AreEqual(c, _color)) |
||||
return; |
||||
|
||||
_color = c; |
||||
if (ColorChanged != null) |
||||
ColorChanged(this, EventArgs.Empty); |
||||
} |
||||
|
||||
public new Color Color { |
||||
get { |
||||
return _color; |
||||
} |
||||
|
||||
set { |
||||
SetColorInternal(value); |
||||
if (panelAlpha != null) |
||||
panelAlpha.Alpha = value.A; |
||||
|
||||
base.Color = value; |
||||
} |
||||
} |
||||
|
||||
protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) { |
||||
//System.Diagnostics.Debug.WriteLine((Opulos.Core.Win32.WM) msg); |
||||
if (msg == WM_INITDIALOG) { |
||||
IntPtr hWndOK = GetDlgItem(hWnd, 0x1); // 0x1 == OK button |
||||
RECT rOK = new RECT(); |
||||
GetWindowRect(hWndOK, ref rOK); |
||||
|
||||
IntPtr hWndDefineCustomColors = GetDlgItem(hWnd, 0x02cf); |
||||
RECT rDefineCustomColors = new RECT(); |
||||
GetWindowRect(hWndDefineCustomColors, ref rDefineCustomColors); |
||||
|
||||
IntPtr hWndCancel = GetDlgItem(hWnd, 0x2); // 0x2 == Cancel button |
||||
RECT rCancel = new RECT(); |
||||
GetWindowRect(hWndCancel, ref rCancel); |
||||
// Convert the cancel button's screen coordinates to client coordinates |
||||
POINT pt = new POINT(); |
||||
pt.X = rCancel.Right; |
||||
pt.Y = rCancel.Top; |
||||
ScreenToClient(hWnd, ref pt); |
||||
IntPtr hWndParent = GetParent(hWndCancel); |
||||
int w = rCancel.Right - rCancel.Left; |
||||
int h = rCancel.Bottom - rCancel.Top; |
||||
int gap = (rCancel.Left - rOK.Right); |
||||
|
||||
// the "Define Custom Colors >>" button is slightly less wide than the total width of the |
||||
// OK, Cancel and Alpha buttons. Options: |
||||
// 1) Increase the width of the define button so it right aligns with the alpha button |
||||
// 2) Make the alpha button smaller in width |
||||
// 3) Decrease the widths of all three button and decrease the gap between them. |
||||
// Option 1 looks better than option 2. Didn't try option 3. |
||||
if (rCancel.Right + gap + w > rDefineCustomColors.Right) { // screen coordinates |
||||
int diff = (rCancel.Right + gap + w) - rDefineCustomColors.Right; |
||||
// Option 2: //w = w - diff; |
||||
// Option 1: |
||||
int w2 = rDefineCustomColors.Right - rDefineCustomColors.Left; |
||||
int h2 = rDefineCustomColors.Bottom - rDefineCustomColors.Top; |
||||
SetWindowPos(hWndDefineCustomColors, IntPtr.Zero, 0, 0, w2 + diff, h2, SWP_NOMOVE | SWP_NOZORDER); |
||||
} |
||||
|
||||
var hWndAlpha = btnAlpha.Handle; // creates the handle |
||||
btnAlpha.Bounds = new Rectangle(pt.X + gap, pt.Y, w, h); |
||||
SetParent(hWndAlpha, hWndParent); |
||||
int hWndFont = SendMessage(hWndCancel, WM_GETFONT, 0, 0); |
||||
SendMessage(hWndAlpha, WM_SETFONT, hWndFont, 0); |
||||
|
||||
// Alternative way to create the Alpha button, but would have to handle the WM_NOTIFY messages for the button click events. |
||||
//hWndAlpha = CreateWindowEx(0, "Button", "alphabutton", WS_VISIBLE | WS_CHILD | WS_TABSTOP, pt.X + gap, pt.Y, w, h, hWndParent, 0, 0, 0); |
||||
//SetWindowText(hWndAlpha, "Alpha"); |
||||
//int hWndFont = SendMessage(hWndCancel, WM_GETFONT, 0, 0); |
||||
//SendMessage(hWndAlpha, WM_SETFONT, hWndFont, 0); |
||||
|
||||
// calling ColorDialog.Color does not return the currently selected color until after the OK button |
||||
// is clicked. So the values from the textboxes are used. To find the controlIDs, use Spy++. |
||||
hWndRed = GetDlgItem(hWnd, 0x02c2); // red text box |
||||
hWndGreen = GetDlgItem(hWnd, 0x02c3); |
||||
hWndBlue = GetDlgItem(hWnd, 0x02c4); |
||||
} |
||||
else if (msg == WM_SHOWWINDOW) { |
||||
//center the dialog on the parent window: |
||||
RECT cr = new RECT(); |
||||
RECT r0 = new RECT(); |
||||
IntPtr parent = GetParent(hWnd); |
||||
GetWindowRect(hWnd, ref r0); |
||||
GetWindowRect(parent, ref cr); |
||||
handle = hWnd; |
||||
|
||||
int x = cr.Left + ((cr.Right - cr.Left) - (r0.Right - r0.Left)) / 2; |
||||
int y = cr.Top + ((cr.Bottom - cr.Top) - (r0.Bottom - r0.Top)) / 2; |
||||
SetWindowPos(hWnd, IntPtr.Zero, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); |
||||
} |
||||
else if (msg == ACD_COLORCHANGED) { |
||||
Color c = GetColorInternal(); |
||||
SetColorInternal(c); |
||||
if (panelAlpha != null) |
||||
panelAlpha.Color = c; |
||||
} |
||||
else if (msg == WM_COMMAND || msg == WM_CHAR || msg == WM_LBUTTONDOWN) { |
||||
PostMessage(hWnd, ACD_COLORCHANGED, 0, 0); |
||||
} |
||||
|
||||
return base.HookProc(hWnd, msg, wparam, lparam); |
||||
} |
||||
|
||||
protected override void Dispose(bool disposing) { |
||||
base.Dispose(disposing); |
||||
if (disposing) { |
||||
if (btnAlpha != null) |
||||
btnAlpha.Dispose(); |
||||
|
||||
if (dialogAlpha != null) |
||||
dialogAlpha.Dispose(); |
||||
|
||||
btnAlpha = null; |
||||
dialogAlpha = null; |
||||
} |
||||
} |
||||
|
||||
private class AlphaDialog : Form { |
||||
|
||||
AlphaColorDialog AOwner; |
||||
public AlphaDialog(AlphaColorDialog owner) { |
||||
AOwner = owner; |
||||
ShowIcon = false; |
||||
} |
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e) { |
||||
if (e.CloseReason == CloseReason.None || e.CloseReason == CloseReason.UserClosing) { |
||||
e.Cancel = true; |
||||
Hide(); |
||||
SetForegroundWindow(AOwner.handle); |
||||
} |
||||
base.OnFormClosing(e); |
||||
} |
||||
} |
||||
|
||||
private struct RECT { |
||||
public int Left; |
||||
public int Top; |
||||
public int Right; |
||||
public int Bottom; |
||||
} |
||||
|
||||
private struct POINT { |
||||
public int X; |
||||
public int Y; |
||||
} |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr GetParent(IntPtr hWnd); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool SetForegroundWindow(IntPtr hWnd); |
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); |
||||
|
||||
[DllImport("gdi32.dll", ExactSpelling=true, CharSet=CharSet.Auto, SetLastError=true)] |
||||
private static extern bool BitBlt(IntPtr pHdc, int iX, int iY, int iWidth, int iHeight, IntPtr pHdcSource, int iXSource, int iYSource, System.Int32 dw); |
||||
|
||||
//[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
//private static extern IntPtr CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int hMenu, int hInstance, int lpParam); |
||||
|
||||
//[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
//private static extern bool SetWindowText(IntPtr hWnd, String lpString); |
||||
|
||||
//[DllImport("user32.dll")] |
||||
//private static extern bool DestroyWindow(IntPtr hwnd); |
||||
|
||||
private const int ACD_COLORCHANGED = 0x0400; // custom message |
||||
private const int SRC = 0xCC0020; |
||||
|
||||
private const int SWP_NOSIZE = 0x0001; |
||||
private const int SWP_NOMOVE = 0x0002; |
||||
private const int SWP_NOZORDER = 0x0004; |
||||
|
||||
private const int WM_INITDIALOG = 0x110; |
||||
private const int WM_SETFONT = 0x0030; |
||||
private const int WM_GETFONT = 0x0031; |
||||
private const int WM_SHOWWINDOW = 0x18; |
||||
//private const int WM_NOTIFY; |
||||
// messages that indicate a color change: |
||||
private const int WM_COMMAND = 0x111; |
||||
private const int WM_CHAR = 0x102; |
||||
private const int WM_LBUTTONDOWN = 0x201; |
||||
|
||||
//private const uint WS_VISIBLE = 0x10000000; |
||||
//private const uint WS_CHILD = 0x40000000; |
||||
//private const uint WS_TABSTOP = 0x00010000; |
||||
|
||||
} |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Drawing; |
||||
using System.Collections; |
||||
using System.ComponentModel; |
||||
using System.Windows.Forms; |
||||
using System.Data; |
||||
using System.Runtime.InteropServices; |
||||
using System.Text; |
||||
|
||||
namespace Opulos.Core.UI { |
||||
public class AlphaColorDialog : ColorDialog { |
||||
|
||||
///<summary>Event is fired after the color or alpha value are changed via any of the possible user-interface controls.</summary> |
||||
public event EventHandler ColorChanged; |
||||
|
||||
private Color _color = Color.Black; // currently selected color |
||||
private AlphaDialog dialogAlpha = null; |
||||
private AlphaColorPanel panelAlpha = null; |
||||
private Button btnAlpha = new Button { Text = "Alpha" }; |
||||
private IntPtr handle = IntPtr.Zero; // handle of this ColorDialog |
||||
private IntPtr hWndRed = IntPtr.Zero; // handles to TextBoxes |
||||
private IntPtr hWndGreen = IntPtr.Zero; |
||||
private IntPtr hWndBlue = IntPtr.Zero; |
||||
|
||||
public AlphaColorDialog() { |
||||
btnAlpha.Click += btnAlpha_Click; |
||||
} |
||||
|
||||
///<summary>The handle for the ColorDialog window.</summary> |
||||
public IntPtr Handle { |
||||
get { |
||||
return handle; |
||||
} |
||||
} |
||||
|
||||
void btnAlpha_Click(object sender, EventArgs e) { |
||||
if (dialogAlpha == null) { |
||||
dialogAlpha = new AlphaDialog(this); |
||||
panelAlpha = new AlphaColorPanel(); |
||||
panelAlpha.AlphaChanged += panelAlpha_AlphaChanged; |
||||
dialogAlpha.Controls.Add(panelAlpha); |
||||
dialogAlpha.Text = "Alpha"; |
||||
//dialogAlpha.StartPosition = FormStartPosition.CenterParent; // doesn't work |
||||
dialogAlpha.StartPosition = FormStartPosition.Manual; |
||||
dialogAlpha.ClientSize = panelAlpha.PreferredSize; |
||||
Size sz = dialogAlpha.Size; |
||||
RECT r = new RECT(); |
||||
GetWindowRect(handle, ref r); |
||||
dialogAlpha.Location = new Point(r.Left + ((r.Right - r.Left) - sz.Width) / 2, r.Top + ((r.Bottom - r.Top) - sz.Height) / 2); |
||||
} |
||||
|
||||
panelAlpha.Color = _color; |
||||
|
||||
if (!dialogAlpha.IsHandleCreated || !dialogAlpha.Visible) { |
||||
dialogAlpha.Visible = false; // sometimes IsHandleCreated is reset, so Visible must be reset |
||||
dialogAlpha.Show(new SimpleWindow { Handle = handle }); |
||||
} |
||||
else { |
||||
if (dialogAlpha.WindowState == FormWindowState.Minimized) |
||||
dialogAlpha.WindowState = FormWindowState.Normal; |
||||
|
||||
dialogAlpha.Activate(); |
||||
dialogAlpha.BringToFront(); |
||||
dialogAlpha.Focus(); |
||||
} |
||||
} |
||||
|
||||
void panelAlpha_AlphaChanged(object sender, EventArgs e) { |
||||
SetColorInternal(panelAlpha.Color); |
||||
} |
||||
|
||||
private static String GetWindowText(IntPtr hWnd) { |
||||
StringBuilder sb = new StringBuilder(256); |
||||
GetWindowText(hWnd, sb, sb.Capacity); |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
private class SimpleWindow : IWin32Window { |
||||
public IntPtr Handle { get; set; } |
||||
} |
||||
|
||||
private static Bitmap ConvertToBitmap(IntPtr hWnd) { |
||||
RECT r = new RECT(); |
||||
GetWindowRect(hWnd, ref r); |
||||
int w = r.Right - r.Left; |
||||
int h = r.Bottom - r.Top; |
||||
|
||||
Graphics g = Graphics.FromHwnd(hWnd); |
||||
Bitmap bmp = new Bitmap(w, h); |
||||
Graphics g2 = Graphics.FromImage(bmp); |
||||
IntPtr g2_hdc = g2.GetHdc(); |
||||
IntPtr g_hdc = g.GetHdc(); |
||||
BitBlt(g2_hdc, 0, 0, w, h, g_hdc, 0, 0, SRC); |
||||
g.ReleaseHdc(g_hdc); |
||||
g2.ReleaseHdc(g2_hdc); |
||||
g.Dispose(); |
||||
g2.Dispose(); |
||||
|
||||
return bmp; |
||||
} |
||||
|
||||
private struct IJL { |
||||
public int i; |
||||
public int j; |
||||
public int len; |
||||
|
||||
public override String ToString() { |
||||
return i + " " + j + " " + len; |
||||
} |
||||
} |
||||
|
||||
private static Color? FindSelectedColor(IntPtr hWnd) { |
||||
// This method assumes there is a bounding rectangle around a color swatch. |
||||
// The rectangle can be any color, but must be a single color. Since |
||||
// the rectangle surrounds the swatch, it must have a run of pixels that |
||||
// is longer than the run of pixels inside the swatch. Since it is |
||||
// a rectangle, and we are scanning from top to bottom (left to right would also work), |
||||
// then there must be exactly two runs that tie for longest. If two runs cannot |
||||
// be found, then there is no bounding rectangle. |
||||
|
||||
Bitmap bmp = ConvertToBitmap(hWnd); |
||||
int w = bmp.Width; |
||||
int h = bmp.Height; |
||||
Color bg = bmp.GetPixel(0, 0); |
||||
|
||||
IJL ijl = new IJL(); |
||||
IJL ijl0 = new IJL(); |
||||
IJL ijl1 = new IJL(); |
||||
int k = 0; |
||||
|
||||
for (int i = 0; i < w; i++) { |
||||
Color lastColor = Color.Empty; |
||||
for (int j = 0; j <= h; j++) { |
||||
Color c = (j == h ? Color.Empty : bmp.GetPixel(i, j)); |
||||
if (c == lastColor) { |
||||
ijl.len++; |
||||
} |
||||
else { |
||||
if (ijl.len < h) { |
||||
if (ijl.len > 1 && bg != lastColor) { |
||||
if (ijl.len > ijl0.len) { |
||||
ijl0 = ijl; |
||||
k = 0; |
||||
} |
||||
else if (ijl.len == ijl0.len) { |
||||
ijl1 = ijl; |
||||
k++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
ijl = new IJL(); |
||||
ijl.i = i; |
||||
ijl.j = j; |
||||
ijl.len = 1; |
||||
lastColor = c; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (k != 1) { |
||||
bmp.Dispose(); |
||||
return null; |
||||
} |
||||
|
||||
// k == 1 means there are exactly two runs of maximum length |
||||
int x = ijl0.i + (ijl1.i - ijl0.i) / 2; |
||||
int y = ijl0.j + ijl0.len / 2; |
||||
Color c1 = bmp.GetPixel(x, y); |
||||
bmp.Dispose(); |
||||
return c1; |
||||
} |
||||
|
||||
private Color GetColorInternal() { |
||||
int a = (panelAlpha != null ? panelAlpha.Alpha : 255); |
||||
String _r = GetWindowText(hWndRed); |
||||
if (_r.Length > 0) { |
||||
// Define Custom Colors UI is visible. |
||||
int r = int.Parse(_r); |
||||
int g = int.Parse(GetWindowText(hWndGreen)); |
||||
int b = int.Parse(GetWindowText(hWndBlue)); |
||||
return Color.FromArgb(a, r, g, b); |
||||
} |
||||
else { |
||||
// if the RGB text boxes aren't visible, then resort to trying to find |
||||
// the selected color by looking for the solid line rectangle that indicates the |
||||
// currently selected color. |
||||
Color? c = FindSelectedColor(GetDlgItem(handle, 0x02d0)); // Basic colors |
||||
if (!c.HasValue) |
||||
c = FindSelectedColor(GetDlgItem(handle, 0x02d1)); // Custom colors |
||||
|
||||
return c.HasValue ? Color.FromArgb(a, c.Value) : Color.FromArgb(a, Color.Black); |
||||
} |
||||
} |
||||
|
||||
private static bool AreEqual(Color c1, Color c2) { |
||||
// Color.Black != (255, 0, 0, 0) |
||||
return c1.A == c2.A && c1.R == c2.R && c1.G == c2.G && c1.B == c2.B; |
||||
} |
||||
|
||||
private void SetColorInternal(Color c) { |
||||
if (AreEqual(c, _color)) |
||||
return; |
||||
|
||||
_color = c; |
||||
if (ColorChanged != null) |
||||
ColorChanged(this, EventArgs.Empty); |
||||
} |
||||
|
||||
public new Color Color { |
||||
get { |
||||
return _color; |
||||
} |
||||
|
||||
set { |
||||
SetColorInternal(value); |
||||
if (panelAlpha != null) |
||||
panelAlpha.Alpha = value.A; |
||||
|
||||
base.Color = value; |
||||
} |
||||
} |
||||
|
||||
protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) { |
||||
//System.Diagnostics.Debug.WriteLine((Opulos.Core.Win32.WM) msg); |
||||
if (msg == WM_INITDIALOG) { |
||||
IntPtr hWndOK = GetDlgItem(hWnd, 0x1); // 0x1 == OK button |
||||
RECT rOK = new RECT(); |
||||
GetWindowRect(hWndOK, ref rOK); |
||||
|
||||
IntPtr hWndDefineCustomColors = GetDlgItem(hWnd, 0x02cf); |
||||
RECT rDefineCustomColors = new RECT(); |
||||
GetWindowRect(hWndDefineCustomColors, ref rDefineCustomColors); |
||||
|
||||
IntPtr hWndCancel = GetDlgItem(hWnd, 0x2); // 0x2 == Cancel button |
||||
RECT rCancel = new RECT(); |
||||
GetWindowRect(hWndCancel, ref rCancel); |
||||
// Convert the cancel button's screen coordinates to client coordinates |
||||
POINT pt = new POINT(); |
||||
pt.X = rCancel.Right; |
||||
pt.Y = rCancel.Top; |
||||
ScreenToClient(hWnd, ref pt); |
||||
IntPtr hWndParent = GetParent(hWndCancel); |
||||
int w = rCancel.Right - rCancel.Left; |
||||
int h = rCancel.Bottom - rCancel.Top; |
||||
int gap = (rCancel.Left - rOK.Right); |
||||
|
||||
// the "Define Custom Colors >>" button is slightly less wide than the total width of the |
||||
// OK, Cancel and Alpha buttons. Options: |
||||
// 1) Increase the width of the define button so it right aligns with the alpha button |
||||
// 2) Make the alpha button smaller in width |
||||
// 3) Decrease the widths of all three button and decrease the gap between them. |
||||
// Option 1 looks better than option 2. Didn't try option 3. |
||||
if (rCancel.Right + gap + w > rDefineCustomColors.Right) { // screen coordinates |
||||
int diff = (rCancel.Right + gap + w) - rDefineCustomColors.Right; |
||||
// Option 2: //w = w - diff; |
||||
// Option 1: |
||||
int w2 = rDefineCustomColors.Right - rDefineCustomColors.Left; |
||||
int h2 = rDefineCustomColors.Bottom - rDefineCustomColors.Top; |
||||
SetWindowPos(hWndDefineCustomColors, IntPtr.Zero, 0, 0, w2 + diff, h2, SWP_NOMOVE | SWP_NOZORDER); |
||||
} |
||||
|
||||
var hWndAlpha = btnAlpha.Handle; // creates the handle |
||||
btnAlpha.Bounds = new Rectangle(pt.X + gap, pt.Y, w, h); |
||||
SetParent(hWndAlpha, hWndParent); |
||||
int hWndFont = SendMessage(hWndCancel, WM_GETFONT, 0, 0); |
||||
SendMessage(hWndAlpha, WM_SETFONT, hWndFont, 0); |
||||
|
||||
// Alternative way to create the Alpha button, but would have to handle the WM_NOTIFY messages for the button click events. |
||||
//hWndAlpha = CreateWindowEx(0, "Button", "alphabutton", WS_VISIBLE | WS_CHILD | WS_TABSTOP, pt.X + gap, pt.Y, w, h, hWndParent, 0, 0, 0); |
||||
//SetWindowText(hWndAlpha, "Alpha"); |
||||
//int hWndFont = SendMessage(hWndCancel, WM_GETFONT, 0, 0); |
||||
//SendMessage(hWndAlpha, WM_SETFONT, hWndFont, 0); |
||||
|
||||
// calling ColorDialog.Color does not return the currently selected color until after the OK button |
||||
// is clicked. So the values from the textboxes are used. To find the controlIDs, use Spy++. |
||||
hWndRed = GetDlgItem(hWnd, 0x02c2); // red text box |
||||
hWndGreen = GetDlgItem(hWnd, 0x02c3); |
||||
hWndBlue = GetDlgItem(hWnd, 0x02c4); |
||||
} |
||||
else if (msg == WM_SHOWWINDOW) { |
||||
//center the dialog on the parent window: |
||||
RECT cr = new RECT(); |
||||
RECT r0 = new RECT(); |
||||
IntPtr parent = GetParent(hWnd); |
||||
GetWindowRect(hWnd, ref r0); |
||||
GetWindowRect(parent, ref cr); |
||||
handle = hWnd; |
||||
|
||||
int x = cr.Left + ((cr.Right - cr.Left) - (r0.Right - r0.Left)) / 2; |
||||
int y = cr.Top + ((cr.Bottom - cr.Top) - (r0.Bottom - r0.Top)) / 2; |
||||
SetWindowPos(hWnd, IntPtr.Zero, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); |
||||
} |
||||
else if (msg == ACD_COLORCHANGED) { |
||||
Color c = GetColorInternal(); |
||||
SetColorInternal(c); |
||||
if (panelAlpha != null) |
||||
panelAlpha.Color = c; |
||||
} |
||||
else if (msg == WM_COMMAND || msg == WM_CHAR || msg == WM_LBUTTONDOWN) { |
||||
PostMessage(hWnd, ACD_COLORCHANGED, 0, 0); |
||||
} |
||||
|
||||
return base.HookProc(hWnd, msg, wparam, lparam); |
||||
} |
||||
|
||||
protected override void Dispose(bool disposing) { |
||||
base.Dispose(disposing); |
||||
if (disposing) { |
||||
if (btnAlpha != null) |
||||
btnAlpha.Dispose(); |
||||
|
||||
if (dialogAlpha != null) |
||||
dialogAlpha.Dispose(); |
||||
|
||||
btnAlpha = null; |
||||
dialogAlpha = null; |
||||
} |
||||
} |
||||
|
||||
private class AlphaDialog : Form { |
||||
|
||||
AlphaColorDialog AOwner; |
||||
public AlphaDialog(AlphaColorDialog owner) { |
||||
AOwner = owner; |
||||
ShowIcon = false; |
||||
} |
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e) { |
||||
if (e.CloseReason == CloseReason.None || e.CloseReason == CloseReason.UserClosing) { |
||||
e.Cancel = true; |
||||
Hide(); |
||||
SetForegroundWindow(AOwner.handle); |
||||
} |
||||
base.OnFormClosing(e); |
||||
} |
||||
} |
||||
|
||||
private struct RECT { |
||||
public int Left; |
||||
public int Top; |
||||
public int Right; |
||||
public int Bottom; |
||||
} |
||||
|
||||
private struct POINT { |
||||
public int X; |
||||
public int Y; |
||||
} |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr GetParent(IntPtr hWnd); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern bool SetForegroundWindow(IntPtr hWnd); |
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); |
||||
|
||||
[DllImport("gdi32.dll", ExactSpelling=true, CharSet=CharSet.Auto, SetLastError=true)] |
||||
private static extern bool BitBlt(IntPtr pHdc, int iX, int iY, int iWidth, int iHeight, IntPtr pHdcSource, int iXSource, int iYSource, System.Int32 dw); |
||||
|
||||
//[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
//private static extern IntPtr CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int hMenu, int hInstance, int lpParam); |
||||
|
||||
//[DllImport("user32.dll", CharSet = CharSet.Auto)] |
||||
//private static extern bool SetWindowText(IntPtr hWnd, String lpString); |
||||
|
||||
//[DllImport("user32.dll")] |
||||
//private static extern bool DestroyWindow(IntPtr hwnd); |
||||
|
||||
private const int ACD_COLORCHANGED = 0x0400; // custom message |
||||
private const int SRC = 0xCC0020; |
||||
|
||||
private const int SWP_NOSIZE = 0x0001; |
||||
private const int SWP_NOMOVE = 0x0002; |
||||
private const int SWP_NOZORDER = 0x0004; |
||||
|
||||
private const int WM_INITDIALOG = 0x110; |
||||
private const int WM_SETFONT = 0x0030; |
||||
private const int WM_GETFONT = 0x0031; |
||||
private const int WM_SHOWWINDOW = 0x18; |
||||
//private const int WM_NOTIFY; |
||||
// messages that indicate a color change: |
||||
private const int WM_COMMAND = 0x111; |
||||
private const int WM_CHAR = 0x102; |
||||
private const int WM_LBUTTONDOWN = 0x201; |
||||
|
||||
//private const uint WS_VISIBLE = 0x10000000; |
||||
//private const uint WS_CHILD = 0x40000000; |
||||
//private const uint WS_TABSTOP = 0x00010000; |
||||
|
||||
} |
||||
} |
@ -1,200 +1,200 @@ |
||||
using System; |
||||
using System.Drawing; |
||||
using System.Runtime.InteropServices; |
||||
using System.Windows.Forms; |
||||
|
||||
namespace Opulos.Core.UI { |
||||
|
||||
public class AlphaColorPanel : Panel { |
||||
|
||||
public event EventHandler AlphaChanged; |
||||
|
||||
NumericUpDown nudAlpha = new NumericUpDown { AutoSize = true, Minimum = 0, Maximum = 255, DecimalPlaces = 0, Increment = 1, Value = 255, Anchor = AnchorStyles.Top }; |
||||
TrackBar trackBar = new TrackBar2 { Minimum = 0, Maximum = 255, TickFrequency = 5, TickStyle = TickStyle.None, Orientation = Orientation.Horizontal, Value = 255, Anchor = AnchorStyles.Left | AnchorStyles.Right }; |
||||
Color[] colors = new Color[] { Color.White, Color.Black, Color.Green, Color.Blue, Color.Red, Color.Yellow }; |
||||
public int Cols { get; set; } |
||||
public int SwatchSize { get; set; } |
||||
|
||||
private Color color = Color.Empty; |
||||
|
||||
public AlphaColorPanel() : base() { |
||||
Dock = DockStyle.Fill; |
||||
AutoSize = true; |
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink; |
||||
DoubleBuffered = true; |
||||
//TabStop = true; |
||||
//SetStyle(ControlStyles.Selectable, true); |
||||
ResizeRedraw = true; |
||||
|
||||
Cols = 3; |
||||
SwatchSize = 100; |
||||
trackBar.ValueChanged += trackBar_ValueChanged; |
||||
nudAlpha.ValueChanged += nudAlpha_ValueChanged; |
||||
Alpha = 255; |
||||
|
||||
TableLayoutPanel p = new TableLayoutPanel { Dock = DockStyle.Bottom }; |
||||
p.AutoSize = true; |
||||
p.AutoSizeMode = AutoSizeMode.GrowAndShrink; |
||||
p.Controls.Add(nudAlpha, 0, 0); |
||||
p.Controls.Add(trackBar, 1, 0); |
||||
p.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); |
||||
p.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1)); |
||||
Controls.Add(p); |
||||
|
||||
nudAlpha.KeyDown += nudAlpha_KeyDown; |
||||
trackBar.KeyDown += trackBar_KeyDown; |
||||
} |
||||
|
||||
void trackBar_KeyDown(object sender, KeyEventArgs e) { |
||||
HandleKeyEvent((Control) sender, e); |
||||
} |
||||
|
||||
void nudAlpha_KeyDown(object sender, KeyEventArgs e) { |
||||
HandleKeyEvent((Control) sender, e); |
||||
} |
||||
|
||||
private void HandleKeyEvent(Control sender, KeyEventArgs e) { |
||||
if (e.KeyCode == Keys.Enter) { |
||||
e.SuppressKeyPress = true; // stop beep |
||||
e.Handled = true; |
||||
} |
||||
else if (e.KeyCode == Keys.Escape) { |
||||
e.SuppressKeyPress = true; |
||||
e.Handled = true; |
||||
Form f = FindForm(); |
||||
if (f != null) |
||||
f.Close(); |
||||
} |
||||
else if (e.KeyCode == Keys.Tab) { |
||||
// seems like because the Form is displays with Show(Window) but |
||||
// it is not modal, that stops tabs from working correctly, so |
||||
// it is handled manually: |
||||
sender.Parent.SelectNextControl(sender, true, true, true, true); |
||||
e.SuppressKeyPress = true; |
||||
e.Handled = true; |
||||
} |
||||
} |
||||
|
||||
void nudAlpha_ValueChanged(object sender, EventArgs e) { |
||||
trackBar.Value = Convert.ToInt32(nudAlpha.Value); |
||||
} |
||||
|
||||
public override Size GetPreferredSize(Size proposedSize) { |
||||
int w = SwatchSize * Cols; |
||||
int h = SwatchSize * (((Colors.Length - 1) / Cols) + 1); |
||||
h += Math.Max(trackBar.Height, nudAlpha.Height); |
||||
return new Size(w, h); |
||||
} |
||||
|
||||
public Color Color { |
||||
get { |
||||
return color; |
||||
} |
||||
set { |
||||
var c = value; |
||||
color = Color.FromArgb(Alpha, c.R, c.G, c.B); |
||||
Invalidate(); //Refresh(); |
||||
} |
||||
} |
||||
|
||||
public int Alpha { |
||||
get { |
||||
return trackBar.Value; |
||||
} |
||||
set { |
||||
trackBar.Value = value; |
||||
} |
||||
} |
||||
|
||||
public Color[] Colors { |
||||
get { |
||||
return colors; |
||||
} |
||||
set { |
||||
colors = value; |
||||
} |
||||
} |
||||
|
||||
void trackBar_ValueChanged(object sender, EventArgs e) { |
||||
nudAlpha.Value = trackBar.Value; |
||||
Color c = Color; |
||||
Color = Color.FromArgb(trackBar.Value, c.R, c.G, c.B); |
||||
Refresh(); |
||||
if (AlphaChanged != null) |
||||
AlphaChanged(this, EventArgs.Empty); |
||||
} |
||||
|
||||
protected override void OnPaint(PaintEventArgs e) { |
||||
base.OnPaint(e); |
||||
|
||||
int rows = ((Colors.Length - 1) / Cols) + 1; |
||||
int r1 = Width / Cols; |
||||
int r2 = Height / Cols; |
||||
int r = Math.Min(r1, r2); |
||||
if (r < SwatchSize) |
||||
r = SwatchSize; |
||||
|
||||
int offsetX = (Width - r * Cols) / 2; |
||||
int offsetY = ((Height - Math.Max(nudAlpha.Height, trackBar.Height)) - r * rows) / 2; |
||||
|
||||
var g = e.Graphics; |
||||
int x = 0; |
||||
int y = 0; |
||||
for (int i = 0, j = 1; i < colors.Length; i++, j++) { |
||||
Color c = colors[i]; |
||||
|
||||
using (var b = new SolidBrush(c)) |
||||
g.FillRectangle(b, x + offsetX, y + offsetY, r, r); |
||||
|
||||
if (j == Cols) { |
||||
j = 0; |
||||
x = 0; |
||||
y += r; |
||||
} |
||||
else { |
||||
x += r; |
||||
} |
||||
} |
||||
|
||||
using (var b = new SolidBrush(Color)) |
||||
g.FillRectangle(b, r / 2 + offsetX, r / 2 + offsetY, 2 * r, r); |
||||
} |
||||
} |
||||
|
||||
|
||||
class TrackBar2 : TrackBar { |
||||
|
||||
public TrackBar2() : base() { |
||||
AutoSize = false; |
||||
RECT r = GetThumbRect(this); |
||||
Height = r.Bottom - r.Top; |
||||
} |
||||
|
||||
public override Size GetPreferredSize(Size proposedSize) { |
||||
Size sz = base.GetPreferredSize(proposedSize); |
||||
RECT r = GetThumbRect(this); |
||||
sz.Height = r.Bottom - r.Top; |
||||
return sz; |
||||
} |
||||
|
||||
[StructLayout(LayoutKind.Sequential)] |
||||
private struct RECT { |
||||
public int Left; |
||||
public int Top; |
||||
public int Right; |
||||
public int Bottom; |
||||
} |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern void SendMessage(IntPtr hwnd, uint msg, IntPtr wp, ref RECT lp); |
||||
|
||||
private const uint TBM_GETTHUMBRECT = 0x419; |
||||
private static RECT GetThumbRect(TrackBar trackBar) { |
||||
RECT rc = new RECT(); |
||||
SendMessage(trackBar.Handle, TBM_GETTHUMBRECT, IntPtr.Zero, ref rc); |
||||
return rc; |
||||
} |
||||
} |
||||
|
||||
|
||||
using System; |
||||
using System.Drawing; |
||||
using System.Runtime.InteropServices; |
||||
using System.Windows.Forms; |
||||
|
||||
namespace Opulos.Core.UI { |
||||
|
||||
public class AlphaColorPanel : Panel { |
||||
|
||||
public event EventHandler AlphaChanged; |
||||
|
||||
NumericUpDown nudAlpha = new NumericUpDown { AutoSize = true, Minimum = 0, Maximum = 255, DecimalPlaces = 0, Increment = 1, Value = 255, Anchor = AnchorStyles.Top }; |
||||
TrackBar trackBar = new TrackBar2 { Minimum = 0, Maximum = 255, TickFrequency = 5, TickStyle = TickStyle.None, Orientation = Orientation.Horizontal, Value = 255, Anchor = AnchorStyles.Left | AnchorStyles.Right }; |
||||
Color[] colors = new Color[] { Color.White, Color.Black, Color.Green, Color.Blue, Color.Red, Color.Yellow }; |
||||
public int Cols { get; set; } |
||||
public int SwatchSize { get; set; } |
||||
|
||||
private Color color = Color.Empty; |
||||
|
||||
public AlphaColorPanel() : base() { |
||||
Dock = DockStyle.Fill; |
||||
AutoSize = true; |
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink; |
||||
DoubleBuffered = true; |
||||
//TabStop = true; |
||||
//SetStyle(ControlStyles.Selectable, true); |
||||
ResizeRedraw = true; |
||||
|
||||
Cols = 3; |
||||
SwatchSize = 100; |
||||
trackBar.ValueChanged += trackBar_ValueChanged; |
||||
nudAlpha.ValueChanged += nudAlpha_ValueChanged; |
||||
Alpha = 255; |
||||
|
||||
TableLayoutPanel p = new TableLayoutPanel { Dock = DockStyle.Bottom }; |
||||
p.AutoSize = true; |
||||
p.AutoSizeMode = AutoSizeMode.GrowAndShrink; |
||||
p.Controls.Add(nudAlpha, 0, 0); |
||||
p.Controls.Add(trackBar, 1, 0); |
||||
p.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); |
||||
p.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1)); |
||||
Controls.Add(p); |
||||
|
||||
nudAlpha.KeyDown += nudAlpha_KeyDown; |
||||
trackBar.KeyDown += trackBar_KeyDown; |
||||
} |
||||
|
||||
void trackBar_KeyDown(object sender, KeyEventArgs e) { |
||||
HandleKeyEvent((Control) sender, e); |
||||
} |
||||
|
||||
void nudAlpha_KeyDown(object sender, KeyEventArgs e) { |
||||
HandleKeyEvent((Control) sender, e); |
||||
} |
||||
|
||||
private void HandleKeyEvent(Control sender, KeyEventArgs e) { |
||||
if (e.KeyCode == Keys.Enter) { |
||||
e.SuppressKeyPress = true; // stop beep |
||||
e.Handled = true; |
||||
} |
||||
else if (e.KeyCode == Keys.Escape) { |
||||
e.SuppressKeyPress = true; |
||||
e.Handled = true; |
||||
Form f = FindForm(); |
||||
if (f != null) |
||||
f.Close(); |
||||
} |
||||
else if (e.KeyCode == Keys.Tab) { |
||||
// seems like because the Form is displays with Show(Window) but |
||||
// it is not modal, that stops tabs from working correctly, so |
||||
// it is handled manually: |
||||
sender.Parent.SelectNextControl(sender, true, true, true, true); |
||||
e.SuppressKeyPress = true; |
||||
e.Handled = true; |
||||
} |
||||
} |
||||
|
||||
void nudAlpha_ValueChanged(object sender, EventArgs e) { |
||||
trackBar.Value = Convert.ToInt32(nudAlpha.Value); |
||||
} |
||||
|
||||
public override Size GetPreferredSize(Size proposedSize) { |
||||
int w = SwatchSize * Cols; |
||||
int h = SwatchSize * (((Colors.Length - 1) / Cols) + 1); |
||||
h += Math.Max(trackBar.Height, nudAlpha.Height); |
||||
return new Size(w, h); |
||||
} |
||||
|
||||
public Color Color { |
||||
get { |
||||
return color; |
||||
} |
||||
set { |
||||
var c = value; |
||||
color = Color.FromArgb(Alpha, c.R, c.G, c.B); |
||||
Invalidate(); //Refresh(); |
||||
} |
||||
} |
||||
|
||||
public int Alpha { |
||||
get { |
||||
return trackBar.Value; |
||||
} |
||||
set { |
||||
trackBar.Value = value; |
||||
} |
||||
} |
||||
|
||||
public Color[] Colors { |
||||
get { |
||||
return colors; |
||||
} |
||||
set { |
||||
colors = value; |
||||
} |
||||
} |
||||
|
||||
void trackBar_ValueChanged(object sender, EventArgs e) { |
||||
nudAlpha.Value = trackBar.Value; |
||||
Color c = Color; |
||||
Color = Color.FromArgb(trackBar.Value, c.R, c.G, c.B); |
||||
Refresh(); |
||||
if (AlphaChanged != null) |
||||
AlphaChanged(this, EventArgs.Empty); |
||||
} |
||||
|
||||
protected override void OnPaint(PaintEventArgs e) { |
||||
base.OnPaint(e); |
||||
|
||||
int rows = ((Colors.Length - 1) / Cols) + 1; |
||||
int r1 = Width / Cols; |
||||
int r2 = Height / Cols; |
||||
int r = Math.Min(r1, r2); |
||||
if (r < SwatchSize) |
||||
r = SwatchSize; |
||||
|
||||
int offsetX = (Width - r * Cols) / 2; |
||||
int offsetY = ((Height - Math.Max(nudAlpha.Height, trackBar.Height)) - r * rows) / 2; |
||||
|
||||
var g = e.Graphics; |
||||
int x = 0; |
||||
int y = 0; |
||||
for (int i = 0, j = 1; i < colors.Length; i++, j++) { |
||||
Color c = colors[i]; |
||||
|
||||
using (var b = new SolidBrush(c)) |
||||
g.FillRectangle(b, x + offsetX, y + offsetY, r, r); |
||||
|
||||
if (j == Cols) { |
||||
j = 0; |
||||
x = 0; |
||||
y += r; |
||||
} |
||||
else { |
||||
x += r; |
||||
} |
||||
} |
||||
|
||||
using (var b = new SolidBrush(Color)) |
||||
g.FillRectangle(b, r / 2 + offsetX, r / 2 + offsetY, 2 * r, r); |
||||
} |
||||
} |
||||
|
||||
|
||||
class TrackBar2 : TrackBar { |
||||
|
||||
public TrackBar2() : base() { |
||||
AutoSize = false; |
||||
RECT r = GetThumbRect(this); |
||||
Height = r.Bottom - r.Top; |
||||
} |
||||
|
||||
public override Size GetPreferredSize(Size proposedSize) { |
||||
Size sz = base.GetPreferredSize(proposedSize); |
||||
RECT r = GetThumbRect(this); |
||||
sz.Height = r.Bottom - r.Top; |
||||
return sz; |
||||
} |
||||
|
||||
[StructLayout(LayoutKind.Sequential)] |
||||
private struct RECT { |
||||
public int Left; |
||||
public int Top; |
||||
public int Right; |
||||
public int Bottom; |
||||
} |
||||
|
||||
[DllImport("user32.dll")] |
||||
private static extern void SendMessage(IntPtr hwnd, uint msg, IntPtr wp, ref RECT lp); |
||||
|
||||
private const uint TBM_GETTHUMBRECT = 0x419; |
||||
private static RECT GetThumbRect(TrackBar trackBar) { |
||||
RECT rc = new RECT(); |
||||
SendMessage(trackBar.Handle, TBM_GETTHUMBRECT, IntPtr.Zero, ref rc); |
||||
return rc; |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
Loading…
Reference in new issue