/// <summary>
        ///  Returns the Size in logical units of the given text using the given Font, and according to the formatting flags.
        ///  The proposed size is used to create a bounding rectangle as follows:
        ///  - If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by
        ///  the lpRect parameter and extends the base of the rectangle to bound the last line of text.
        ///  - If the largest word is wider than the rectangle, the width is expanded.
        ///  - If the text is less than the width of the rectangle, the width is reduced.
        ///  - If there is only one line of text, DrawText modifies the right side of the rectangle so that
        ///  it bounds the last character in the line.
        ///  If the font is null, the hdc's current font will be used.
        ///
        ///  Note for vertical fonts (if ever supported): DrawTextEx uses GetTextExtentPoint32 for measuring the text and this
        ///  function has the following limitation (from MSDN):
        ///  - This function assumes that the text is horizontal, that is, that the escapement is always 0. This is true for both
        ///  the horizontal and vertical measurements of the text.  The application must convert it explicitly.
        /// </summary>
        public static Size MeasureText(
            this Gdi32.HDC hdc,
            ReadOnlySpan <char> text,
            FontCache.Scope font,
            Size proposedSize,
            TextFormatFlags flags)
        {
            (User32.DT dt, TextPaddingOptions padding) = SplitTextFormatFlags(flags);

            if (text.IsEmpty)
            {
                return(Size.Empty);
            }

            // DrawText returns a rectangle useful for aligning, but not guaranteed to encompass all
            // pixels (its not a FitBlackBox, if the text is italicized, it will overhang on the right.)
            // So we need to account for this.

            User32.DRAWTEXTPARAMS dtparams = GetTextMargins(font, padding);

            // If Width / Height are < 0, we need to make them larger or DrawText will return
            // an unbounded measurement when we actually trying to make it very narrow.
            int minWidth = 1 + dtparams.iLeftMargin + dtparams.iRightMargin;

            if (proposedSize.Width <= minWidth)
            {
                proposedSize.Width = minWidth;
            }

            if (proposedSize.Height <= 0)
            {
                proposedSize.Height = 1;
            }

            var rect = new RECT(0, 0, proposedSize.Width, proposedSize.Height);

            using var fontSelection = new Gdi32.SelectObjectScope(hdc, font.Object);

            // If proposedSize.Height >= MaxSize.Height it is assumed bounds needed.  If flags contain SINGLELINE and
            // VCENTER or BOTTOM options, DrawTextEx does not bind the rectangle to the actual text height since
            // it assumes the text is to be vertically aligned; we need to clear the VCENTER and BOTTOM flags to
            // get the actual text bounds.
            if (proposedSize.Height >= TextRenderer.MaxSize.Height && (dt & User32.DT.SINGLELINE) != 0)
            {
                // Clear vertical-alignment flags.
                dt &= ~(User32.DT.BOTTOM | User32.DT.VCENTER);
            }

            if (proposedSize.Width == TextRenderer.MaxSize.Width)
            {
                // PERF: No constraining width means no word break.
                // in this case, we dont care about word wrapping - there should be enough room to fit it all
                dt &= ~(User32.DT.WORDBREAK);
            }

            dt |= User32.DT.CALCRECT;
            User32.DrawTextExW(hdc, text, ref rect, dt, ref dtparams);

            return(rect.Size);
        }
