Page 1 of 2

Office-style menus (full include) - 20Feb2013 [x86 / x64]

Posted: Tue Oct 16, 2012 6:06 pm
by Inf0Byt3
I have finally finished an old project of mine, an include for creating custom menus that look like the ones from Office. The idea is inspired by that of eesau that can be found here:

http://www.purebasic.fr/english/viewtopic.php?t=27233.

This one is a complete library, written from scratch. The system itself is modeled after PureBasic's menu lib to make it easy to implement, without having to modify too much code. Some features:
  • - Close resemblance to Office menus
    - You can add new styles (colors) and change them in real time
    - Own management system for Office Menu 'objects' (with IDs, etc.)
    - Should work on: Window$ 2000, XP, Vista, 7, 8 (32 / 64 bit, Unicode supported)
    - Support for keyboard navigation and mnemonics
    - Open source
The menus are also compatible with animations and draw correctly, the only downside being that they flicker a bit sometimes. Nothing that can't be fixed with some double buffering - if I knew how to implement it that is. But that's something for you to tackle with, as for me fiddling with owner drawn menus was like trying to count hairs while wearing boxing gloves, especially since the menu implementations are so inconsistent across Window$.

As for older operating systems, I did try to make this code compatible with them. The tests on Window$ 98 looked promising, except for a single thing that I would like to hear an explanation for: after you play with the menu in its current form and you enter sub-menus, next time you open them, the menu item states do not reset :shock:. So if one item was highlighted when you click somewhere to close the menu and you open it again, the items are drawn as highlighted even if the cursor does not hover over them. I even tried to reset their state by force upon #WM_INITMENUPOPUP, but to no avail. Inconsistent menu implementation is inconsistent, but if you have any idea why this happens, please let me know. On the other hand, in Win2K things went better, even if the slightest drawing mistake would break all other menus. I found this to be a good guide while implementing the drawing code because it reduced the risk of bugs slipping in.

And another cool one: on Window$ 8, the menus are automatically opened to the left. This makes things look ackward. Much to my amazement, system menus behave the same way, opening sub-menus to the left, even if the arrows are drawn on the right ( :lol: ) and there is enough space to the right edge of the screen (gotta love these 'great new features'). So after fiddling around for some time I found a way to show the menus the good ol' way from Control Panel, in Tablet PC -> Handedness. What on earth is happening @ M$?

Screenshots:

Image

Image

That being said, enjoy:

BE_OfficeMenu.zip, 16 KB
http://www.bytessence.com/download/snip ... ceMenu.zip

Changelog:
20 February 2013:
-Fixed a crash when showing menus from the systray
-Added double buffering (no more flickering)
-Added OfficeMenu_IsMenu procedure
-Switched all data types to integers to avoid potential problems on x64

4 November 2012:
-Added x64 support

16 October 2012:
-First release

Re: Office-style menus (full include) - 16Oct2012

Posted: Tue Oct 16, 2012 6:44 pm
by eesau
Looks good!

Re: Office-style menus (full include) - 16Oct2012

Posted: Tue Oct 16, 2012 7:59 pm
by Inf0Byt3
Thank you, especially for breaking the ice with your code. Hopefully the lib will work as intended :).

Re: Office-style menus (full include) - 16Oct2012

Posted: Wed Oct 17, 2012 12:48 am
by yrreti
Thanks very much Inf0Byt3

It looks very nice, and will make some menu's in some of my personal programs
look a lot nicer. :D :D :D

yrreti

Re: Office-style menus (full include) - 16Oct2012

Posted: Wed Oct 17, 2012 11:41 am
by Kwai chang caine
Waooouuuh !!! Splendid !! :shock:
Works great, perhaps you can give your candidacy to CROSOFT now :D
Thanks a lot for sharing this jewel 8)

Re: Office-style menus (full include) - 16Oct2012

Posted: Wed Oct 17, 2012 1:41 pm
by Inf0Byt3
yrreti wrote:Thanks very much Inf0Byt3

It looks very nice, and will make some menu's in some of my personal programs
look a lot nicer. :D :D :D

yrreti
Sweet, let me know if you find any problem.
Kwaï chang caïne wrote:Waooouuuh !!! Splendid !! :shock:
Works great, perhaps you can give your candidacy to CROSOFT now :D
Thanks a lot for sharing this jewel 8)
Hehe they'll never get me alive :P.

