// TODO: Use VisualStyles stuff in .NET 2.0 instead /// <summary> /// Draws a button in the appropriate system theme (Aero vs. Luna vs. Classic). /// </summary> /// <remarks> /// Note to implementors: This may be implemented as a simple thunk to ControlPaint.DrawButton(). /// </remarks> public static void DrawThemedButton( Control hostControl, Graphics g, int x, int y, int width, int height, UI.ButtonState state) { System.Windows.Forms.ButtonState swfState; switch (state) { case UI.ButtonState.Disabled: swfState = System.Windows.Forms.ButtonState.Inactive; break; default: case UI.ButtonState.Hot: case UI.ButtonState.Normal: swfState = System.Windows.Forms.ButtonState.Normal; break; case UI.ButtonState.Pressed: swfState = System.Windows.Forms.ButtonState.Pushed; break; } ControlPaint.DrawButton(g, x, y, width, height, swfState); GC.KeepAlive(hostControl); }
protected override void OnPaintButton(Graphics g, UI.ButtonState state, bool drawAsDefault, bool drawFocusCues, bool drawKeyboardCues) { UI.ButtonState newState; if (this.forcedPushed) { newState = UI.ButtonState.Pressed; } else { newState = state; } OnPaintButtonImpl(g, newState, drawAsDefault, drawFocusCues, drawKeyboardCues); }
public void SetPartRenderState(ItemPart itemPart, UI.ButtonState renderState) { switch (itemPart) { case ItemPart.None: break; case ItemPart.CloseButton: CloseRenderState = renderState; break; case ItemPart.Image: ImageRenderState = renderState; break; default: throw new InvalidEnumArgumentException(); } }
private void OnPaintButtonImpl(Graphics g, UI.ButtonState state, bool drawAsDefault, bool drawFocusCues, bool drawKeyboardCues) { Color backColor; Color outlineColor; Color arrowFillColor; Color arrowOutlineColor; switch (state) { case UI.ButtonState.Disabled: backColor = Color.Transparent; outlineColor = BackColor; arrowFillColor = Color.Gray; arrowOutlineColor = Color.Black; break; case UI.ButtonState.Hot: backColor = Color.FromArgb(64, SystemColors.HotTrack); outlineColor = backColor; arrowFillColor = Color.Blue; arrowOutlineColor = Color.White; break; case UI.ButtonState.Normal: backColor = Color.Transparent; outlineColor = Color.Transparent; arrowFillColor = Color.Black; arrowOutlineColor = Color.White; break; case UI.ButtonState.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 }); } }
private Size MeasureAndDraw(Graphics g, bool enableDrawing, UI.ButtonState state, bool drawAsDefault, bool drawFocusCues, bool drawKeyboardCues) { if (enableDrawing) { g.PixelOffsetMode = PixelOffsetMode.Half; g.CompositingMode = CompositingMode.SourceOver; g.InterpolationMode = InterpolationMode.Bilinear; } int marginX = UI.ScaleWidth(9); int marginYTop = UI.ScaleHeight(8); int marginYBottom = UI.ScaleHeight(9); int paddingX = UI.ScaleWidth(8); int paddingY = UI.ScaleHeight(3); int offsetX = 0; int offsetY = 0; if (enableDrawing) { switch (state) { case UI.ButtonState.Disabled: UI.DrawThemedButton(this, g, 0, 0, ClientSize.Width, ClientSize.Height, UI.ButtonState.Disabled); break; case UI.ButtonState.Pressed: UI.DrawThemedButton(this, g, 0, 0, ClientSize.Width, ClientSize.Height, UI.ButtonState.Pressed); offsetX = 1; offsetY = 1; break; case UI.ButtonState.Hot: UI.DrawThemedButton(this, g, 0, 0, ClientSize.Width, ClientSize.Height, UI.ButtonState.Hot); break; case UI.ButtonState.Normal: using (Brush backBrush = new SolidBrush(this.BackColor)) { g.FillRectangle(backBrush, ClientRectangle); } break; } } Rectangle actionImageRect; Brush textBrush = new SolidBrush(SystemColors.WindowText); if (this.actionImage == null) { actionImageRect = new Rectangle(offsetX, offsetY + marginYTop, 0, 0); } else { actionImageRect = new Rectangle(offsetX + marginX, offsetY + marginYTop, UI.ScaleWidth(this.actionImage.Width), UI.ScaleHeight(this.actionImage.Height)); Rectangle srcRect = new Rectangle(0, 0, this.actionImage.Width, this.actionImage.Height); if (enableDrawing) { Image drawMe = Enabled ? this.actionImage : this.actionImageDisabled; actionImageRect.Y += 2; g.DrawImage(drawMe, actionImageRect, srcRect, GraphicsUnit.Pixel); actionImageRect.Y -= 2; } } int actionTextX = actionImageRect.Right + paddingX; int actionTextY = actionImageRect.Top; int actionTextWidth = ClientSize.Width - actionTextX - marginX + offsetX; StringFormat stringFormat = (StringFormat)StringFormat.GenericTypographic.Clone(); stringFormat.HotkeyPrefix = drawKeyboardCues ? HotkeyPrefix.Show : HotkeyPrefix.Hide; SizeF actionTextSize = g.MeasureString(this.actionText, this.actionTextFont, actionTextWidth, stringFormat); Rectangle actionTextRect = new Rectangle(actionTextX, actionTextY, actionTextWidth, (int)Math.Ceiling(actionTextSize.Height)); if (enableDrawing) { if (state == UI.ButtonState.Disabled) { ControlPaint.DrawStringDisabled(g, this.actionText, this.actionTextFont, this.BackColor, actionTextRect, stringFormat); } else { g.DrawString(this.actionText, this.actionTextFont, textBrush, actionTextRect, stringFormat); } } int descriptionTextX = actionTextX; int descriptionTextY = actionTextRect.Bottom + paddingY; int descriptionTextWidth = actionTextWidth; SizeF descriptionTextSize = g.MeasureString(this.explanationText, this.explanationTextFont, descriptionTextWidth, stringFormat); Rectangle descriptionTextRect = new Rectangle(descriptionTextX, descriptionTextY, descriptionTextWidth, (int)Math.Ceiling(descriptionTextSize.Height)); if (enableDrawing) { if (state == UI.ButtonState.Disabled) { ControlPaint.DrawStringDisabled(g, this.explanationText, this.explanationTextFont, this.BackColor, descriptionTextRect, stringFormat); } else { g.DrawString(this.explanationText, this.explanationTextFont, textBrush, descriptionTextRect, stringFormat); } } if (enableDrawing) { if (drawFocusCues) { ControlPaint.DrawFocusRectangle(g, new Rectangle(3, 3, ClientSize.Width - 5, ClientSize.Height - 5)); } } if (textBrush != null) { textBrush.Dispose(); textBrush = null; } stringFormat.Dispose(); stringFormat = null; Size layoutSize = new Size(ClientSize.Width, descriptionTextRect.Bottom + marginYBottom); return(layoutSize); }
protected override void OnPaintButton(Graphics g, UI.ButtonState state, bool drawAsDefault, bool drawFocusCues, bool drawKeyboardCues) { MeasureAndDraw(g, true, state, drawAsDefault, drawFocusCues, drawKeyboardCues); }
// TODO: Use VisualStyles stuff in .NET 2.0 instead /// <summary> /// Draws a button in the appropriate system theme (Aero vs. Luna vs. Classic). /// </summary> /// <remarks> /// Note to implementors: This may be implemented as a simple thunk to ControlPaint.DrawButton(). /// </remarks> public static void DrawThemedButton( Control hostControl, Graphics g, int x, int y, int width, int height, UI.ButtonState state) { IntPtr hTheme = OpenTheme(hostControl); if (hTheme != IntPtr.Zero) { NativeStructs.RECT rect = new NativeStructs.RECT(); rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; int iState; switch (state) { case UI.ButtonState.Disabled: iState = NativeConstants.PBS_DISABLED; break; case UI.ButtonState.Hot: iState = NativeConstants.PBS_HOT; break; default: case UI.ButtonState.Normal: iState = NativeConstants.PBS_NORMAL; break; case UI.ButtonState.Pressed: iState = NativeConstants.PBS_PRESSED; break; } IntPtr hdc = g.GetHdc(); SafeNativeMethods.DrawThemeBackground( hTheme, hdc, NativeConstants.BP_PUSHBUTTON, iState, ref rect, ref rect); g.ReleaseHdc(hdc); SafeNativeMethods.CloseThemeData(hTheme); hTheme = IntPtr.Zero; } else { System.Windows.Forms.ButtonState swfState; switch (state) { case UI.ButtonState.Disabled: swfState = System.Windows.Forms.ButtonState.Inactive; break; default: case UI.ButtonState.Hot: case UI.ButtonState.Normal: swfState = System.Windows.Forms.ButtonState.Normal; break; case UI.ButtonState.Pressed: swfState = System.Windows.Forms.ButtonState.Pushed; break; } ControlPaint.DrawButton(g, x, y, width, height, swfState); } GC.KeepAlive(hostControl); }
protected abstract void OnPaintButton( Graphics g, UI.ButtonState state, bool drawAsDefault, bool drawFocusCues, bool drawKeyboardCues);