Esempio n. 2
0
        private Gdi32.HBITMAP GetCompatibleBitmap(Bitmap bm)
        {
            using var screenDC = User32.GetDcScope.ScreenDC;

            // GDI+ returns a DIBSECTION based HBITMAP. The clipboard deals well
            // only with bitmaps created using CreateCompatibleBitmap(). So, we
            // convert the DIBSECTION into a compatible bitmap.
            Gdi32.HBITMAP hBitmap = bm.GetHBITMAP();

            // Create a compatible DC to render the source bitmap.
            using var sourceDC = new Gdi32.CreateDcScope(screenDC);
            using var sourceBitmapSelection = new Gdi32.SelectObjectScope(sourceDC, hBitmap);

            // Create a compatible DC and a new compatible bitmap.
            using var destinationDC = new Gdi32.CreateDcScope(screenDC);
            Gdi32.HBITMAP bitmap = Gdi32.CreateCompatibleBitmap(screenDC, bm.Size.Width, bm.Size.Height);

            // Select the new bitmap into a compatible DC and render the blt the original bitmap.
            using var destinationBitmapSelection = new Gdi32.SelectObjectScope(destinationDC, bitmap);
            Gdi32.BitBlt(
                destinationDC,
                0,
                0,
                bm.Size.Width,
                bm.Size.Height,
                sourceDC,
                0,
                0,
                Gdi32.ROP.SRCCOPY);

            return(bitmap);
        }
        internal static void DrawRectangle(this Gdi32.HDC hdc, Rectangle rectangle, Gdi32.HPEN hpen)
        {
            using var penScope   = new Gdi32.SelectObjectScope(hdc, hpen);
            using var ropScope   = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN);
            using var brushScope = new Gdi32.SelectObjectScope(hdc, Gdi32.GetStockObject(Gdi32.StockObject.HOLLOW_BRUSH));

            Gdi32.Rectangle(hdc, rectangle.X, rectangle.Y, rectangle.Right, rectangle.Bottom);
        }
        internal unsafe static void DrawLine(this Gdi32.HDC hdc, Gdi32.HPEN pen, int x1, int y1, int x2, int y2)
        {
            using var ropScope  = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN);
            using var bkScope   = new Gdi32.SetBkModeScope(hdc, Gdi32.BKMODE.TRANSPARENT);
            using var selection = new Gdi32.SelectObjectScope(hdc, pen);

            Point oldPoint = new Point();

            Gdi32.MoveToEx(hdc, x1, y1, &oldPoint);
            Gdi32.LineTo(hdc, x2, y2);
            Gdi32.MoveToEx(hdc, oldPoint.X, oldPoint.Y, &oldPoint);
        }
