Environment
- TMS VCL UI Pack 13.6.8.2 (unchanged since at least 13.6.5.1)
- RAD Studio / Delphi 13.1, VCL, Win32 and Win64
- Windows 11 (build 26200)
- Application manifest: Per-Monitor V2
- Two monitors: primary 1280x800 at 125% (120 dpi), secondary 1920x1080 at 100% (96 dpi)
Line numbers refer to AdvToolBar.pas of 13.6.8.2. Method names are exact.
Summary
When a TAdvMainMenu is hosted in a TAdvToolBar (ToolBar.Menu := AdvMainMenu), the top level menu items are painted by AdvToolBar.pas as toolbar buttons.
TAdvCustomToolBarButton.AdjustSize, which measures the caption to decide the button width, applies the DPI scale factor to the font unconditionally. But TAdvCustomToolBarButton.DrawGlyphAndCaption, which paints that same caption, applies it under a condition that excludes menu buttons.
So for a menu button the width is computed for a font that is never used to draw it. The button ends up wider than its text by exactly the scale factor, and since that factor is 1.0 at 96 dpi, the apparent spacing between the menu items changes from one monitor to another.
Steps to reproduce
- Two monitors with different scaling (we use 125% and 100%).
- A form with a
TAdvToolBar, aTAdvMainMenuwith several top level items (File, Edit, View...), and aTAdvToolBarOfficeStylerwhoseAdvMenuStyleris assigned. - Assign the menu to the toolbar:
ToolBar.Menu := AdvMainMenu. - Compare the horizontal spacing between the menu captions on the 120 dpi monitor and on the 96 dpi one.
Expected
The spacing between menu items looks the same on both monitors. It should depend only on the margins, which scale with the DPI.
Actual
| Monitor | Font used to MEASURE | Font used to PAINT | Result |
|---|---|---|---|
| 120 dpi | height -19 | height -15 | ~25% of unused width per caption: the items look widely spaced |
| 96 dpi | height -15 | height -15 | no extra width: the items look cramped |
The captions themselves are drawn at the correct size in both cases. What is wrong is the width reserved for them.
Root cause
Both routines start the same way, taking the font from the menu styler when the button is a menu button:
if ParentStyler and Assigned(ToolBarStyler) and Assigned(ToolBarStyler.CurrentAdvMenuStyler) then
begin
if IsMenuButton then
Canvas.Font.Assign(ToolBarStyler.CurrentAdvMenuStyler.RootItem.font)
else
Canvas.Font.Assign(ToolBarStyler.ButtonAppearance.CaptionFont);
end
else
Canvas.Font.Assign(Font);
and then they disagree on whether to scale it. There are four places in the unit that make this same decision, with four different conditions:
| Line | Method | Condition guarding the scaling |
|---|---|---|
| 28784 | DrawGlyphAndCaption (1st branch) |
not (Assigned(ToolBarStyler) and Assigned(ToolBarStyler.AdvMenuStyler)) or not IsMenuButton |
| 29295 | DrawGlyphAndCaption (2nd branch) |
the same, plus or (IsMenuButton and not ...RootItem.UseSystemFont) |
| 30082 | AdjustSize (1st branch) |
none — see below |
| 30259 | AdjustSize (2nd branch) |
not (Assigned(ToolBarStyler) and Assigned(ToolBarStyler.AdvMenuStyler)) — no IsMenuButton test |
The first branch of AdjustSize (line 30082) is the one that matters for a menu button, and it has no condition at all. What put us on the track is that the condition is already written there, commented out, immediately above it:
// if not Assigned(ToolBarStyler) or not Assigned(ToolBarStyler.AdvMenuStyler) then
Canvas.Font.Height := Round(Canvas.Font.Height * scale);
We believe this is a defect rather than a deliberate choice: measuring and painting the same text with different fonts cannot be intentional, and the four conditions above cannot all be correct.
Suggested fix
Make AdjustSize use the same condition the painting code already uses, so that measurement and drawing stay symmetrical. In the first branch (line 30082):
if not (Assigned(ToolBarStyler) and Assigned(ToolBarStyler.AdvMenuStyler)) or not IsMenuButton then
Canvas.Font.Height := Round(Canvas.Font.Height * scale);
With this change, the spacing between the menu items depends only on the margin and looks identical on both monitors, and no other toolbar button is affected: for a non-menu button the condition evaluates to true, which is the current behaviour.
The second branch of AdjustSize (line 30259) presumably needs the same test. We did not have to touch it for our case, but it is inconsistent with the painting code for the same reason.