1

Possible Duplicate:
Owner Drawing TMainMenu over Aero Glass Form?

Hi,

I am interested in having an application's main menu drawn on the application's caption bar ? A bit like iTunes and Songbird (Windows 7).

Any hints would be helpful - I can draw a button or panel, but no a menu.

CHeers

Community
  • 1
  • 1
mmmm
  • 2,431
  • 2
  • 35
  • 56
  • 2
    Is this a duplicate of http://stackoverflow.com/questions/4732039/owner-drawing-tmainmenu-over-aero-glass-form? – Andreas Rejbrand Feb 26 '11 at 23:48
  • iTunes does not draw its main menus in glass, even though it is drawing its menus at the top of the nonclient area. If you just want to draw your menus in the nonclient area, remove the word glass from your question title, and it would not get closed as a duplicate. Songbird does not support glass either from what I can see. – Warren P Feb 27 '11 at 17:52
  • Voted to reopen, as apparently mentioning *glass* have been an unintentional mistake which has been corrected in response to Warren's comment, and in fact, I don't quite understand what the other question asks. – Sertac Akyuz Feb 28 '11 at 15:50

1 Answers1

2

It is not possible to relocate a standard Windows menu, Windows places it always right under the caption. Indeed a search with "iTunes" and "WS_CAPTION" shows up some references that say the iTunes window does not have the WS_CAPTION style. I would guess the same to be true with 'Songbird' also. So what these applications doing is to remove the caption to have the menu at the top and simulate having a caption (they might even not have a standard menu and their own menu implementation, but I don't know about that).

You can remove the caption of a Delphi form by removing the style:

  SetWindowLong(Handle, GWL_STYLE,
      GetWindowLong(Handle, GWL_STYLE) and not WS_CAPTION);
  SetWindowPos(Handle, 0, 0, 0, 0, 0,
      SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_FRAMECHANGED);

Then the menu will appear at the top (with no caption). You would then fake mouse clicks at the top of the window to be on the caption for being able to move around the window with the mouse. You can achieve this by handling WM_NCHITTEST message. But you have to exclude the area that the menu items occupy;

type
  TForm1 = class(TForm)
    [...]
  private
    procedure WmNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
  public

[...]

procedure TForm1.WmNCHitTest(var Msg: TWMNCHitTest);
var
  Pt: TPoint;
  MenuBarInfo: TMenuBarInfo;
  i, MenuWidth: Integer;
begin
  inherited;

  // calculate the total width of top menu items
  MenuBarInfo.cbSize := SizeOf(MenuBarInfo);
  MenuWidth := 0;
  for i := 0 to MainMenu1.Items.Count - 1 do begin
    GetMenuBarInfo(Handle, OBJID_MENU, 1, MenuBarInfo);
    MenuWidth := MenuWidth + MenuBarInfo.rcBar.Right - MenuBarInfo.rcBar.Left;
  end;

  Pt := ScreenToClient(SmallPointToPoint(Msg.Pos));
  Pt.Y := Pt.Y + MenuBarInfo.rcBar.Bottom - MenuBarInfo.rcBar.Top;
  if (Pt.Y <= GetSystemMetrics(SM_CYCAPTION)) and (Pt.Y >= 0) and
      (Pt.X > MenuWidth) and (Pt.X < ClientWidth) then
    Msg.Result := HTCAPTION;
end;

Depending on the Delphi version you use, you might not succeed with the GetMenuBarInfo call. F.i. D2007 incorrectly declares the TMenuBarInfo structure packed. So you might have to redeclare it and the function before you call the function.

type
  TMenuBarInfo = record
    cbSize: DWORD;
    rcBar: TRect;
    hMenu: HMENU;
    hwndMenu: HWND;
    fBarFocused: Byte;
    fFocused: Byte;
  end;

function GetMenuBarInfo(hend: HWND; idObject, idItem: ULONG;
  var pmbi: TMenuBarInfo): BOOL; stdcall; external user32;

Finally you would probably put some buttons to the far right side for users to be able to minimize, restore etc.. the window.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Cool. I'll experiment, and see whether this does what I want! – mmmm Feb 28 '11 at 12:16
  • It works - if only I knew how to replace the control buttons. – mmmm Feb 28 '11 at 15:35
  • @Mmarquee - If by control buttons you mean minimize, close etc.., you can again return the relevant hit test depending on the cursor's location. As for the looks, you can draw appropriate images depending on mouse button is pressed or not... Hint: you can always ask a question. :) – Sertac Akyuz Feb 28 '11 at 16:02