Esempio n. 5
0
        /// <summary>
        ///  Draws the text in the given bounds, using the given Font, foreColor and backColor, and according to the specified
        ///  TextFormatFlags flags.
        ///
        ///  If font is null, the font currently selected in the hdc is used.
        ///
        ///  If foreColor and/or backColor are Color.Empty, the hdc current text and/or background color are used.
        /// </summary>
        public static void DrawText(
            this Gdi32.HDC hdc,
            ReadOnlySpan <char> text,
            FontCache.Scope font,
            Rectangle bounds,
            Color foreColor,
            User32.DT flags,
            Color backColor            = default,
            TextPaddingOptions padding = default)
        {
            if (text.IsEmpty || foreColor == Color.Transparent)
            {
                return;
            }

            ValidateFlags(flags);

            // DrawText requires default text alignment.
            using var alignment = new Gdi32.SetTextAlignmentScope(hdc, default);

            // Color empty means use the one currently selected in the dc.
            using var textColor = foreColor.IsEmpty ? default : new Gdi32.SetTextColorScope(hdc, foreColor);
                                  using var fontSelection = new Gdi32.SelectObjectScope(hdc, (Gdi32.HFONT)font);

                                  Gdi32.BKMODE newBackGroundMode = (backColor.IsEmpty || backColor == Color.Transparent) ?
                                                                   Gdi32.BKMODE.TRANSPARENT :
                                                                   Gdi32.BKMODE.OPAQUE;

                                  using var backgroundMode  = new Gdi32.SetBkModeScope(hdc, newBackGroundMode);
                                  using var backgroundColor = newBackGroundMode != Gdi32.BKMODE.TRANSPARENT
                ? new Gdi32.SetBackgroundColorScope(hdc, backColor)
                : default;

                                  User32.DRAWTEXTPARAMS dtparams = GetTextMargins(font, padding);

                                  bounds = AdjustForVerticalAlignment(hdc, text, bounds, flags, ref dtparams);

                                  // Adjust unbounded rect to avoid overflow since Rectangle ctr does not do param validation.
                                  if (bounds.Width == TextRenderer.MaxSize.Width)
                                  {
                                      bounds.Width -= bounds.X;
                                  }

                                  if (bounds.Height == TextRenderer.MaxSize.Height)
                                  {
                                      bounds.Height -= bounds.Y;
                                  }

                                  RECT rect = bounds;

                                  User32.DrawTextExW(hdc, text, ref rect, flags, ref dtparams);
        }
        internal static void DrawRectangle(
            this Gdi32.HDC hdc,
            int left,
            int top,
            int right,
            int bottom,
            Gdi32.HPEN hpen)
        {
            using var penScope   = new Gdi32.SelectObjectScope(hdc, hpen);
            using var ropScope   = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN);
            using var brushScope = new Gdi32.SelectObjectScope(hdc, Gdi32.GetStockObject(Gdi32.StockObject.NULL_BRUSH));

            Gdi32.Rectangle(hdc, left, top, right, bottom);
        }
        /// <summary>
        ///  Returns the Size of the given text using the specified font if not null, otherwise the font currently
        ///  set in the dc is used.
        ///  This method is used to get the size in points of a line of text; it uses GetTextExtentPoint32 function
        ///  which computes the width and height of the text ignoring TAB\CR\LF characters.
        ///  A text extent is the distance between the beginning of the space and a character that will fit in the space.
        /// </summary>
        public static Size GetTextExtent(this Gdi32.HDC hdc, string?text, Gdi32.HFONT hfont)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(Size.Empty);
            }

            Size size = new Size();

            using var selectFont = new Gdi32.SelectObjectScope(hdc, hfont);

            Gdi32.GetTextExtentPoint32W(hdc, text, text.Length, ref size);

            return(new Size(size.Width, size.Height));
        }
        /// <summary>
        ///  Draws lines with the <paramref name="hpen"/> using points defined in <paramref name="lines"/>.
        /// </summary>
        /// <param name="lines">
        ///  MUST be a mulitple of 4. Each group of 4 represents x1, y1, x2, y2.
        /// </param>
        internal unsafe static void DrawLines(this Gdi32.HDC hdc, Gdi32.HPEN hpen, ReadOnlySpan <int> lines)
        {
            Debug.Assert((lines.Length % 4) == 0);

            using var ropScope  = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN);
            using var bkScope   = new Gdi32.SetBkModeScope(hdc, Gdi32.BKMODE.TRANSPARENT);
            using var selection = new Gdi32.SelectObjectScope(hdc, hpen);

            Point oldPoint = new Point();

            for (int i = 0; i < lines.Length; i += 4)
            {
                Gdi32.MoveToEx(hdc, lines[i], lines[i + 1], &oldPoint);
                Gdi32.LineTo(hdc, lines[i + 2], lines[i + 3]);
                Gdi32.MoveToEx(hdc, oldPoint.X, oldPoint.Y, null);
            }
        }
        private void DrawReversibleFrame(IntPtr handle, Rectangle rectangle, Color backColor)
        {
            //Bug # 71547 <subhag> to make drag rect visible if any the dimensions of the control are 0
            if (rectangle.Width == 0)
            {
                rectangle.Width = 5;
            }
            if (rectangle.Height == 0)
            {
                rectangle.Height = 5;
            }

            // Copy of ControlPaint.DrawReversibleFrame, see VSWhidbey 581670
            // If ControlPaint ever gets overrloaded, we should replace the code below by calling it:
            // ControlPaint.DrawReversibleFrame(handle, rectangle, backColor, FrameStyle.Thick);

            // ------ Duplicate code----------------------------------------------------------
            Gdi32.R2 rop2;
            Color    graphicsColor;

            if (backColor.GetBrightness() < .5)
            {
                rop2          = Gdi32.R2.NOTXORPEN;
                graphicsColor = Color.White;
            }
            else
            {
                rop2          = Gdi32.R2.XORPEN;
                graphicsColor = Color.Black;
            }

            using var dc  = new User32.GetDcScope(handle);
            using var pen = new Gdi32.ObjectScope(Gdi32.CreatePen(Gdi32.PS.SOLID, 2, ColorTranslator.ToWin32(backColor)));

            using var rop2Scope      = new Gdi32.SetRop2Scope(dc, rop2);
            using var brushSelection = new Gdi32.SelectObjectScope(dc, Gdi32.GetStockObject(Gdi32.StockObject.NULL_BRUSH));
            using var penSelection   = new Gdi32.SelectObjectScope(dc, pen);

            Gdi32.SetBkColor(dc, ColorTranslator.ToWin32(graphicsColor));
            Gdi32.Rectangle(dc, rectangle.X, rectangle.Y, rectangle.Right, rectangle.Bottom);
            // ------ Duplicate code----------------------------------------------------------
        }