BTW, has anyone compiled it on x64 yet? I'm curious if it even runs.

Re: Office-style menus (full include) - 16Oct2012

Posted: Wed Oct 17, 2012 3:53 pm
by leonhardt
:P useful,thanks

Re: Office-style menus (full include) - 16Oct2012

Posted: Wed Oct 17, 2012 4:37 pm
by NoahPhense
Very nice IB!

Re: Office-style menus (full include) - 16Oct2012

Posted: Thu Oct 18, 2012 11:25 am
by rudz
I compiled it using PB 5.0 B5 x64, the menu is not showing.
However, works like a charm in the x86 version.

Re: Office-style menus (full include) - 16Oct2012

Posted: Thu Oct 18, 2012 12:30 pm
by Inf0Byt3
NoahPhense wrote:Very nice IB!
Thanks!
rudz wrote:I compiled it using PB 5.0 B5 x64, the menu is not showing.
However, works like a charm in the x86 version.
Thanks for testing. I will try to add x64 support for the next version.

Re: Office-style menus (full include) - 16Oct2012

Posted: Sat Oct 27, 2012 8:17 pm
by Inf0Byt3
mevedia.de wrote: The only Problem here (again) is the gray Line between MenuBar and the client Area. (Line has #COLOR_3DFACE) :?
Ahh yes, that line is a total pain. I was quite annoyed by it too, but the thing is that it doesn't seem to be part of the menu itself, so trying to draw over it from the menu callback led nowhere. It could be a part of the main window client area. In other implementations, like the Internet Explorer menu, the "titles" are not actually menus, but toolbar items made to look like menus. The toolbar is then snapped onto a rebar, that's why it doesn't have a line under it. Maybe some API guru on the forum knows a way to eliminate it?
mevedia.de wrote: Small suggestion: Would be great, if you create a full featured MenuBar + ToolBar. (automaticly creating the ToolBar from MenuBar) and possibility to show/hide Menu Groups. :)
Initially this include should have been a complete menu, rebar and toolbar library, but due to the lack of examples regarding on how to owner-draw a rebar or even a toolbar, only the menu made it. Most examples were on buttons, combo-boxes or menus. It is possible to create a toolbar from scratch to avoid fiddling with API, I had started some code a few years back but never finished it. Maybe it's time to dig it up :mrgreen:.

Re: Office-style menus (full include) - 16Oct2012

Posted: Sat Oct 27, 2012 9:16 pm
by RASHAD
Workaround
But it needs more work to do

Code: Select all


;- DEMO for BE_OfficeMenus

;{ Includes
XIncludeFile "BE_OfficeMenu.pbi"
;}

;{ Variables
Define AddIcons, Image, WindowHandle, Event, PopupEvent
;}

;{ Create an array and put some icons into it
Dim Icons(9)
For AddIcons = 0 To 9
  Icons(AddIcons) = ExtractIcon_(GetModuleHandle_(0), "Shell32.dll", 15 + AddIcons)
Next
;}

