| File: System\Windows\Forms\Controls\ToolStrips\ToolStripItem.ToolStripItemInternalLayout.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using System.Windows.Forms.ButtonInternal; namespace System.Windows.Forms; public partial class ToolStripItem { /// <summary> /// This class helps determine where the image and text should be drawn. /// </summary> internal partial class ToolStripItemInternalLayout { private ToolStripItemLayoutOptions? _currentLayoutOptions; private readonly ToolStripItem _ownerItem; private ButtonBaseAdapter.LayoutData? _layoutData; private const int BorderWidth = 2; private static readonly Size s_invalidSize = new(int.MinValue, int.MinValue); private Size _lastPreferredSize = s_invalidSize; private ToolStripLayoutData? _parentLayoutData; public ToolStripItemInternalLayout(ToolStripItem ownerItem) { _ownerItem = ownerItem.OrThrowIfNull(); } protected virtual ToolStripItem Owner => _ownerItem; public virtual Rectangle ImageRectangle { get { ButtonBaseAdapter.LayoutData layoutData = LayoutData; Rectangle imageRect = layoutData.ImageBounds; imageRect.Intersect(layoutData.Field); return imageRect; } } internal ButtonBaseAdapter.LayoutData LayoutData { get { EnsureLayout(); return _layoutData; } } public Size PreferredImageSize => Owner.PreferredImageSize; protected virtual ToolStrip? ParentInternal => _ownerItem?.ParentInternal; public virtual Rectangle TextRectangle { get { ButtonBaseAdapter.LayoutData layoutData = LayoutData; Rectangle textRect = layoutData.TextBounds; textRect.Intersect(layoutData.Field); return textRect; } } public virtual Rectangle ContentRectangle => LayoutData.Field; public virtual TextFormatFlags TextFormat { get { if (_currentLayoutOptions is not null) { return _currentLayoutOptions.GdiTextFormatFlags; } return CommonLayoutOptions().GdiTextFormatFlags; } } internal static TextFormatFlags ContentAlignmentToTextFormat(ContentAlignment alignment, bool rightToLeft) { TextFormatFlags textFormat = TextFormatFlags.Default; if (rightToLeft) { // We specifically do not want to turn on TextFormatFlags.Right. textFormat |= TextFormatFlags.RightToLeft; } // Calculate Text Positioning textFormat |= ControlPaint.ConvertAlignmentToTextFormat(alignment); return textFormat; } protected virtual ToolStripItemLayoutOptions CommonLayoutOptions() { ToolStripItemLayoutOptions layoutOptions = new(); Rectangle bounds = new(Point.Empty, _ownerItem.Size); layoutOptions.Client = bounds; layoutOptions.GrowBorderBy1PxWhenDefault = false; layoutOptions.BorderSize = BorderWidth; layoutOptions.PaddingSize = 0; layoutOptions.MaxFocus = true; layoutOptions.FocusOddEvenFixup = false; layoutOptions.Font = _ownerItem.Font; layoutOptions.Text = ((Owner.DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text) ? Owner.Text : string.Empty; layoutOptions.ImageSize = PreferredImageSize; layoutOptions.CheckSize = 0; layoutOptions.CheckPaddingSize = 0; layoutOptions.CheckAlign = ContentAlignment.TopLeft; layoutOptions.ImageAlign = Owner.ImageAlign; layoutOptions.TextAlign = Owner.TextAlign; layoutOptions.HintTextUp = false; layoutOptions.ShadowedText = !_ownerItem.Enabled; layoutOptions.LayoutRTL = Owner.RightToLeft == RightToLeft.Yes; layoutOptions.TextImageRelation = Owner.TextImageRelation; // Set textImageInset to 0 since we don't draw 3D border for ToolStripItems. layoutOptions.TextImageInset = 0; layoutOptions.DotNetOneButtonCompat = false; // Support RTL layoutOptions.GdiTextFormatFlags = ContentAlignmentToTextFormat(Owner.TextAlign, Owner.RightToLeft == RightToLeft.Yes); // Hide underlined &File unless ALT is pressed layoutOptions.GdiTextFormatFlags = Owner.ShowKeyboardCues ? layoutOptions.GdiTextFormatFlags : layoutOptions.GdiTextFormatFlags | TextFormatFlags.HidePrefix; return layoutOptions; } [MemberNotNull(nameof(_layoutData))] private void EnsureLayout() { if (_layoutData is null || _parentLayoutData is null || !_parentLayoutData.IsCurrent(ParentInternal)) { PerformLayout(); } } [MemberNotNull(nameof(_currentLayoutOptions))] private ButtonBaseAdapter.LayoutData GetLayoutData() { _currentLayoutOptions = CommonLayoutOptions(); if (Owner.TextDirection != ToolStripTextDirection.Horizontal) { _currentLayoutOptions.VerticalText = true; } ButtonBaseAdapter.LayoutData data = _currentLayoutOptions.Layout(); return data; } public virtual Size GetPreferredSize(Size constrainingSize) { EnsureLayout(); // we would prefer not to be larger than the ToolStrip itself. // so we'll ask the ButtonAdapter layout guy what it thinks // its preferred size should be - and we'll tell it to be no // bigger than the ToolStrip itself. Note this is "Parent" not // "Owner" because we care in this instance what we're currently displayed on. if (_ownerItem is not null) { // _currentLayoutOptions will always be initialised if EnsureLayout() is called, // because it will get called at least once (for _layoutData is null) and, in turn, // it'll invoke PerformLayout() that'll unconditionally invoke GetLayoutData(). _lastPreferredSize = _currentLayoutOptions!.GetPreferredSizeCore(constrainingSize); return _lastPreferredSize; } return Size.Empty; } [MemberNotNull(nameof(_layoutData))] [MemberNotNull(nameof(_currentLayoutOptions))] internal void PerformLayout() { _layoutData = GetLayoutData(); ToolStrip? parent = ParentInternal; if (parent is not null) { _parentLayoutData = new ToolStripLayoutData(parent); } else { _parentLayoutData = null; } } } }