Esempio n. 10
0
        public void Font_AdjustForVerticalAlignment(string family, float size, Rectangle bounds, uint dt, Rectangle expected)
        {
            using Font font = new Font(family, size);
            if (font.Name != family)
            {
                // Not installed on this machine
                return;
            }

            using var hfont         = GdiCache.GetHFONT(font, Gdi32.QUALITY.CLEARTYPE);
            using var screen        = GdiCache.GetScreenHdc();
            using var fontSelection = new Gdi32.SelectObjectScope(screen, hfont.Object);

            User32.DRAWTEXTPARAMS param  = default;
            Rectangle             result = screen.HDC.AdjustForVerticalAlignment(
                "Windows Foundation Classes",
                bounds,
                (User32.DT)dt,
                ref param);

            Assert.Equal(expected, result);
        }
            private void ActivateDropDown()
            {
                if (_editor != null)
                {
                    try
                    {
                        object newValue = _editor.EditValue(TypeDescriptorContext, this, Value);
                        SetValue(newValue);
                    }
                    catch (Exception ex)
                    {
                        ActionPanel.ShowError(string.Format(SR.DesignerActionPanel_ErrorActivatingDropDown, ex.Message));
                    }
                }
                else
                {
                    ListBox listBox = new ListBox
                    {
                        BorderStyle    = BorderStyle.None,
                        IntegralHeight = false,
                        Font           = ActionPanel.Font
                    };
                    listBox.SelectedIndexChanged += new EventHandler(OnListBoxSelectedIndexChanged);
                    listBox.KeyDown += new KeyEventHandler(OnListBoxKeyDown);

                    TypeConverter.StandardValuesCollection standardValues = GetStandardValues();
                    if (standardValues != null)
                    {
                        foreach (object o in standardValues)
                        {
                            string newItem = PropertyDescriptor.Converter.ConvertToString(TypeDescriptorContext, CultureInfo.CurrentCulture, o);
                            listBox.Items.Add(newItem);

                            if ((o != null) && o.Equals(Value))
                            {
                                listBox.SelectedItem = newItem;
                            }
                        }
                    }

                    // All measurement code borrowed from WinForms PropertyGridView.cs
                    int maxWidth = 0;

                    // The listbox draws with GDI, not GDI+.  So, we use a normal DC here.
                    using (var hdc = new User32.GetDcScope(listBox.Handle))
                    {
                        using var hFont         = new Gdi32.ObjectScope(listBox.Font.ToHFONT());
                        using var fontSelection = new Gdi32.SelectObjectScope(hdc, hFont);

                        var tm = new Gdi32.TEXTMETRICW();

                        if (listBox.Items.Count > 0)
                        {
                            foreach (string s in listBox.Items)
                            {
                                var textSize = new Size();
                                Gdi32.GetTextExtentPoint32W(hdc, s, s.Length, ref textSize);
                                maxWidth = Math.Max(textSize.Width, maxWidth);
                            }
                        }

                        Gdi32.GetTextMetricsW(hdc, ref tm);

                        // border + padding + scrollbar
                        maxWidth += 2 + tm.tmMaxCharWidth + SystemInformation.VerticalScrollBarWidth;

                        listBox.Height       = Math.Max(tm.tmHeight + 2, Math.Min(ListBoxMaximumHeight, listBox.PreferredHeight));
                        listBox.Width        = Math.Max(maxWidth, EditRegionSize.Width);
                        _ignoreDropDownValue = false;
                    }

                    try
                    {
                        ShowDropDown(listBox, SystemColors.ControlDark);
                    }
                    finally
                    {
                        listBox.SelectedIndexChanged -= new EventHandler(OnListBoxSelectedIndexChanged);
                        listBox.KeyDown -= new KeyEventHandler(OnListBoxKeyDown);
                    }

                    if (!_ignoreDropDownValue)
                    {
                        if (listBox.SelectedItem != null)
                        {
                            SetValue(listBox.SelectedItem);
                        }
                    }
                }
            }