Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Delphi themed toolbars have dividers that are centred between their tool buttons?

I have noticed a rather annoying oddity with Delphi toolbars. I have a TToolbar that has logical groups of icons. To make the grouping stand out I would like to use separator buttons, with style tbsDivider.

When I do this, it looks like this:

enter image description here

Note the double vertical lines between each icon. The right hand one is in the middle of the separator tool button. The left hand one is on the left edge of the separator tool button.

So, I can switch to tbsSeparator which removes the middle line:

enter image description here

But I'm not keen on that since I'd like the divider to be in the middle.

I looked at an ancient version of my real app and found that it had centred separators. It seems that is possible when Windows themes are disabled. Here's what it looks like with tbsDivider and the application manifest removed:

enter image description here

That's the layout I am looking for. Is this attainable when themes are active?

I did find a discussion of the issue on the Embarcadero forums, but there was no useful insight: https://forums.embarcadero.com/message.jspa?messageID=467842

For sake of completeness, here's the pertinent extract from the .dfm file

object ToolButton1: TToolButton
  Left = 0
  Top = 0
  ImageIndex = 0
end
object ToolButton2: TToolButton
  Left = 23
  Top = 0
  Width = 16
  ImageIndex = 1
  Style = tbsDivider
end
object ToolButton3: TToolButton
  Left = 39
  Top = 0
  ImageIndex = 1
end
object ToolButton4: TToolButton
  Left = 62
  Top = 0
  Width = 16
  ImageIndex = 2
  Style = tbsDivider
end
object ToolButton5: TToolButton
  Left = 78
  Top = 0
  ImageIndex = 2
end
like image 668
David Heffernan Avatar asked Sep 28 '12 18:09

David Heffernan


1 Answers

This looks like a flaw in the VCL to me. The tbsDivider style does not map to an equivalent style in Win32. A tool button with that style is implemented in the VCL in just the same way as a tbsSeparator style, but with a custom paint method. This is extracted from TToolButton.Paint:

if Style = tbsDivider then
  with Canvas do
  begin
    R := Rect(Width div 2 - 1, 0, Width, Height);
    if StyleServices.Enabled then
    begin
      Details := StyleServices.GetElementDetails(ttbSeparatorNormal);
      StyleServices.DrawElement(Handle, Details, R);
    end
    else
      DrawEdge(Handle, R, EDGE_ETCHED, BF_LEFT)
  end;

In the old days of pre-v6 comctl32, the tbsSeparator style maps to a Win32 TBSTYLE_SEP style tool button. And in pre-v6 comctl32 that renders simply as a space with no vertical lines. The VCL designers clearly wanted to do more and added tbsDivider with the custom painting above.

Fast forward to v6 comctl32. Now the common control draws a vertical line at the left hand edge of all TBSTYLE_SEP separators. So the code above simply adds an extra vertical line in the middle of the separator.

We can try to get rid of the left-hand vertical line from a tbsDivider by modifying the code like this:

if Style = tbsDivider then
  with Canvas do
  begin
    if StyleServices.Enabled then
    begin
      //re-paint the background to remove the vertical line drawn
      //for the standard separator button
      R := Rect(0, 0, Width, Height);
      StyleServices.DrawParentBackground(FToolBar.Handle, Handle, nil, False, R);
    end;

    R := Rect(Width div 2 - 1, 0, Width, Height);
    if StyleServices.Enabled then
    begin
      Details := StyleServices.GetElementDetails(ttbSeparatorNormal);
      StyleServices.DrawElement(Handle, Details, R);
    end
    else
      DrawEdge(Handle, R, EDGE_ETCHED, BF_LEFT)
  end;

However, that doesn't work out because there's a lot of flickering as the left hand line is drawn and then painted over.

I suspect that the VCL designers simply missed this arcane detail in the transition to v6 comctl32.

I'll submit a QC report in due course.

like image 171
David Heffernan Avatar answered Sep 17 '22 16:09

David Heffernan