Announcement

Collapse
No announcement yet.

Owndrawn menu, top level

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Owndrawn menu, top level

    Guys --
    somebody have a sample ?
    I mean exactly first level ("File", "Edit" ?)

    ------------------
    E-MAIL: [email protected]

  • #2
    Never managed to reached those main items. Seems they are painted
    by system. Can use other way, if needed. Static control or toolbar
    as "menu bar" and a bunch of popup menus that are shown when user
    clicks on specic area or button. Then, possible to make all look
    like ownerdrawn top-level menu.

    And, can create/load an accelerator table to make all act as regular menu.
    And, can add HITTEST and make it possible to drag "menu" to other position..


    ------------------

    Comment


    • #3
      Menu is painted on NCPAINT

      (Like scrollbars in an edit box)

      ------------------
      http://www.hellobasic.com
      hellobasic

      Comment


      • #4
        I tried AppendMenu hMenu, %MF_POPUP Or %MF_OWNERDRAW, hMenuPopup, "..."
        There are %WM_MEASUREITEM and %WM_DRAWITEM , I can draw, but I can't recognize, what to draw.
        Typically is used (for "childs") ModifyMenu with %MF_BYCOMMAND to set itemdata.
        But how to modify submenu ?

        ------------------
        E-MAIL: [email protected]

        Comment


        • #5
          Okay, tested some and see it's possible. In WM_DRAWITEM, use DRAWITEMSTRUCT's
          hwndItem member and compare with handle of main menu. When they match, one can
          use GetMenuString with %MF_BYPOSITION and get sort out what item is to be drawn
          by comparing strings in a table.

          Only did a quick test and while it works, I think it means lots of extra
          work, because one has to do same work in %WM_MEASUREITEM to set widths, etc.
          Still think building look-a-like menu would be easier and far more flexible..


          ------------------

          Comment


          • #6
            Borje --
            GetMenuString ... Which id to use for popup-submenu

            ------------------
            E-MAIL: [email protected]

            Comment


            • #7
              Have to know and use position, I think. Understand what you mean and
              looking around among app's, can't see anyone doing it on a top-level
              sub-menu. Hm, makes it interesting - maybe can set and use the itemData
              member in DRAWITEMSTRUCT stucture for this purpose? Will test later.


              ------------------

              Comment


              • #8
                Okay, think I found a way to do it here. In a way, one has to know
                positions, but only for "header" menu items. Lets say main menu handle
                is hMnu, then one can set an id for given position via the uIDNewItem
                member in ModifyMenu. Something like:
                Code:
                  ModifyMenu hMnu, 0, %MF_BYPOSITION OR %MF_STRING OR %MF_OWNERDRAW, %NEWID, BYVAL %NULL
                Now itemId member in DRAWITEMSTRUCT can see what it is. Did quick test
                and if to give the main menu items, File, Edit, etc, id's below a certain
                value, and the rest above this value, there is a way to separate them.
                Same can be done with popup menu items, and then one can use another range
                of id's, to be able to separate them from top-level items.

                Then it's just a matter of controlling how and what to draw. Main items
                pops up on mouse over and is never drawn with "selected" color, so have
                to act differently on them. Just tested on my previous Drawmenu code,
                and it looks fine. Will clean up and post later on..


                ------------------

                Comment


                • #9
                  Borje --
                  today I came back to this problem.
                  Instead of AppendMenu I used InsertMenuItem and specified mii.wID.
                  Now I can recognize, using .itemId, but there is no %WM_MEASUREITEM message (WM_DRAWITEM only).
                  So troubles with width of top level items.
                  Did you have success ?
                  I did
                  Code:
                      Dim mii As Static MENUITEMINFO
                      mii.cbsize = Len(MENUITEMINFO)
                      mii.fMask = %MIIM_ID Or %MIIM_SUBMENU Or %MIIM_TYPE
                      mii.fType = %MFT_OWNERDRAW
                      mii.wID = k * 100 + 10
                      mii.hSubMenu = hMenuPopup(k)
                      InsertMenuItem hMenu, mii.wID, %FALSE, mii



                  ------------------
                  E-MAIL: [email protected]

                  Comment


                  • #10
                    Hm, yes - that part works fine. I have only tested with DDT-created menu, but
                    should not differ. After creation, I used following:
                    Code:
                      ModifyMenu hMnu, 0, %MF_BYPOSITION OR  %MF_STRING OR %MF_OWNERDRAW, %IDMENUFILE,  BYVAL %NULL
                    Where hMenu is global handle for main menu and %IDMENUFILE is my own id for it.
                    DRAWITEMSTRUCT sees this id so I can decide what bitmap to draw. Stumbled on
                    another problem and have had to let it rest for a while.

                    Problem is, standard top-level menu items pops up on mouse over. Ownerdrawn
                    ones of course don't, we must paint that ourselves. How detect what top-level
                    menu item mouse is over and then, how force a proper WM_DRAWITEM "manually"?

                    Anyway, following gives me proper widths in Win98 - not sure it is 100% okay
                    to like this, but looks fine in test app' here:
                    Code:
                        CASE %WM_MEASUREITEM    'Get menu item size
                           IF wParam = 0 THEN   'a menu is calling
                              LOCAL hDC AS LONG, hFont AS LONG, lpmis AS MEASUREITEMSTRUCT PTR, sz AS SIZEL
                     
                              lpmis = lParam         'Copy pointer into our structure
                              hDC = GetDC(hWnd)
                              hFont = SelectObject(hDC, GetStockObject(%DEFAULT_GUI_FONT))
                     
                              GetMenuString  hMnu, @lpmis.itemID, zText, SIZEOF(zText), 0
                              GetTextExtentPoint32 hDC, zText, LEN(zText), sz
                              @lpmis.itemWidth = 30 + sz.cx           'bitmap is 16 wide + some space = 30, + text width..
                              @lpmis.itemHeight = Max&(20, sz.cy + 2) 'bitmap is 15 heigh, plus frames, so use minimun 20
                     
                              SelectObject hDC, hFont
                              ReleaseDC hWnd, hDC
                              Function = %TRUE: Exit Function
                           END IF

                    ------------------

                    Comment


                    • #11
                      Okay, so one can use %WM_NCMOUSEMOVE to detect when mouse is in menu, but
                      then what?
                      Code:
                           CASE %WM_NCMOUSEMOVE
                              IF wParam = %HTMENU THEN BEEP
                      Will play more with it later..


                      ------------------

                      Comment


                      • #12
                        Borje --
                        Can't understand "by position" (there are some submenu).
                        I cut my code to minimum.
                        Under Win2000 something terrible. If to leave one submenu, it's name is visible, but width of element is incorrect (no MEASUREITEM).

                        Code:
                           #Compile Exe
                           #Register None
                           #Dim All
                           #Include "WIN32API.INC"
                        
                           Function mDrawMenu(ByVal hWnd As Long, ByVal wMsg As Long, _
                                             ByVal wParam As Long, ByVal lParam As Long) As Long
                        
                              Local lpmis As MEASUREITEMSTRUCT Ptr
                              Local lpdis As DRAWITEMSTRUCT Ptr
                              Local hdc As Long
                              Local SizeA As SizeL
                              Local Txt As Asciiz * 255
                              Select Case wMsg
                                 Case %WM_MEASUREITEM
                                    lpmis = lparam
                                    If @lpmis.itemId = 110 Then SetWindowText hWnd, "MEASUREITEM"
                                    hdc = GetDC(hWnd)
                                    Txt = "Id"+ Str$(@lpmis.itemId)
                                    GetTextExtentPoint32 hdc, Txt, Len(Txt), SizeA
                                    @lpmis.itemWidth = 8 + sizeA.cx
                                    @lpmis.itemHeight = sizeA.cy
                                    ReleaseDC hWnd, hdc
                        
                                 Case %WM_DRAWITEM
                                    lpdis = lparam
                                    '  If @lpdis.itemId = 110 Then SetWindowText hWnd, "DRAWITEM"
                                    Txt = "Id=" + Str$(@lpdis.itemId)
                                    If (@lpdis.itemState And %ODS_SELECTED) Then
                                       FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_HIGHLIGHT)
                                       SetTextColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHTTEXT)
                                    Else
                                       FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_MENU)
                                       SetTextColor @lpdis.hDC, GetSysColor(%COLOR_MENUTEXT)
                                    End If
                                    SetBkMode @lpdis.hDC, %TRANSPARENT
                                    TextOut @lpdis.hDC, 8 + @lpdis.rcItem.nleft, @lpdis.rcItem.nTop, Txt, Len(Txt) ', ByVal 0
                              End Select
                        
                           End Function
                        
                        
                           CallBack Function DlgProc
                        
                              Dim hMenuPopup(5) As Long
                              Static hmenu As Long
                              Local i As Long, k As Long
                        
                              Select Case CbMsg
                                 Case %WM_INITDIALOG
                                    hMenu = CreateMenu
                        
                                    For k = 1 To 5
                                       hMenuPopup(k)  = CreateMenu
                                       For i = 0 To 5
                                          InsertMenu hMenuPopup(k), %MF_BYCOMMAND, %MF_STRING, k * 100 + i, ""
                                          ModifyMenu hmenuPopup(k), k * 100 + i, %MF_BYCOMMAND Or %MF_OWNERDRAW, k * 100 + i, ByVal 0
                                       Next
                        
                                       Dim mii As Static MENUITEMINFO
                                       mii.cbsize = Len(MENUITEMINFO)
                                       mii.fMask = %MIIM_ID Or %MIIM_TYPE Or %MIIM_SUBMENU
                                       mii.fType =  %MFT_OWNERDRAW
                                       mii.wID = k * 100 + 10
                                       mii.hSubMenu = hMenuPopup(k)
                                       InsertMenuItem hMenu, mii.wID, %FALSE, mii
                                    Next
                                    SetMenu CbHndl, hMenu
                        
                                Case %WM_MEASUREITEM, %WM_DRAWITEM
                                    mDrawMenu CbHndl, CbMsg, CbWparam, CbLparam
                                    Function = 1
                              End Select
                           End Function
                        
                           Function PbMain
                              Local hDlg As Long
                              Dialog New 0, "Test", , , 400, 200, %WS_CAPTION Or %WS_OVERLAPPEDWINDOW To hDlg
                              Dialog Show Modal hDlg Call DlgProc
                           End Function

                        ------------------
                        E-MAIL: [email protected]

                        Comment


                        • #13
                          Don't know, but following seems to work. Changed InsertMenuItem so
                          it sets %MFT_STRING instead and modifiy each top-level menu after menu
                          has been set. Get WM_MEASUREITEM and all looks fine.. except the problem
                          with no pop-up, as mentioned earlier.
                          Code:
                                Case %WM_INITDIALOG
                                   LOCAL zText AS ASCIIZ * 10
                                   Dim mii As Static MENUITEMINFO
                                   mii.cbsize = Len(MENUITEMINFO)
                                   mii.fMask = %MIIM_ID Or %MIIM_TYPE Or %MIIM_SUBMENU
                                   mii.fType = %MFT_STRING
                           
                                   hMenu = CreateMenu
                                   zText = "" 
                           
                                   For k = 1 To 5
                                      hMenuPopup(k)  = CreateMenu
                                      For i = 0 To 5
                                         InsertMenu hMenuPopup(k), %MF_BYCOMMAND, %MF_STRING, k * 100 + i, ""
                                         ModifyMenu hmenuPopup(k), k * 100 + i, %MF_BYCOMMAND Or %MF_OWNERDRAW, k * 100 + i, ByVal 0
                                      Next
                           
                                      mii.wID = k * 100 + 10
                                      mii.hSubMenu = hMenuPopup(k)
                                      mii.dwTypeData = VARPTR(zText)
                                      mii.cch = LEN(zText)
                                      InsertMenuItem hMenu, mii.wID, %FALSE, mii
                                   Next
                                   SetMenu CbHndl, hMenu
                                   For k = 1 To 5
                                      ModifyMenu hMenu, k - 1, %MF_BYPOSITION Or %MF_OWNERDRAW, k * 100 + 10, ByVal 0
                                   NEXT
                          ------------------
                          Changed the id's in last ModifyMenu part..



                          [This message has been edited by Borje Hagsten (edited October 04, 2001).]

                          Comment


                          • #14
                            Borje --
                            Thanx. I quickly tested. Under Win2000 it also works.
                            I was afraid to modify by position, because I was not sure, how Windows enumerates items.
                            Tomorrow I will do more deep test.

                            Added later ...
                            I changed MF_BYCOMMAND. Also works. It looks that a reason of my troubles was mii.fType (which I set initially to owndraw)

                            [This message has been edited by Semen Matusovski (edited October 04, 2001).]

                            Comment


                            • #15
                              Okay, nice to see it works that way too. Agree it feels safer. Here's a
                              complete sample that sets text at creation and gets it in %WM_MEASUREITEM
                              and %WM_DRAWITEM. Added some icons to the top-level menus just to show
                              others how it can be done. Still the "pop-up issue" left to solve, though.

                              May have to experiment with selecting correct font into DC in %WM_MEASUREITEM
                              to get correct widths, etc. Rough sample that needs a lot more work, but can
                              act as good starting-point for fun stuff.
                              Code:
                              #Compile Exe
                              #Register None
                              #Dim All
                              #Include "WIN32API.INC"
                               
                              Function mDrawMenu(ByVal hWnd As Long, ByVal wMsg As Long, _
                                                 ByVal wParam As Long, ByVal lParam As Long) As Long
                               
                                 Local lpmis As MEASUREITEMSTRUCT Ptr
                                 Local lpdis As DRAWITEMSTRUCT Ptr
                                 LOCAL MMI AS MENUITEMINFO
                                 Local hdc As Long, hIcon AS LONG
                                 Local SizeA As SizeL
                                 Local Txt As Asciiz * 255
                               
                                 Select Case wMsg
                                    Case %WM_MEASUREITEM
                                       lpmis = lparam
                              
                                       MMI.cbSize     = LEN(MMI)
                                       MMI.fMask      = %MF_STRING OR %MIIM_TYPE
                                       MMI.cch        = SIZEOF(Txt)
                                       MMI.dwTypeData = VARPTR(Txt)
                                       CALL GetMenuItemInfo(GetMenu(hWnd), @lpmis.itemId, 0&, BYVAL VARPTR(MMI))
                               
                                       hdc = GetDC(hWnd)
                                         GetTextExtentPoint32 hdc, Txt, Len(Txt), SizeA
                                         @lpmis.itemWidth  = sizeA.cx + 16
                                         @lpmis.itemHeight = sizeA.cy + 2
                                       ReleaseDC hWnd, hdc
                               
                                    Case %WM_DRAWITEM
                                       lpdis = lparam
                              
                                       MMI.cbSize     = LEN(MMI)
                                       MMI.fMask      = %MF_STRING OR %MIIM_TYPE
                                       MMI.cch        = SIZEOF(Txt)
                                       MMI.dwTypeData = VARPTR(Txt)
                                       CALL GetMenuItemInfo(GetMenu(hWnd), @lpdis.itemId, 0&, BYVAL VARPTR(MMI))
                              
                                       If (@lpdis.itemState And %ODS_SELECTED) Then
                                          FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_INFOBK)
                                          SetTextColor @lpdis.hDC, GetSysColor(%COLOR_INFOTEXT)
                                       Else
                                          FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_MENU)
                                          SetTextColor @lpdis.hDC, GetSysColor(%COLOR_MENUTEXT)
                                       End If
                                       SetBkMode @lpdis.hDC, %TRANSPARENT
                                       TextOut @lpdis.hDC, @lpdis.rcItem.nleft + 22, @lpdis.rcItem.nTop, Txt, Len(Txt) ', ByVal 0
                               
                                       Select Case @lpdis.itemID
                                          CASE 105  : hIcon = LoadIcon(0, BYVAL %IDI_HAND)        'sub-menu item..
                                          CASE 110  : hIcon = LoadIcon(0, BYVAL %IDI_APPLICATION) 'top-menu items..
                                          CASE 210  : hIcon = LoadIcon(0, BYVAL %IDI_ASTERISK)
                                          CASE 310  : hIcon = LoadIcon(0, BYVAL %IDI_EXCLAMATION)
                                          CASE 410  : hIcon = LoadIcon(0, BYVAL %IDI_QUESTION)
                                          CASE 510  : hIcon = LoadIcon(0, BYVAL %IDI_WINLOGO)
                                          CASE ELSE : EXIT FUNCTION
                                       END SELECT
                                       DrawIconEx @lpdis.hDC, @lpdis.rcItem.nleft + 2, @lpdis.rcItem.nTop + 1, _
                                                  hIcon, 16, 16, 0, ByVal 0, %DI_NORMAL
                               
                                 End Select
                               
                              End Function
                               
                              CallBack Function DlgProc
                                 Dim hMenuPopup(5) As Long
                                 Static hmenu As Long
                                 Local i As Long, k As Long
                               
                                 Select Case CbMsg
                                    Case %WM_INITDIALOG
                                       LOCAL zText AS ASCIIZ * 100
                                       Dim mii As Static MENUITEMINFO
                               
                                       hMenu = CreateMenu
                                       zText = "" 
                               
                                       For k = 1 To 5
                                         '--- SUB-MENUS ----------------------
                                          hMenuPopup(k)  = CreateMenu
                                          For i = 0 To 5
                                             IF k = 3 THEN
                                                zText = "Long sub-menu string, id "+ Str$(k * 100 + i)
                                             ELSE
                                                zText = "Id "+ Str$(k * 100 + i)
                                             END IF
                                             InsertMenu hMenuPopup(k), %MF_BYCOMMAND, %MF_STRING, k * 100 + i, zText
                                             ModifyMenu hmenuPopup(k), k * 100 + i, %MF_BYCOMMAND Or %MF_OWNERDRAW, k * 100 + i, ByVal 0
                                          Next
                               
                                         '--- TOP-LEVEL MENUS ----------------------
                                          mii.cbsize = Len(MENUITEMINFO)
                                          mii.fMask = %MIIM_ID Or %MIIM_TYPE Or %MIIM_SUBMENU
                                          mii.fType = %MFT_STRING
                                          mii.wID = k * 100 + 10
                                          mii.hSubMenu = hMenuPopup(k)
                               
                                          If k = 2 Then
                                             zText = "Long menu string, id "+ Str$(k * 100 + 10)
                                          ELSE
                                             zText = "Id "+ Str$(k * 100 + 10)
                                          END IF
                               
                                          mii.dwTypeData = VARPTR(zText)
                                          mii.cch = LEN(zText)
                                          InsertMenuItem hMenu, mii.wID, %FALSE, mii
                                       Next
                               
                                       SetMenu CbHndl, hMenu
                               
                                       For k = 1 To 5
                                          ModifyMenu hMenu, k * 100 + 10, %MF_OWNERDRAW, k * 100 + 10, ByVal 0
                                       NEXT
                               
                                   Case %WM_MEASUREITEM, %WM_DRAWITEM
                                       mDrawMenu CbHndl, CbMsg, CbWparam, CbLparam
                                       Function = 1
                                 End Select
                              End Function
                               
                              Function PbMain
                                 Local hDlg As Long
                                 Dialog New 0, "Test", , , 400, 200, %WS_OVERLAPPEDWINDOW To hDlg
                                 Dialog Show Modal hDlg Call DlgProc
                              End Function

                              ------------------




                              [This message has been edited by Borje Hagsten (edited October 05, 2001).]

                              Comment


                              • #16
                                1) GetMenuString in similar situation doesn't work, at least, in Windows 95 and 2000 (I didn't test under NT, but think also).
                                2) Interesting that
                                Code:
                                SetMenu CbHndl, hMenu
                                For k = 1 To 5
                                   ModifyMenu hMenu, k * 100 + 10, %MF_OWNERDRAW, k * 100 + 10, ByVal 0
                                Next
                                works correctly exactly in such order (I tested in 95/NT/2000).
                                3) With "popup" all is simple: itemstate And %ODS_HOTLIGHT (&H0040&)
                                Under 95/NT there is no "popup" feature (and ODS_HOTLIGHT also).

                                Now I think about Alt-* for first level.
                                How to do/work with accelerators - not a problem, I'll correct message loop.
                                But Alt-* are not accelerators, as I understand.

                                I can detect Alt-* in message loop, but I don't imagine how to stimulate "Dropdown".
                                To generate mouse event looks not interesting, unlike possible.


                                ------------------
                                E-MAIL: [email protected]

                                [This message has been edited by Semen Matusovski (edited October 05, 2001).]

                                Comment


                                • #17
                                  Works here, in Win98. Seem to recall there were problem with GetMenuString
                                  in another code, so changed my sample to use GetMenuItemInfo instead.

                                  Don't think Bill ever wanted us to be able to do things with top-level
                                  menus. Did some testing and a "good" way to keep track of up-down seems
                                  to be by using timer, GetCursorPos, GetMenuItemRect and PtInRect.
                                  Not pretty.



                                  ------------------

                                  Comment


                                  • #18
                                    I think many MS apps use a toolbar for the top level bit, see VB.

                                    ------------------
                                    Kev G Peel
                                    KGP Software, Bridgwater, UK.
                                    mailto:[email protected][email protected]</A>
                                    kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

                                    Comment


                                    • #19
                                      It seems to me I found, what it's necessary to do - to process WM_MENUCHAR.
                                      But my tests with DDT was unsuccessful. Will try SDK tomorrow.

                                      ------------------
                                      E-MAIL: [email protected]

                                      Comment

                                      Working...
                                      X