public void ControlPaint_DrawBorder_Dashed_Rendering() { using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC); Rectangle bounds = new Rectangle(10, 10, 10, 10); ControlPaint.DrawBorder(graphics, bounds, Color.Pink, ButtonBorderStyle.Dashed); // For whatever reason GDI+ renders as polygons scaled 16x with a 1/16th world transform applied. Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f); // This is the default pen style GDI+ renders dotted lines with Gdi32.PS penStyle = Gdi32.PS.SOLID | Gdi32.PS.JOIN_ROUND | Gdi32.PS.COSMETIC | Gdi32.PS.ENDCAP_FLAT | Gdi32.PS.JOIN_BEVEL | Gdi32.PS.GEOMETRIC; emf.Validate( state, Validate.PolyPolygon16( new Rectangle(8, 8, 13, 13), polyCount: 9, State.Transform(oneSixteenth), State.Pen(16, Color.Pink, penStyle), State.Brush(Color.Pink, Gdi32.BS.SOLID))); }
public void ControlPaint_DrawBorder_Inset_Rendering() { using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC); Rectangle bounds = new Rectangle(10, 10, 10, 10); ControlPaint.DrawBorder(graphics, bounds, Color.Gray, ButtonBorderStyle.Inset); // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied. // For test readability we'll transform the points from our coordinates to the logical coordinates. Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f); Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f); // This is the default pen style GDI+ renders polylines with Gdi32.PS penStyle = Gdi32.PS.SOLID | Gdi32.PS.JOIN_ROUND | Gdi32.PS.COSMETIC | Gdi32.PS.ENDCAP_FLAT | Gdi32.PS.JOIN_MITER | Gdi32.PS.GEOMETRIC; emf.Validate( state, // Top Validate.Polyline16( bounds: null, PointArray(times16, 10, 10, 19, 10), State.Pen(16, ControlPaint.DarkDark(Color.Gray), penStyle), State.Transform(oneSixteenth)), // Left Validate.Polyline16( bounds: null, PointArray(times16, 10, 10, 10, 19), State.Pen(16, ControlPaint.DarkDark(Color.Gray), penStyle), State.Transform(oneSixteenth)), // Bottom Validate.Polyline16( bounds: null, PointArray(times16, 10, 19, 19, 19), State.Pen(16, ControlPaint.LightLight(Color.Gray), penStyle), State.Transform(oneSixteenth)), // Right Validate.Polyline16( bounds: null, PointArray(times16, 19, 10, 19, 19), State.Pen(16, ControlPaint.LightLight(Color.Gray), penStyle), State.Transform(oneSixteenth)), // Top inset Validate.Polyline16( bounds: null, PointArray(times16, 11, 11, 18, 11), State.Pen(16, ControlPaint.Light(Color.Gray), penStyle), State.Transform(oneSixteenth)), // Left inset Validate.Polyline16( bounds: null, PointArray(times16, 11, 11, 11, 18), State.Pen(16, ControlPaint.Light(Color.Gray), penStyle), State.Transform(oneSixteenth)) ); }
public unsafe void TextRenderer_DrawText_DefaultBackground_RendersTransparent(Func <IDeviceContext, Action> func) { using var emf = EmfScope.Create(); DeviceContextState state = new DeviceContextState(emf); func(new HdcDeviceContextAdapter(emf)).Invoke(); bool success = false; emf.EnumerateWithState((ref EmfRecord record, DeviceContextState state) => { switch (record.Type) { case Gdi32.EMR.EXTTEXTOUTW: var textOut = record.ExtTextOutWRecord; Assert.Equal("Acrylic", textOut->emrtext.GetString().ToString()); Assert.Equal(Gdi32.MM.TEXT, state.MapMode); Assert.Equal(Gdi32.BKMODE.TRANSPARENT, state.BackgroundMode); Assert.Equal((COLORREF)Color.Blue, state.TextColor); Assert.Equal(SystemFonts.DefaultFont.Name, state.SelectedFont); success = true; return(false); } return(true); }, state); Assert.True(success, "Did not find the text out record."); }
public void NumericUpDown_VisualStyles_off_BasicRendering_ControlDisabled() { if (Application.RenderWithVisualStyles) { return; } using var form = new Form(); using var upDown = new NumericUpDown(); form.Controls.Add(upDown); // Check the disabled state upDown.Enabled = false; using var emfDisabled = new EmfScope(); DeviceContextState state = new DeviceContextState(emfDisabled); upDown.PrintToMetafile(emfDisabled); emfDisabled.Validate( state, Validate.Rectangle( new Rectangle(0, 0, 99, 18), State.Pen(1, upDown.BackColor, Gdi32.PS.SOLID)), Validate.Rectangle( new Rectangle(1, 1, 97, 16), State.Pen(1, SystemColors.Control, Gdi32.PS.SOLID)), Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.LineTo( (0, 18), (16, 18), State.Pen(1, upDown.BackColor, Gdi32.PS.SOLID))); }
public unsafe void Button_FlatStyle_WithText_Rectangle() { using Button button = new Button { Text = "Flat Style", FlatStyle = FlatStyle.Flat, }; using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); emf.Validate( state, Validate.SkipType(Gdi32.EMR.BITBLT), Validate.TextOut("Flat Style"), Validate.Rectangle( new Rectangle(0, 0, button.Width - 1, button.Height - 1), penColor: Color.Black, penStyle: Gdi32.PS.ENDCAP_ROUND, brushColor: Color.Empty, // Color doesn't really matter as we're using a null brush brushStyle: Gdi32.BS.NULL, // Regressed in https://github.com/dotnet/winforms/pull/3667 rop2: Gdi32.R2.COPYPEN)); }
public unsafe void Button_FlatStyle_WithText_Rectangle() { using Button button = new Button { Text = "Flat Style", FlatStyle = FlatStyle.Flat, }; using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); emf.Validate( state, Validate.SkipType(Gdi32.EMR.BITBLT), Validate.TextOut("Flat Style"), Validate.Rectangle( new Rectangle(0, 0, button.Width - 1, button.Height - 1), State.PenColor(Color.Black), State.PenStyle(Gdi32.PS.ENDCAP_ROUND), State.BrushStyle(Gdi32.BS.NULL), // Regressed in https://github.com/dotnet/winforms/pull/3667 State.Rop2(Gdi32.R2.COPYPEN))); }
public void TextBox_Disabled_PlaceholderText_RendersBackgroundCorrectly() { // Regression test for https://github.com/dotnet/winforms/issues/3706 using Form form = new Form(); using TextBox textBox = new TextBox { Size = new Size(80, 23), PlaceholderText = "abc", Enabled = false }; form.Controls.Add(textBox); // Force the handle creation Assert.NotEqual(IntPtr.Zero, form.Handle); Assert.NotEqual(IntPtr.Zero, textBox.Handle); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); textBox.TestAccessor().Dynamic.DrawPlaceholderText(emf.HDC); emf.Validate( state, Validate.TextOut( "abc", bounds: null, // Don't care about the bounds for this test State.BackgroundMode(Gdi32.BKMODE.TRANSPARENT))); }
/// <summary> /// Creates a metafile for the specified <see cref="Control"/>. /// </summary> internal static void CreateMetafile( this Control control, EmfScope emf, User32.PRF prf = User32.PRF.CHILDREN | User32.PRF.CLIENT) { User32.SendMessageW(control.Handle, User32.WM.PRINT, (IntPtr)emf.HDC, (IntPtr)prf); }
public void NumericUpDown_BasicRendering() { using var form = new Form(); using var upDown = new NumericUpDown(); form.Controls.Add(upDown); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Assert.Equal(new Rectangle(0, 0, 120, 23), upDown.Bounds); // The rendering here is the "fill" for the background around the child edit control, which // doesn't match up to the main control's bounds. upDown.PrintToMetafile(emf); emf.Validate( state, Validate.Rectangle( new Rectangle(1, 1, 98, 17), State.Pen(2, upDown.BackColor, Gdi32.PS.SOLID))); // Printing the main control doesn't get the redraw for the child controls on the first render, // directly hitting the up/down button subcontrol. using var emfButtons = new EmfScope(); state = new DeviceContextState(emfButtons); upDown.Controls[0].PrintToMetafile(emfButtons); // This is the "fill" line under the up/down arrows emfButtons.Validate( state, Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.LineTo( (0, 18), (16, 18), State.Pen(1, upDown.BackColor, Gdi32.PS.SOLID))); // Now check the disabled state upDown.Enabled = false; using var emfDisabled = new EmfScope(); state = new DeviceContextState(emfDisabled); upDown.PrintToMetafile(emfDisabled); emfDisabled.Validate( state, Validate.Rectangle( new Rectangle(0, 0, 99, 18), State.Pen(1, upDown.BackColor, Gdi32.PS.SOLID)), Validate.Rectangle( new Rectangle(1, 1, 97, 16), State.Pen(1, SystemColors.Control, Gdi32.PS.SOLID)), Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.SkipType(Gdi32.EMR.STRETCHDIBITS), Validate.LineTo( (0, 18), (16, 18), State.Pen(1, upDown.BackColor, Gdi32.PS.SOLID))); }
public unsafe void CaptureButtonOnForm() { using Form form = new Form(); using Button button = new Button(); form.Controls.Add(button); using var emf = new EmfScope(); form.PrintToMetafile(emf); var details = emf.RecordsToString(); }
public void PropertyGridView_Render_Labels_Values_Correctly() { Point pt = default(Point); using PropertyGrid propertyGrid = new() { SelectedObject = pt, Size = new(300, 200), Visible = true }; PropertyGridView propertyGridView = propertyGrid.TestAccessor().GridView; // For us to be able to render PropertyGridView and its values // PropertyGrid must be visible and have a valid handle. // To be Visible is must either be visible (we don't want this in tests) or // have no parent - so we can't add it to another control (such as a form). propertyGrid.CreateControl(); using var emf = new EmfScope(); DeviceContextState state = new(emf); propertyGridView.PrintToMetafile(emf); // Only care about text: labels and values emf.Validate( state, // Category: Misc Validate.SkipTo( Validate.TextOut("Misc", new(25, 4, 25, 14), stateValidators: State.FontFace(Control.DefaultFont.Name))), // Value for "X" Validate.SkipTo( Validate.TextOut(" ", new(145, 22, 5, 14))), // blank?? Validate.SkipTo( Validate.TextOut(pt.X.ToString(), new(145, 22, 5, 14), stateValidators: State.FontFace(Control.DefaultFont.Name))), // Label for "X" Validate.SkipTo( Validate.TextOut(nameof(Point.X), new(25, 23, 6, 14), stateValidators: State.FontFace(Control.DefaultFont.Name))), // Value for "Y" Validate.SkipTo( Validate.TextOut(" ", new(145, 41, 5, 14))), // blank?? Validate.SkipTo( Validate.TextOut(pt.Y.ToString(), new(145, 41, 5, 14), stateValidators: State.FontFace(Control.DefaultFont.Name))), // Label for "Y" Validate.SkipTo( Validate.TextOut(nameof(Point.Y), new(25, 42, 6, 14), stateValidators: State.FontFace(Control.DefaultFont.Name))), Validate.SkipAll()); } }
public unsafe void Button_VisualStyles_on_Default_WithText_LineDrawing() { if (!Application.RenderWithVisualStyles) { return; } using Button button = new Button { Text = "Hello" }; using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); /* * * [ENHMETAHEADER] Bounds: {0, 0, 74, 22 (LTRB)} Device Size: {Width=3840, Height=2160} Header Size: 108 * [EMRINTERSECTCLIPRECT] RECT: {0, 0, 75, 23 (LTRB)} * [EMRSETVIEWPORTORGEX] Point: {X=0,Y=0} * [EMRCREATEBRUSHINDIRECT] Index: 1 Style: SOLID Color: [R=240, G=240, B=240] (COLOR_MENU, COLOR_BTNFACE, COLOR_MENUBAR) * [EMRSELECTOBJECT] Index: 1 * [EMRBITBLT] Bounds: {0, 0, -1, -1 (LTRB)} Destination: {0, 0, 120, 0 (LTRB)} Rop: PATCOPY Source DC Color: [R=0, G=0, B=0] (COLOR_BACKGROUND, COLOR_MENUTEXT, COLOR_WINDOWTEXT, COLOR_CAPTIONTEXT, COLOR_BTNTEXT, COLOR_INACTIVECAPTIONTEXT, COLOR_INFOTEXT) * [EMRSELECTOBJECT] StockObject: WHITE_BRUSH * [EMRDELETEOBJECT] Index: 1 * [EMRCREATEBRUSHINDIRECT] Index: 1 Style: SOLID Color: [R=240, G=240, B=240] (COLOR_MENU, COLOR_BTNFACE, COLOR_MENUBAR) * [EMRSELECTOBJECT] Index: 1 * [EMRBITBLT] Bounds: {0, 0, -1, -1 (LTRB)} Destination: {0, 0, 120, 0 (LTRB)} Rop: PATCOPY Source DC Color: [R=0, G=0, B=0] (COLOR_BACKGROUND, COLOR_MENUTEXT, COLOR_WINDOWTEXT, COLOR_CAPTIONTEXT, COLOR_BTNTEXT, COLOR_INACTIVECAPTIONTEXT, COLOR_INFOTEXT) * [EMRSELECTOBJECT] StockObject: WHITE_BRUSH * [EMRDELETEOBJECT] Index: 1 * [EMRSETVIEWPORTORGEX] Point: {X=0,Y=0} * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 75, 23 (LTRB)} Rects: 1 Rect index 0: {0, 0, 75, 23 (LTRB)} * [EMRINTERSECTCLIPRECT] RECT: {0, 0, 75, 23 (LTRB)} * [EMRALPHABLEND] * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 75, 23 (LTRB)} Rects: 1 Rect index 0: {0, 0, 75, 23 (LTRB)} * [EMRSAVEDC] * [EMRSETICMMODE] Mode: ICM_OFF * [EMREXTSELECTCLIPRGN] Mode: Set Default * [EMRSETBKMODE] Mode: BKMODE_TRANSPARENT * [EMRSETTEXTCOLOR] Color: [R=0, G=0, B=0] (COLOR_BACKGROUND, COLOR_MENUTEXT, COLOR_WINDOWTEXT, COLOR_CAPTIONTEXT, COLOR_BTNTEXT, COLOR_INACTIVECAPTIONTEXT, COLOR_INFOTEXT) * [EMRSETTEXTALIGN] Mode: TA_BASELINE * [EMREXTCREATEFONTINDIRECTW] Index: 1 FaceName: 'Segoe UI' Height: -12 Weight: FW_NORMAL * [EMRSELECTOBJECT] Index: 1 * [EMREXTTEXTOUTW] Bounds: {24, 4, 51, 18 (LTRB)} Text: 'Hello' * [EMRSELECTOBJECT] StockObject: SYSTEM_FONT * [EMRRESTOREDC] Index: -1 * [EMRDELETEOBJECT] Index: 1 * [EMREOF] * */ }
public unsafe void TextRenderer_DrawText_DefaultBackground_RendersTransparent(Func <IDeviceContext, Action> func) { using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); func(new HdcDeviceContextAdapter(emf)).Invoke(); emf.Validate( state, Validate.TextOut( "Acrylic", Color.Blue, fontFace: SystemFonts.DefaultFont.Name)); }
public unsafe void TextRenderer_DrawText_DefaultBackground_RendersTransparent(Func <IDeviceContext, Action> func) { using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); func(new HdcDeviceContextAdapter(emf)).Invoke(); emf.Validate( state, Validate.TextOut( "Acrylic", bounds: null, // Don't care about the bounds for this test State.FontFace(SystemFonts.DefaultFont.Name), State.TextColor(Color.Blue))); }
public void ToolStrip_RendersBackgroundCorrectly() { using Form form = new Form(); using ToolStrip toolStrip = new ToolStrip { BackColor = Color.Blue, Size = new Size(200, 38) }; form.Controls.Add(toolStrip); // Force the handle creation _ = form.Handle; _ = toolStrip.Handle; form.PerformLayout(); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = toolStrip.Bounds; PaintEventArgs e = new PaintEventArgs(emf, bounds); toolStrip.TestAccessor().Dynamic.OnPaintBackground(e); Rectangle bitBltBounds = new Rectangle(bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); RECT[] expectedRects = new RECT[] { new RECT(0, 0, 1, 1), new RECT(bounds.Width - 3, 0, bounds.Width, 1), new RECT(bounds.Width - 1, 1, bounds.Width, 3), new RECT(0, bounds.Height - 2, 1, bounds.Height - 1), new RECT(bounds.Width - 1, bounds.Height - 2, bounds.Width, bounds.Height - 1), new RECT(0, bounds.Height - 1, 2, bounds.Height), new RECT(bounds.Width - 2, bounds.Height - 1, bounds.Width, bounds.Height) }; emf.Validate( state, Validate.BitBltValidator( bitBltBounds, State.BrushColor(Color.Blue)), Validate.BitBltValidator( bitBltBounds, State.BrushColor(form.BackColor), State.Clipping(expectedRects))); var details = emf.RecordsToString(); }
public unsafe void CaptureButton() { using Button button = new Button(); using var emf = new EmfScope(); button.PrintToMetafile(emf); var types = new List <Gdi32.EMR>(); var details = new List <string>(); emf.Enumerate((ref EmfRecord record) => { types.Add(record.Type); details.Add(record.ToString()); return(true); }); }
public void ControlPaint_DrawBorder_Solid_Rendering() { using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC); Rectangle bounds = new Rectangle(10, 10, 10, 10); ControlPaint.DrawBorder(graphics, bounds, Color.Blue, ButtonBorderStyle.Solid); emf.Validate( state, Validate.Rectangle( // We match the legacy GDI+ rendering, where the right and bottom are drawn inside the bounds new Rectangle(10, 10, 9, 9), State.Pen(1, Color.Blue, Gdi32.PS.SOLID))); }
public unsafe void Button_VisualStyles_off_Default_WithText_LineDrawing() { if (Application.RenderWithVisualStyles) { return; } using Button button = new Button { Text = "Hello" }; using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); emf.Validate( state, Validate.SkipType(Gdi32.EMR.BITBLT), Validate.TextOut("Hello"), Validate.LineTo( (bounds.Right - 1, 0), (0, 0), State.PenColor(SystemColors.ControlLightLight)), Validate.LineTo( (0, 0), (0, bounds.Bottom - 1), State.PenColor(SystemColors.ControlLightLight)), Validate.LineTo( (0, bounds.Bottom - 1), (bounds.Right - 1, bounds.Bottom - 1), State.PenColor(SystemColors.ControlDarkDark)), Validate.LineTo( (bounds.Right - 1, bounds.Bottom - 1), (bounds.Right - 1, -1), State.PenColor(SystemColors.ControlDarkDark)), Validate.LineTo( (bounds.Right - 2, 1), (1, 1), State.PenColor(SystemColors.Control)), Validate.LineTo( (1, 1), (1, bounds.Bottom - 2), State.PenColor(SystemColors.Control)), Validate.LineTo( (1, bounds.Bottom - 2), (bounds.Right - 2, bounds.Bottom - 2), State.PenColor(SystemColors.ControlDark)), Validate.LineTo( (bounds.Right - 2, bounds.Bottom - 2), (bounds.Right - 2, 0), State.PenColor(SystemColors.ControlDark))); }
public unsafe void CaptureButtonOnForm() { using Form form = new Form(); using Button button = new Button(); form.Controls.Add(button); using var emf = EmfScope.Create(); form.CreateMetafile(emf); var types = new List <Gdi32.EMR>(); var details = new List <string>(); emf.Enumerate((ref EmfRecord record) => { types.Add(record.Type); details.Add(record.ToString()); return(true); }); }
public unsafe void Button_VisualStyles_on_Default_LineDrawing() { if (!Application.RenderWithVisualStyles) { return; } using Button button = new Button(); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); /* * * [ENHMETAHEADER] Bounds: {0, 0, 74, 22 (LTRB)} Device Size: {Width=1024, Height=768} Header Size: 108 * [EMRINTERSECTCLIPRECT] RECT: {0, 0, 75, 23 (LTRB)} * [EMRSETVIEWPORTORGEX] Point: {X=0,Y=0} * [EMRCREATEBRUSHINDIRECT] Index: 1 Style: SOLID Color: [R=240, G=240, B=240] (COLOR_MENU, COLOR_BTNFACE, COLOR_MENUBAR) * [EMRSELECTOBJECT] Index: 1 * [EMRBITBLT] Bounds: {0, 0, -1, -1 (LTRB)} Destination: {0, 0, 120, 0 (LTRB)} Rop: PATCOPY Source DC Color: [R=0, G=0, B=0] (COLOR_BACKGROUND, COLOR_MENUTEXT, COLOR_WINDOWTEXT, COLOR_CAPTIONTEXT, COLOR_BTNTEXT, COLOR_INACTIVECAPTIONTEXT, COLOR_INFOTEXT) * [EMRSELECTOBJECT] StockObject: WHITE_BRUSH * [EMRDELETEOBJECT] Index: 1 * [EMRCREATEBRUSHINDIRECT] Index: 1 Style: SOLID Color: [R=240, G=240, B=240] (COLOR_MENU, COLOR_BTNFACE, COLOR_MENUBAR) * [EMRSELECTOBJECT] Index: 1 * [EMRBITBLT] Bounds: {0, 0, -1, -1 (LTRB)} Destination: {0, 0, 120, 0 (LTRB)} Rop: PATCOPY Source DC Color: [R=0, G=0, B=0] (COLOR_BACKGROUND, COLOR_MENUTEXT, COLOR_WINDOWTEXT, COLOR_CAPTIONTEXT, COLOR_BTNTEXT, COLOR_INACTIVECAPTIONTEXT, COLOR_INFOTEXT) * [EMRSELECTOBJECT] StockObject: WHITE_BRUSH * [EMRDELETEOBJECT] Index: 1 * [EMRSETVIEWPORTORGEX] Point: {X=0,Y=0} * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 75, 23 (LTRB)} Rects: 1 Rect index 0: {0, 0, 75, 23 (LTRB)} * [EMRINTERSECTCLIPRECT] RECT: {0, 0, 75, 23 (LTRB)} * [EMRALPHABLEND] * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 75, 23 (LTRB)} Rects: 1 Rect index 0: {0, 0, 75, 23 (LTRB)} * [EMREOF] * */ }
public unsafe void Button_Default_LineDrawing() { using Button button = new Button(); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Rectangle bounds = button.Bounds; button.PrintToMetafile(emf); emf.Validate( state, Validate.Repeat(Validate.SkipType(Gdi32.EMR.BITBLT), 2), Validate.LineTo((bounds.Right - 1, 0), (0, 0), SystemColors.ControlLightLight), Validate.LineTo((0, 0), (0, bounds.Bottom - 1), SystemColors.ControlLightLight), Validate.LineTo((0, bounds.Bottom - 1), (bounds.Right - 1, bounds.Bottom - 1), SystemColors.ControlDarkDark), Validate.LineTo((bounds.Right - 1, bounds.Bottom - 1), (bounds.Right - 1, -1), SystemColors.ControlDarkDark), Validate.LineTo((bounds.Right - 2, 1), (1, 1), SystemColors.Control), Validate.LineTo((1, 1), (1, bounds.Bottom - 2), SystemColors.Control), Validate.LineTo((1, bounds.Bottom - 2), (bounds.Right - 2, bounds.Bottom - 2), SystemColors.ControlDark), Validate.LineTo((bounds.Right - 2, bounds.Bottom - 2), (bounds.Right - 2, 0), SystemColors.ControlDark)); }
public void StatusStrip_RendersBorderCorrectly() { using Form form = new Form(); using StatusStrip statusStrip = new StatusStrip { BackColor = Color.Blue, SizingGrip = false, Renderer = new ToolStripProfessionalRenderer(new CustomColorTable()), Size = new Size(200, 38) }; form.Controls.Add(statusStrip); // Force the handle creation Assert.NotEqual(IntPtr.Zero, form.Handle); Assert.NotEqual(IntPtr.Zero, statusStrip.Handle); // Create an Enhance Metafile into which we will render the control using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); // Render the control statusStrip.PrintToMetafile(emf); Rectangle bounds = statusStrip.Bounds; Rectangle bitBltBounds = new Rectangle(bounds.X, 0, bounds.Width - 1, bounds.Height - 1); Rectangle polylineBounds = new Rectangle(bounds.X, 0, bounds.Width - 1, 15); // This is the default pen style GDI+ renders polylines with Gdi32.PS penStyle = Gdi32.PS.SOLID | Gdi32.PS.JOIN_ROUND | Gdi32.PS.COSMETIC | Gdi32.PS.ENDCAP_FLAT | Gdi32.PS.JOIN_MITER | Gdi32.PS.GEOMETRIC; emf.Validate( state, Validate.BitBltValidator(bitBltBounds, State.BrushColor(Color.Blue)), Validate.Polyline16(polylineBounds, null, State.Pen(16, Color.Green, penStyle)) ); var details = emf.RecordsToString(); }
public void DataGridView_DefaultCellStyles_Rendering() { #region DataGridView setup using Font formFont1 = new Font("Times New Roman", 12F, FontStyle.Regular); using Form form = new Form { Font = formFont1, Size = new Size(700, 200) }; using Font customCellStyleFont = new Font("Tahoma", 8.25F, FontStyle.Regular); using Font customColumnHeaderFont = new Font("Consolas", 14F, FontStyle.Italic); using Font customRowHeaderFont = new Font("Arial", 9F, FontStyle.Bold); var defaultCellStyle = new DataGridViewCellStyle { Font = customCellStyleFont, // We must supply a completely initialised instance, else we'd be receiving a copy // refer to DefaultCellStyle implementation Alignment = DataGridViewContentAlignment.MiddleLeft, BackColor = SystemColors.Info, ForeColor = Color.Maroon, SelectionBackColor = SystemColors.Highlight, SelectionForeColor = SystemColors.HighlightText, WrapMode = DataGridViewTriState.False }; using DataGridView dataGridView = new DataGridView { DefaultCellStyle = defaultCellStyle, ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle { Font = customColumnHeaderFont }, RowHeadersDefaultCellStyle = new DataGridViewCellStyle { Font = customRowHeaderFont }, Dock = DockStyle.Fill, ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize, }; var column1 = new DataGridViewTextBoxColumn { HeaderText = "Style" }; var column2 = new DataGridViewTextBoxColumn { HeaderText = "Font" }; dataGridView.Columns.AddRange(new[] { column1, column2, }); dataGridView.Rows.Add(nameof(DataGridView.DefaultCellStyle), customCellStyleFont.ToString()); dataGridView.Rows.Add(nameof(DataGridView.ColumnHeadersDefaultCellStyle), customColumnHeaderFont.ToString()); dataGridView.Rows.Add(nameof(DataGridView.RowHeadersDefaultCellStyle), customRowHeaderFont.ToString()); for (int i = 0; i < dataGridView.Rows.Count; i++) { dataGridView.Rows[i].HeaderCell.Value = $"Row {i + 1}"; } dataGridView.RowHeadersWidth = 100; Assert.Same(customCellStyleFont, dataGridView.DefaultCellStyle.Font); Assert.Same(customColumnHeaderFont, dataGridView.ColumnHeadersDefaultCellStyle.Font); Assert.Same(customRowHeaderFont, dataGridView.RowHeadersDefaultCellStyle.Font); // Add the datagridview to the form, this will trigger Font change via OnFontChanged form.Controls.Add(dataGridView); #endregion using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Assert.NotEqual(IntPtr.Zero, dataGridView.Handle); dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); dataGridView.PrintToMetafile(emf); // We only care about font styles, nothing else emf.Validate( state, // Column headers Validate.SkipTo( Validate.TextOut(column1.HeaderText, stateValidators: State.FontFace(customColumnHeaderFont.Name))), Validate.SkipTo( Validate.TextOut(column2.HeaderText, stateValidators: State.FontFace(customColumnHeaderFont.Name))), // Row1 Validate.SkipTo( Validate.TextOut("Row 1", stateValidators: State.FontFace(customRowHeaderFont.Name))), Validate.SkipTo( Validate.TextOut(nameof(DataGridView.DefaultCellStyle), stateValidators: State.FontFace(customCellStyleFont.Name))), Validate.SkipTo( Validate.TextOut(customCellStyleFont.ToString(), stateValidators: State.FontFace(customCellStyleFont.Name))), // Row2 Validate.SkipTo( Validate.TextOut("Row 2", stateValidators: State.FontFace(customRowHeaderFont.Name))), Validate.SkipTo( Validate.TextOut(nameof(DataGridView.ColumnHeadersDefaultCellStyle), stateValidators: State.FontFace(customCellStyleFont.Name))), Validate.SkipTo( Validate.TextOut(customColumnHeaderFont.ToString(), stateValidators: State.FontFace(customCellStyleFont.Name))), // Row3 Validate.SkipTo( Validate.TextOut("Row 3", stateValidators: State.FontFace(customRowHeaderFont.Name))), Validate.SkipTo( Validate.TextOut(nameof(DataGridView.RowHeadersDefaultCellStyle), stateValidators: State.FontFace(customCellStyleFont.Name))), Validate.SkipTo( Validate.TextOut(customRowHeaderFont.ToString(), stateValidators: State.FontFace(customCellStyleFont.Name))), Validate.SkipAll()); }
public void DataGridView_GridColor_Rendering() { using Form form = new Form(); // Only want to render one cell to validate using var dataGrid = new DataGridView { GridColor = Color.Blue, ColumnCount = 1, RowCount = 1, ColumnHeadersVisible = false, RowHeadersVisible = false }; form.Controls.Add(dataGrid); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); dataGrid.PrintToMetafile(emf); Assert.Equal(new Rectangle(0, 0, 240, 150), dataGrid.Bounds); Assert.Equal(new Size(100, 25), dataGrid[0, 0].Size); Rectangle bounds = dataGrid.Bounds; // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied. // For test readability we'll transform the points from our coordinates to the logical coordinates. Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f); Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f); // This is the default pen style GDI+ renders with Gdi32.PS penStyle = Gdi32.PS.SOLID | Gdi32.PS.JOIN_ROUND | Gdi32.PS.COSMETIC | Gdi32.PS.ENDCAP_FLAT | Gdi32.PS.JOIN_MITER | Gdi32.PS.GEOMETRIC; // Don't really care about the bounds, just the actual shapes/lines emf.Validate( state, // The datagrid background Validate.Polygon16( bounds: null, PointArray(times16, 1, 1, 1, 149, 239, 149, 239, 1, 1, 1), State.Pen(1, Color.Empty, Gdi32.PS.NULL), State.Brush(SystemColors.ButtonShadow, Gdi32.BS.SOLID), State.Transform(oneSixteenth)), // Left cell border Validate.Polyline16( bounds: null, PointArray(times16, 1, 1, 1, 26), State.Pen(16, Color.Blue, penStyle), State.Transform(oneSixteenth)), // Right cell border Validate.Polyline16( bounds: null, PointArray(times16, 101, 1, 101, 26), State.Pen(16, Color.Blue, penStyle), State.Transform(oneSixteenth)), // Top cell border Validate.Polyline16( bounds: null, PointArray(times16, 1, 1, 101, 1), State.Pen(16, Color.Blue, penStyle), State.Transform(oneSixteenth)), // Bottom cell border Validate.Polyline16( bounds: null, PointArray(times16, 1, 26, 101, 26), State.Pen(16, Color.Blue, penStyle), State.Transform(oneSixteenth)), // Cell background Validate.Polygon16( bounds: null, PointArray(times16, 2, 2, 2, 26, 101, 26, 101, 2, 2, 2), State.Pen(1, Color.Empty, Gdi32.PS.NULL), State.Brush(SystemColors.ButtonHighlight, Gdi32.BS.SOLID), State.Transform(oneSixteenth)), // Datagrid border Validate.Polygon16( bounds: null, PointArray(times16, 0, 0, 239, 0, 239, 149, 0, 149), State.Pen(16, SystemColors.Desktop, penStyle), State.Brush(Color.Empty, Gdi32.BS.NULL), State.Transform(oneSixteenth))); }
public void NumericUpDown_VisualStyles_on_BasicRendering() { if (!Application.RenderWithVisualStyles) { return; } using var form = new Form(); using var upDown = new NumericUpDown(); form.Controls.Add(upDown); using var emf = new EmfScope(); DeviceContextState state = new DeviceContextState(emf); Assert.Equal(new Rectangle(0, 0, 120, 23), upDown.Bounds); // The rendering here is the "fill" for the background around the child edit control, which // doesn't match up to the main control's bounds. upDown.PrintToMetafile(emf); /* * * [ENHMETAHEADER] Bounds: {0, 0, 119, 22 (LTRB)} Device Size: {Width=3840, Height=2160} Header Size: 108 * [EMRSETBKCOLOR] Color: [R=171, G=173, B=179] * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, 0, 22 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, 0, 0 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 22, 0, 22 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRSETBKCOLOR] Color: [R=171, G=173, B=179] * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, 0, 0 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {119, 0, 119, 0 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, 119, 0 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRSETBKCOLOR] Color: [R=171, G=173, B=179] * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {119, 0, 119, 22 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {119, 0, 119, 0 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {119, 22, 119, 22 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRSETBKCOLOR] Color: [R=171, G=173, B=179] * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 22, 0, 22 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {119, 22, 119, 22 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 22, 119, 22 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMREXTTEXTOUTW] Bounds: {0, 0, -1, -1 (LTRB)} Text: '' * [EMRSETBKCOLOR] Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRCREATEPEN] Index: 1 Style: ENDCAP_ROUND Width: {X=1,Y=0} Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRSELECTOBJECT] Index: 1 * [EMRSETROP2] Mode: R2_COPYPEN * [EMRSELECTOBJECT] StockObject: NULL_BRUSH * [EMRRECTANGLE] RECT: {1, 1, 102, 21 (LTRB)} * [EMRSELECTOBJECT] StockObject: WHITE_BRUSH * [EMRSELECTOBJECT] StockObject: BLACK_PEN * [EMRDELETEOBJECT] Index: 1 * [EMREOF] * */ // Printing the main control doesn't get the redraw for the child controls on the first render, // directly hitting the up/down button subcontrol. using var emfButtons = new EmfScope(); state = new DeviceContextState(emfButtons); upDown.Controls[0].PrintToMetafile(emfButtons); /* * * [ENHMETAHEADER] Bounds: {0, 0, 16, 20 (LTRB)} Device Size: {Width=3840, Height=2160} Header Size: 108 * [EMRINTERSECTCLIPRECT] RECT: {0, 0, 16, 10 (LTRB)} * [EMRBITBLT] Bounds: {0, 0, 15, 9 (LTRB)} Destination: {0, 0, 16, 10 (LTRB)} Rop: SRCCOPY Source DC Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 16, 21 (LTRB)} Rects: 1 Rect index 0: {0, 0, 16, 21 (LTRB)} * [EMRINTERSECTCLIPRECT] RECT: {4, 2, 11, 8 (LTRB)} * [EMRALPHABLEND] * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 16, 21 (LTRB)} Rects: 1 Rect index 0: {0, 0, 16, 21 (LTRB)} * [EMRINTERSECTCLIPRECT] RECT: {0, 10, 16, 20 (LTRB)} * [EMRBITBLT] Bounds: {0, 10, 15, 19 (LTRB)} Destination: {0, 10, 16, 20 (LTRB)} Rop: SRCCOPY Source DC Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 16, 21 (LTRB)} Rects: 1 Rect index 0: {0, 0, 16, 21 (LTRB)} * [EMRINTERSECTCLIPRECT] RECT: {4, 12, 11, 18 (LTRB)} * [EMRALPHABLEND] * [EMREXTSELECTCLIPRGN] Mode: COPY Bounds: {0, 0, 16, 21 (LTRB)} Rects: 1 Rect index 0: {0, 0, 16, 21 (LTRB)} * [EMRSETROP2] Mode: R2_COPYPEN * [EMRSETBKMODE] Mode: BKMODE_TRANSPARENT * [EMRCREATEPEN] Index: 1 Style: ENDCAP_ROUND Width: {X=1,Y=0} Color: [R=255, G=255, B=255] (COLOR_WINDOW, COLOR_HIGHLIGHTTEXT, COLOR_BTNHIGHLIGHT) * [EMRSELECTOBJECT] Index: 1 * [EMRMOVETOEX] Point: {X=0,Y=20} * [EMRLINETO] Point: {X=16,Y=20} * [EMRMOVETOEX] Point: {X=0,Y=0} * [EMRSELECTOBJECT] StockObject: BLACK_PEN * [EMRSETBKMODE] Mode: BKMODE_OPAQUE * [EMRDELETEOBJECT] Index: 1 * [EMREOF] * */ }