;{ Create an image here
Image = CreateImage(#PB_Any, 200, 20)
If IsImage(Image)
  StartDrawing(ImageOutput(Image))
  Box(0, 0, 200, 20, RGB(0, 128, 255))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(6, 2, "Image gadget (right click me)", 0)
  DrawText(7, 3, "Image gadget (right click me)", RGB(255, 255, 255))
  StopDrawing()
EndIf
;}

If OpenWindow(0, 0, 0, 400, 280, "OfficeMenu Test", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_Invisible | #PB_Window_SizeGadget)
   OpenWindow(1, 0, 0, 400, 19, "OfficeMenu Test", #WS_POPUP|#PB_Window_BorderLess,WindowID(0))
   SetParent_(WindowID(1),WindowID(0))
  ;{ Init
  SetWindowColor(0, RGB(128,128,128))
  OfficeMenu_Init(WindowID(1)) ;This will hook the main window, must be called before adding OfficeMenus!
  ;}

  ;{ Gadgets
  UseGadgetList(WindowID(0))
  ButtonGadget(0, 100, 40, 200, 20, "Change menu theme")
  ImageGadget(1, 100, 90, 200, 20, ImageID(Image))
  StringGadget(2, 100, 140, 200, 20, "My context menu is left alone :P")
  ButtonGadget(3, 100, 190, 200, 20, "Change items")
  ButtonGadget(4, 100, 240, 200, 20, "Change titles")
  ;}

  ;{ Create menus
  WindowHandle = WindowID(1)
  If OfficeMenu_CreateMenu(0, WindowHandle, #OfficeMenu_Style_Blue) <> 0
    OfficeMenu_Title(0, "&File")
    OfficeMenu_Item(0, 0, "New" + Chr(9) + "Ctrl N")
    OfficeMenu_Item(0, 1, "&Open..." + Chr(9 ) + "Ctrl O")
    OfficeMenu_Item(0, 2, "Save" + Chr(9) + "Ctrl S", Icons(1))
    OfficeMenu_Item(0, 3, "Save As...", Icons(2))
    OfficeMenu_Item(0, 4, "Save All")
    OfficeMenu_Item(0, 5, "&Close" + Chr(9) + "Ctrl W", Icons(3))
    OfficeMenu_Item(0, 6, "Close All")
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 7, "Sort &Sources...", Icons(4))
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 8, "Preferences...", Icons(5))
    OfficeMenu_Bar(0)
    If OfficeMenu_OpenSubMenu(0, "Recent Files", Icons(8))
      OfficeMenu_Item(0, 9, "file1.pb")
      OfficeMenu_Item(0, 10, "file2.pb")
      OfficeMenu_Item(0, 11, "file3.pb", Icons(6))
      OfficeMenu_Bar(0)
      If OfficeMenu_OpenSubMenu(0, "More Files", Icons(1))
        OfficeMenu_Item(0, 12, "file4.pb")
        OfficeMenu_Item(0, 13, "file5.pb", Icons(7))
        OfficeMenu_Item(0, 14, "file6.pb")
        OfficeMenu_Item(0, 15, "file7.pb", Icons(8))
        OfficeMenu_Item(0, 16, "file8.pb")
        OfficeMenu_CloseSubMenu(0)
      EndIf
      OfficeMenu_Bar(0)
      OfficeMenu_Item(0, 17, "&Another item!", Icons(9))
      OfficeMenu_CloseSubMenu(0)
    EndIf
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 18, "Exit" + Chr(9) + "Alt + F4")
    OfficeMenu_Title(0, "&Edit")
    OfficeMenu_Item(0, 19, "&Undo" + Chr(9)+ "Ctrl + Z", Icons(2))
    OfficeMenu_Item(0, 20, "&Redo" + Chr(9)+ "Ctrl + Y")
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 21, "&Cut" + Chr(9)+ "Ctrl + X")
    OfficeMenu_Item(0, 22, "Co&py" + Chr(9)+ "Ctrl + C", Icons(5))
    OfficeMenu_Item(0, 23, "Pas&te" + Chr(9)+ "Ctrl + V", Icons(6))
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 24, "Select &All" + Chr(9)+ "Ctrl + A")
    OfficeMenu_Bar(0)
    OfficeMenu_Item(0, 25, "&Find" + Chr(9)+ "Ctrl + F", Icons(8))
    OfficeMenu_Title(0, "&Help")
    If OfficeMenu_OpenSubMenu(0, "I want", Icons(4))
      OfficeMenu_Item(0, 26, "some")
      If OfficeMenu_OpenSubMenu(0, "help", Icons(7))
        OfficeMenu_Item(0, 27, "please!" + Chr(9)+ "F1", Icons(3))
        OfficeMenu_CloseSubMenu(0)
      EndIf
      OfficeMenu_CloseSubMenu(0)
    EndIf
  Else
    Debug "Error creating main menu"
  EndIf
  If OfficeMenu_CreatePopupMenu(1, #OfficeMenu_Style_Standard) <> 0
    OfficeMenu_Item(1, 1000, "&This is", Icons(1))
    OfficeMenu_Item(1, 1001, "A &cool")
    OfficeMenu_Item(1, 1002, "Popup &menu!")
    OfficeMenu_Bar(1)
    If OfficeMenu_OpenSubMenu(1, "&Submenu", Icons(5))
      OfficeMenu_Item(1, 1003, "&Here")
      OfficeMenu_Bar(1)
      If OfficeMenu_OpenSubMenu(1, "And &another", Icons(2))
        OfficeMenu_Item(1, 1004, "&Here!")
        OfficeMenu_CloseSubMenu(1)
      EndIf
      OfficeMenu_CloseSubMenu(1)
    EndIf
    OfficeMenu_Bar(1)
    OfficeMenu_Item(1, 1005, "Co&nfiguration")
  Else
    Debug "Error creating popup menu"
  EndIf
  ;}

  ;{ Configure the menu
  OfficeMenu_SetItemState(0, 0, #MFS_CHECKED)
  OfficeMenu_SetItemState(0, 1, #MFS_CHECKED | #MFS_DISABLED)
  OfficeMenu_SetItemState(0, 10, #MFS_CHECKED)
  OfficeMenu_SetItemState(1, 1002, #MFS_CHECKED)
  OfficeMenu_SetItemState(1, 1004, #MFS_CHECKED)
  ;}

  ;{ Show the window
  HideWindow(0, 0)
  ;}

EndIf
SetActiveWindow(1)
Repeat
  Event = WaitWindowEvent()
  Select Event

    Case #PB_Event_Gadget ;{
      Select EventGadget()

        Case 0 ;{ Change theme
          If OfficeMenu_GetStyle(0) = #OfficeMenu_Style_Standard
            OfficeMenu_SetStyle(0, #OfficeMenu_Style_Blue)
            OfficeMenu_SetStyle(1, #OfficeMenu_Style_Standard)
          Else
            OfficeMenu_SetStyle(0, #OfficeMenu_Style_Standard)
            OfficeMenu_SetStyle(1, #OfficeMenu_Style_Blue)
          EndIf
          ;}

        Case 1 ;{ Image gadget
          If EventType() = #PB_EventType_RightClick
            PopupEvent = OfficeMenu_DisplayPopupMenu(1, WindowID(0), 0, 0, 1) ;Also return the selected item
            If PopupEvent <> 0
              MessageRequester("Menu event!","Popup event menu: "+Str(PopupEvent))
            EndIf
          EndIf
          ;}

        Case 3 ;{ Change items
          OfficeMenu_SetItemText(0, 6, "Looooooooooooooooooooooooooooooooong STRING :P "+Str(Random(1024)))
          Debug "New text for item 6: "+OfficeMenu_GetItemText(0, 6)
          OfficeMenu_SetItemIcon(0, 7, Icons(Random(9)))
          OfficeMenu_SetItemIcon(0, 8, Icons(Random(9)))
          OfficeMenu_SetItemIcon(1, 1000, Icons(Random(9)))
          OfficeMenu_SetItemIcon(1, 1003, Icons(Random(9)))
          ;}

        Case 4 ;{ Change titles
          OfficeMenu_SetTitleText(0, 0, "&What File !?")
          OfficeMenu_SetTitleText(0, 1, "&Tools are cool")
          Debug "New text for title 0: "+OfficeMenu_GetTitleText(0, 0)
          Debug "New text for title 1: "+OfficeMenu_GetTitleText(0, 1)
          If OfficeMenu_GetTitleState(0, 1) & #MFS_GRAYED
            OfficeMenu_SetTitleState(0, 1, #MFS_ENABLED)
          Else
            OfficeMenu_SetTitleState(0, 1, #MFS_GRAYED)
          EndIf
          ;}

      EndSelect
      ;}

    Case #PB_Event_Menu ;{
      MessageRequester("Menu event!","Event menu: "+Str(EventMenu()))
      ;}

  EndSelect
Until Event = #PB_Event_CloseWindow
;Manually free the menus!
OfficeMenu_FreeMenu(0)
OfficeMenu_FreeMenu(1)
;And uninit from the window
OfficeMenu_UnInit(WindowID(0))

Edit : Updated

Re: Office-style menus (full include) - 16Oct2012

Posted: Sat Oct 27, 2012 11:07 pm
by Inf0Byt3
Thanks RASHAD, that seems to eliminate the line. The downside is that it makes the main window lose focus :).

Re: Office-style menus (full include) - 16Oct2012

Posted: Sat Oct 27, 2012 11:15 pm
by RASHAD
Yes,but you can handle that a fake through a CallBack() with Moving and Resizing........

Re: Office-style menus (full include) - 16Oct2012

Posted: Sat Oct 27, 2012 11:37 pm
by Inf0Byt3
Indeed, it's worth a try :).