123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- using System;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Imaging;
- using System.Windows.Forms;
- using System.Windows.Forms.VisualStyles;
- namespace PaintDotNet
- {
- public sealed class ArrowButton
- : ButtonBase
- {
- public bool drawTransparentBackColor = true;
- private ArrowDirection arrowDirection = ArrowDirection.Right;
- private bool drawWithGradient = false;
- private bool reverseArrowColors = false;
- private float arrowOutlineWidth = 1.0f;
- private bool forcedPushed = false;
- private Surface backBufferSurface = null;
- private RenderArgs backBuffer = null;
- public bool ForcedPushedAppearance
- {
- get
- {
- return this.forcedPushed;
- }
- set
- {
- if (this.forcedPushed != value)
- {
- this.forcedPushed = value;
- Invalidate();
- }
- }
- }
- public bool ReverseArrowColors
- {
- get
- {
- return this.reverseArrowColors;
- }
- set
- {
- if (this.reverseArrowColors != value)
- {
- this.reverseArrowColors = value;
- Invalidate();
- }
- }
- }
- public float ArrowOutlineWidth
- {
- get
- {
- return this.arrowOutlineWidth;
- }
- set
- {
- if (this.arrowOutlineWidth != value)
- {
- this.arrowOutlineWidth = value;
- Invalidate();
- }
- }
- }
- public ArrowDirection ArrowDirection
- {
- get
- {
- return this.arrowDirection;
- }
- set
- {
- if (this.arrowDirection != value)
- {
- this.arrowDirection = value;
- Invalidate();
- }
- }
- }
- public bool DrawWithGradient
- {
- get
- {
- return this.drawWithGradient;
- }
- set
- {
- if (this.drawWithGradient != value)
- {
- this.drawWithGradient = value;
- Invalidate();
- }
- }
- }
- public ArrowButton()
- {
- InitializeComponent();
- }
- private void InitializeComponent()
- {
- this.BackColor = this.drawTransparentBackColor ? Color.Transparent : Color.FromArgb(192, SystemColors.ControlDark);
- }
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (this.backBuffer != null)
- {
- this.backBuffer.Dispose();
- this.backBuffer = null;
- }
- if (this.backBufferSurface != null)
- {
- this.backBufferSurface.Dispose();
- this.backBufferSurface = null;
- }
- }
- base.Dispose(disposing);
- }
- protected override void OnPaintButton(Graphics g, PushButtonState state, bool drawFocusCues, bool drawKeyboardCues)
- {
- PushButtonState newState;
- if (this.forcedPushed)
- {
- newState = PushButtonState.Pressed;
- }
- else
- {
- newState = state;
- }
- OnPaintButtonImpl(g, newState, drawFocusCues, drawKeyboardCues);
- }
- private void OnPaintButtonImpl(Graphics g, PushButtonState state, bool drawFocusCues, bool drawKeyboardCues)
- {
- Color backColor;
- Color outlineColor;
- Color arrowFillColor;
- Color arrowOutlineColor;
- switch (state)
- {
- case PushButtonState.Disabled:
- backColor = this.drawTransparentBackColor ? Color.Transparent : Color.FromArgb(192, SystemColors.ControlDark);
- outlineColor = BackColor;
- arrowFillColor = Color.Gray;
- arrowOutlineColor = Color.Black;
- break;
- case PushButtonState.Hot:
- backColor = Color.FromArgb(64, SystemColors.HotTrack);
- outlineColor = backColor;
- arrowFillColor = Color.Blue;
- arrowOutlineColor = Color.White;
- break;
- case PushButtonState.Default:
- case PushButtonState.Normal:
- backColor = this.drawTransparentBackColor ? Color.Transparent : Color.FromArgb(192, SystemColors.ControlDark);
- outlineColor = Color.Transparent;
- arrowFillColor = Color.Black;
- arrowOutlineColor = Color.White;
- break;
- case PushButtonState.Pressed:
- backColor = Color.FromArgb(192, SystemColors.Highlight);
- outlineColor = Color.FromArgb(192, SystemColors.Highlight);
- arrowFillColor = Color.Blue;
- arrowOutlineColor = Color.White;
- break;
- default:
- throw new InvalidEnumArgumentException("buttonState");
- }
- // Draw parent background
- IPaintBackground asIpb = Parent as IPaintBackground;
- if (!this.drawWithGradient || asIpb == null)
- {
- if (asIpb != null)
- {
- Rectangle screenRect = RectangleToScreen(ClientRectangle);
- Rectangle parentRect = Parent.RectangleToClient(screenRect);
- g.TranslateTransform(-Left, -Top, MatrixOrder.Append);
- asIpb.PaintBackground(g, parentRect);
- g.TranslateTransform(+Left, +Top, MatrixOrder.Append);
- }
- else
- {
- using (SolidBrush backBrush = new SolidBrush(BackColor))
- {
- g.FillRectangle(backBrush, ClientRectangle);
- }
- }
- }
- else
- {
- if (this.backBufferSurface != null &&
- (this.backBufferSurface.Width != ClientSize.Width || this.backBufferSurface.Height != ClientSize.Height))
- {
- this.backBuffer.Dispose();
- this.backBuffer = null;
- this.backBufferSurface.Dispose();
- this.backBufferSurface = null;
- }
- if (this.backBufferSurface == null)
- {
- this.backBufferSurface = new Surface(ClientSize.Width, ClientSize.Height);
- this.backBuffer = new RenderArgs(this.backBufferSurface);
- }
- Rectangle screenRect = RectangleToScreen(ClientRectangle);
- Rectangle parentRect = Parent.RectangleToClient(screenRect);
- using (Graphics bg = Graphics.FromImage(this.backBuffer.Bitmap))
- {
- bg.TranslateTransform(-Left, -Top, MatrixOrder.Append);
- asIpb.PaintBackground(bg, parentRect);
- }
- BitmapData bitmapData = this.backBuffer.Bitmap.LockBits(
- new Rectangle(0, 0, this.backBuffer.Bitmap.Width, this.backBuffer.Bitmap.Height),
- ImageLockMode.ReadWrite,
- PixelFormat.Format32bppArgb);
- int startAlpha;
- int finishAlpha;
- if (this.arrowDirection == ArrowDirection.Left || this.arrowDirection == ArrowDirection.Up)
- {
- startAlpha = 255;
- finishAlpha = 0;
- }
- else if (this.arrowDirection == ArrowDirection.Right || this.ArrowDirection == ArrowDirection.Down)
- {
- startAlpha = 0;
- finishAlpha = 255;
- }
- else
- {
- throw new InvalidEnumArgumentException("this.arrowDirection");
- }
- unsafe
- {
- if (this.arrowDirection == ArrowDirection.Left || this.arrowDirection == ArrowDirection.Right)
- {
- for (int x = 0; x < this.backBuffer.Bitmap.Width; ++x)
- {
- float lerp = (float)x / (float)(this.backBuffer.Bitmap.Width - 1);
- if (this.arrowDirection == ArrowDirection.Left)
- {
- lerp = 1.0f - (float)Math.Cos(lerp * (Math.PI / 2.0));
- }
- else
- {
- lerp = (float)Math.Sin(lerp * (Math.PI / 2.0));
- }
- byte alpha = (byte)(startAlpha + ((int)(lerp * (finishAlpha - startAlpha))));
- byte* pb = (byte*)bitmapData.Scan0.ToPointer() + (x * 4) + 3; // *4 because 4-bytes per pixel, +3 to get to alpha channel
- for (int y = 0; y < this.backBuffer.Bitmap.Height; ++y)
- {
- *pb = alpha;
- pb += bitmapData.Stride;
- }
- }
- }
- else if (this.arrowDirection == ArrowDirection.Up || this.arrowDirection == ArrowDirection.Down)
- {
- for (int y = 0; y < this.backBuffer.Bitmap.Height; ++y)
- {
- float lerp = (float)y / (float)(this.backBuffer.Bitmap.Height - 1);
- lerp = 1.0f - (float)Math.Cos(lerp * (Math.PI / 2.0));
- byte alpha = (byte)(startAlpha + ((int)(lerp * (finishAlpha - startAlpha))));
- byte* pb = (byte*)bitmapData.Scan0.ToPointer() + (y * bitmapData.Stride) + 3; // *Stride for access to start of row, +3 to get to alpha channel
- for (int x = 0; x < this.backBuffer.Bitmap.Width; ++x)
- {
- *pb = alpha;
- pb += 4; // 4 for byte size of pixel
- }
- }
- }
- }
- this.backBuffer.Bitmap.UnlockBits(bitmapData);
- bitmapData = null;
- g.DrawImage(this.backBuffer.Bitmap, new Point(0, 0));
- }
- using (SolidBrush fillBrush = new SolidBrush(backColor))
- {
- g.FillRectangle(fillBrush, ClientRectangle);
- }
- // Draw outline
- using (Pen outlinePen = new Pen(outlineColor))
- {
- g.DrawRectangle(outlinePen, new Rectangle(0, 0, ClientSize.Width - 1, ClientSize.Height - 1));
- }
- // Draw button
- g.SmoothingMode = SmoothingMode.AntiAlias;
- const int arrowInset = 3;
- int arrowSize = Math.Min(ClientSize.Width - arrowInset * 2, ClientSize.Height - arrowInset * 2) - 1;
- PointF a;
- PointF b;
- PointF c;
- switch (this.arrowDirection)
- {
- case ArrowDirection.Left:
- a = new PointF(arrowInset, ClientSize.Height / 2);
- b = new PointF(ClientSize.Width - arrowInset, (ClientSize.Height - arrowSize) / 2);
- c = new PointF(ClientSize.Width - arrowInset, (ClientSize.Height + arrowSize) / 2);
- break;
- case ArrowDirection.Right:
- a = new PointF(ClientSize.Width - arrowInset, ClientSize.Height / 2);
- b = new PointF(arrowInset, (ClientSize.Height - arrowSize) / 2);
- c = new PointF(arrowInset, (ClientSize.Height + arrowSize) / 2);
- break;
- case ArrowDirection.Up:
- a = new PointF(ClientSize.Width / 2, (ClientSize.Height - arrowSize) / 2);
- b = new PointF((ClientSize.Width - arrowSize) / 2, (ClientSize.Height + arrowSize) / 2);
- c = new PointF((ClientSize.Width + arrowSize) / 2, (ClientSize.Height + arrowSize) / 2);
- break;
- case ArrowDirection.Down:
- a = new PointF(ClientSize.Width / 2, (ClientSize.Height + arrowSize) / 2);
- b = new PointF((ClientSize.Width - arrowSize) / 2, (ClientSize.Height - arrowSize) / 2);
- c = new PointF((ClientSize.Width + arrowSize) / 2, (ClientSize.Height - arrowSize) / 2);
- break;
- default:
- throw new InvalidEnumArgumentException("this.arrowDirection");
- }
- // SPIKE in order to get this rendering correctly right away
- if (this.arrowDirection == ArrowDirection.Down)
- {
- SmoothingMode oldSM = g.SmoothingMode;
- g.SmoothingMode = SmoothingMode.None;
- float top = b.Y - 2;
- float left = b.X;
- float right = c.X;
- int squareCount = (int)((right - left) / 3);
- Brush outlineBrush = new SolidBrush(arrowOutlineColor);
- Brush interiorBrush = new SolidBrush(arrowFillColor);
- g.FillRectangle(interiorBrush, left, top, right - left + 1, 3);
- ++left;
- while (left < right)
- {
- RectangleF rect = new RectangleF(left, top + 1, 1, 1);
- g.FillRectangle(outlineBrush, rect);
- left += 2;
- }
- outlineBrush.Dispose();
- outlineBrush = null;
- interiorBrush.Dispose();
- interiorBrush = null;
- a.Y += 2;
- b.Y += 2;
- c.Y += 2;
- g.SmoothingMode = oldSM;
- }
- if (this.reverseArrowColors)
- {
- Utility.Swap(ref arrowFillColor, ref arrowOutlineColor);
- }
- using (Brush buttonBrush = new SolidBrush(arrowFillColor))
- {
- g.FillPolygon(buttonBrush, new PointF[] { a, b, c });
- }
- using (Pen buttonPen = new Pen(arrowOutlineColor, this.arrowOutlineWidth))
- {
- g.DrawPolygon(buttonPen, new PointF[] { a, b, c });
- }
- }
- }
- }
|