// // System.Windows.Forms.ControlPaint.cs // // Author: // stubbed out by Jaak Simm (jaaksimm@firm.ee) // Dennis Hayes (dennish@Raytek.com) // Alexandre Pigolkine (pigolkine@gmx.de) // // rewritten for System.Drawing // by Peter Dennis Bartok (pbartok@novell.com) // // // (C) Ximian, Inc 2002/3 // (C) Novell, Inc 2003 // using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; namespace System.Windows.Forms { /// /// Provides methods used to paint common Windows controls and their elements. /// public sealed class ControlPaint { static int RGBMax=255; static int HLSMax=255; private static Color Win32ToColor(int Win32Color) { return(Color.FromArgb( (int)(Win32Color) & 0xff0000 >> 16, // blue (int)(Win32Color) & 0xff00 >> 8, // green (int)(Win32Color) & 0xff // red )); } #region Properties public static Color ContrastControlDark { get { return(SystemColors.ControlDark); } } #endregion #region Helpers internal static void Color2HBS(Color color, out int h, out int l, out int s) { int r; int g; int b; int cMax; int cMin; int rDelta; int gDelta; int bDelta; r=color.R; g=color.G; b=color.B; cMax = Math.Max(Math.Max(r, g), b); cMin = Math.Min(Math.Min(r, g), b); l = (((cMax+cMin)*HLSMax)+RGBMax)/(2*RGBMax); if (cMax==cMin) { // Achromatic h=0; // h undefined s=0; l=r; return; } /* saturation */ if (l<=(HLSMax/2)) { s=(((cMax-cMin)*HLSMax)+((cMax+cMin)/2))/(cMax+cMin); } else { s=(((cMax-cMin)*HLSMax)+((2*RGBMax-cMax-cMin)/2))/(2*RGBMax-cMax-cMin); } /* hue */ rDelta=(((cMax-r)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); gDelta=(((cMax-g)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); bDelta=(((cMax-b)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); if (r == cMax) { h=bDelta - gDelta; } else if (g == cMax) { h=(HLSMax/3) + rDelta - bDelta; } else { /* B == cMax */ h=((2*HLSMax)/3) + gDelta - rDelta; } if (h<0) { h+=HLSMax; } if (h>HLSMax) { h-=HLSMax; } } private static int HueToRGB(int n1, int n2, int hue) { if (hue<0) { hue+=HLSMax; } if (hue>HLSMax) { hue -= HLSMax; } /* return r,g, or b value from this tridrant */ if (hue<(HLSMax/6)) { return(n1+(((n2-n1)*hue+(HLSMax/12))/(HLSMax/6))); } if (hue<(HLSMax/2)) { return(n2); } if (hue<((HLSMax*2)/3)) { return(n1+(((n2-n1)*(((HLSMax*2)/3)-hue)+(HLSMax/12))/(HLSMax/6))); } else { return(n1); } } private static Color HBS2Color(int hue, int lum, int sat) { int R; int G; int B; int Magic1; int Magic2; if (sat == 0) { /* Achromatic */ R=G=B=(lum*RGBMax)/HLSMax; // FIXME : Should throw exception if hue!=0 } else { if (lum<=(HLSMax/2)) { Magic2=(lum*(HLSMax+sat)+(HLSMax/2))/HLSMax; } else { Magic2=sat+lum-((sat*lum)+(HLSMax/2))/HLSMax; } Magic1=2*lum-Magic2; R = Math.Min(255, (HueToRGB(Magic1,Magic2,hue+(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax); G = Math.Min(255, (HueToRGB(Magic1,Magic2,hue)*RGBMax+(HLSMax/2))/HLSMax); B = Math.Min(255, (HueToRGB(Magic1,Magic2,hue-(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax); } return(Color.FromArgb(R, G, B)); } #endregion #region Methods /// following methods were not stubbed out, because they only support .NET framework: public static IntPtr CreateHBitmap16Bit(Bitmap bitmap,Color background){ throw new NotImplementedException (); } public static IntPtr CreateHBitmapColorMask(Bitmap bitmap,IntPtr monochromeMask){ throw new NotImplementedException (); } public static IntPtr CreateHBitmapTransparencyMask(Bitmap bitmap){ throw new NotImplementedException (); } public static Color Light(Color baseColor) { return Light( baseColor, 10.0f); } public static Color Light(Color baseColor,float percOfLightLight) { int H, I, S; ControlPaint.Color2HBS(baseColor, out H, out I, out S); int NewIntensity = Math.Min( 255, I + ((255*(int)percOfLightLight)/100)); return ControlPaint.HBS2Color(H, NewIntensity, S); } public static Color LightLight(Color baseColor) { return Light( baseColor, 20.0f); } public static Color Dark(Color baseColor) { return Dark(baseColor, 10.0f); } public static Color Dark(Color baseColor,float percOfDarkDark) { int H, I, S; ControlPaint.Color2HBS(baseColor, out H, out I, out S); int NewIntensity = Math.Max(0, I - ((255*(int)percOfDarkDark) / 100)); return ControlPaint.HBS2Color(H, NewIntensity, S); } public static Color DarkDark(Color baseColor) { return Dark(baseColor, 20.0f); } public static void DrawBorder(Graphics graphics, Rectangle bounds, Color color, ButtonBorderStyle style) { DrawBorder(graphics, bounds, color, 1, style, color, 1, style, color, 1, style, color, 1, style); } public static void DrawBorder( Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth, ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, int bottomWidth, ButtonBorderStyle bottomStyle) { DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom-1, leftWidth, leftColor, leftStyle, Border3DSide.Left); DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Right-1, bounds.Top, topWidth, topColor, topStyle, Border3DSide.Top); DrawBorderInternal(graphics, bounds.Right-1, bounds.Top, bounds.Right-1, bounds.Bottom-1, rightWidth, rightColor, rightStyle, Border3DSide.Right); DrawBorderInternal(graphics, bounds.Left, bounds.Bottom-1, bounds.Right-1, bounds.Bottom-1, bottomWidth, bottomColor, bottomStyle, Border3DSide.Bottom); } private static void DrawBorderInternal(Graphics graphics, int startX, int startY, int endX, int endY, int width, Color color, ButtonBorderStyle style, Border3DSide side) { Pen pen=new Pen(color, 1); switch(style) { case ButtonBorderStyle.Solid: { pen.DashStyle=DashStyle.Solid; break; } case ButtonBorderStyle.Dashed: { pen.DashStyle=DashStyle.Dash; break; } case ButtonBorderStyle.Dotted: { pen.DashStyle=DashStyle.Dot; break; } case ButtonBorderStyle.Inset: { pen.DashStyle=DashStyle.Solid; break; } case ButtonBorderStyle.Outset: { pen.DashStyle=DashStyle.Solid; break; } default: case ButtonBorderStyle.None: { pen.Dispose(); return; } } switch(style) { case ButtonBorderStyle.Outset: { Color colorGrade; int hue, brightness, saturation; int brightnessSteps; int brightnessDownSteps; Color2HBS(color, out hue, out brightness, out saturation); brightnessDownSteps=brightness/width; if (brightness>127) { brightnessSteps=Math.Max(6, (160-brightness)/width); } else { brightnessSteps=(127-brightness)/width; } for (int i=0; i127) { brightnessSteps=Math.Max(6, (160-brightness)/width); } else { brightnessSteps=(127-brightness)/width; } for (int i=0; i127) { foreColor=Color.Black; } else { foreColor=Color.White; } #if false /* Commented out until I take the time and figure out which HatchStyle will match requirements. The code below is only correct for Percent50. */ if (pixelsBetweenDots.Width==pixelsBetweenDots.Height) { HatchBrush brush=null; switch(pixelsBetweenDots.Width) { case 2: brush=new HatchBrush(HatchStyle.Percent50, foreColor, backColor); break; case 4: brush=new HatchBrush(HatchStyle.Percent25, foreColor, backColor); break; case 5: brush=new HatchBrush(HatchStyle.Percent20, foreColor, backColor); break; default: { /* Have to do it the slow way */ break; } } if (brush!=null) { graphics.FillRectangle(brush, area); pen.Dispose(); brush.Dispose(); return; } } #endif /* Slow method */ Bitmap bitmap = new Bitmap(area.Width, area.Height, graphics); for (int x=0; x 256 colors on the display. */ ImageAttributes imageAttributes=new ImageAttributes(); ColorMatrix colorMatrix=new ColorMatrix(new float[][] { // This table would create a perfect grayscale image, based on luminance // new float[]{0.3f,0.3f,0.3f,0,0}, // new float[]{0.59f,0.59f,0.59f,0,0}, // new float[]{0.11f,0.11f,0.11f,0,0}, // new float[]{0,0,0,1,0,0}, // new float[]{0,0,0,0,1,0}, // new float[]{0,0,0,0,0,1} // This table generates a image that is grayscaled and then // brightened up. Seems to match MS close enough. new float[]{0.2f,0.2f,0.2f,0,0}, new float[]{0.41f,0.41f,0.41f,0,0}, new float[]{0.11f,0.11f,0.11f,0,0}, new float[]{0.15f,0.15f,0.15f,1,0,0}, new float[]{0.15f,0.15f,0.15f,0,1,0}, new float[]{0.15f,0.15f,0.15f,0,0,1} }); imageAttributes.SetColorMatrix(colorMatrix); graphics.DrawImage(image, new Rectangle(x, y, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttributes); imageAttributes.Dispose(); } public static void DrawLockedFrame(Graphics graphics, Rectangle rectangle, bool primary) { Pen penBorder; Pen penInside; if (primary) { penBorder=new Pen(Color.White, 2); penInside=new Pen(Color.Black, 1); } else { penBorder=new Pen(Color.Black, 2); penInside=new Pen(Color.White, 1); } penBorder.Alignment=PenAlignment.Inset; penInside.Alignment=PenAlignment.Inset; graphics.DrawRectangle(penBorder, rectangle); graphics.DrawRectangle(penInside, rectangle.X+2, rectangle.Y+2, rectangle.Width-5, rectangle.Height-5); penBorder.Dispose(); penInside.Dispose(); } public static void DrawMenuGlyph(Graphics graphics, Rectangle rectangle, MenuGlyph glyph) { Rectangle rect; int lineWidth; // MS seems to draw the background white graphics.FillRectangle(new SolidBrush(Color.White), rectangle); switch(glyph) { case MenuGlyph.Arrow: { Point[] arrow = new Point[3]; Point P1; Point P2; Point P3; int centerX; int centerY; int shiftX; int shiftY; rect=new Rectangle(rectangle.X+rectangle.Width/4, rectangle.Y+rectangle.Height/4, rectangle.Width/2, rectangle.Height/2); centerX=rect.Left+rect.Width/2; centerY=rect.Top+rect.Height/2; shiftX=Math.Max(1, rect.Width/8); shiftY=Math.Max(1, rect.Height/8); rect.X-=shiftX; centerX-=shiftX; P1=new Point(centerX, rect.Top-1); P2=new Point(centerX, rect.Bottom); P3=new Point(rect.Right, centerY); arrow[0]=P1; arrow[1]=P2; arrow[2]=P3; graphics.FillPolygon(SystemBrushes.ControlText, arrow, FillMode.Winding); return; } case MenuGlyph.Bullet: { SolidBrush sb; lineWidth=Math.Max(2, rectangle.Width/3); rect=new Rectangle(rectangle.X+lineWidth, rectangle.Y+lineWidth, rectangle.Width-lineWidth*2, rectangle.Height-lineWidth*2); sb=new SolidBrush(SystemColors.MenuText); graphics.FillEllipse(sb, rect); sb.Dispose(); return; } case MenuGlyph.Checkmark: { int Scale; lineWidth=Math.Max(2, rectangle.Width/6); Scale=Math.Max(1, rectangle.Width/12); rect=new Rectangle(rectangle.X+lineWidth, rectangle.Y+lineWidth, rectangle.Width-lineWidth*2, rectangle.Height-lineWidth*2); for (int i=0; i127) { foreColor=SystemColors.ControlDark; } else { foreColor=SystemColors.ControlLight; } transparent=Color.FromArgb(0, backColor); if (active==true) { brush=new HatchBrush(HatchStyle.LightUpwardDiagonal, foreColor, transparent); } else { brush=new HatchBrush(HatchStyle.Percent25, foreColor, transparent); } container=graphics.BeginContainer(); graphics.ExcludeClip(insideRect); graphics.FillRectangle(brush, outsideRect); graphics.EndContainer(container); brush.Dispose(); } public static void DrawSizeGrip(Graphics graphics, Color backColor, Rectangle bounds) { int h; int b; int s; Pen pen1; Pen pen2; Color2HBS(backColor, out h, out b, out s); pen1=new Pen(HBS2Color(h, Math.Min(255, (b*166)/100), s), 1); pen2=new Pen(HBS2Color(h, (b*33)/100, s), 1); for (int i=0; i