Announcement

Collapse
No announcement yet.

Owner Draw button themed for XP

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

  • Owner Draw button themed for XP

    the following is an attempt to address the issue of making image buttons themed when run in xp. this has been a frequent request on this forum, but hasn’t yet been answered. i actually just draw red text, but bitblting an image onto a button would be nearly as easy.

    don’t get too excited though, because my code doesn’t yet ‘hotlight’ the button by adding an orange border when the mouse cursor is on it. can anyone suggest why the %wm_drawitem message never seems to be received with the %ods_hotlight flag set?

    the code assumes that there is an xp manifest in the resource file. calling isthemeactive does not appear to be necessary because openthemedata only returns a handle if the program is running under xp and the style chosen is themed (i.e. not ‘windows classic’).

    theme.inc is by rosa meltronco and is the bottom half of the code posted at: http://www.powerbasic.com/support/pb...ad.php?t=23846
    Code:
    #resource "themed"  ‘includes xml manifest file
    #include "win32api.inc"
    #include "theme.inc"  ‘by rosa meltronco
    
    callback function ownerdrawproc
       select case cbmsg
         case %wm_drawitem       'owner draw buttons 
           dim t as drawitemstruct ptr
           dim txt$, r as rect, htheme as dword, istate as long
           t=cblparam
           r= @t.rcitem
           htheme= openthemedata(cbhndl, "button")
           if htheme then   'xp theme         
              control send cbhndl,cbwparam,%wm_erasebkgnd,@t.hdc,0 
                'avoids button acquiring square corners after being pressed
              istate=1 ' default state = %minbs_normal 
              if (@t.itemstate and %ods_inactive) then istate=5        
              if (@t.itemstate and %ods_disabled) then istate=4      
              if (@t.itemstate and %ods_hotlight) then istate=2 ' %minbs_hot       
              if (@t.itemstate and %ods_selected) then istate=3 ' %minbs_pushed       
              call drawthemebackground(htheme, @t.hdc, 1, istate, @t.rcitem, byval %null) 
              call closethemedata(htheme)
           else             'not xp or not themed
             if(@t.itemstate and %ods_selected) then
               call drawframecontrol(byval @t.hdc,@t.rcitem,%dfc_button,%dfcs_buttonpush or %dfcs_pushed)
               r.ntop=r.ntop+2 : r.nleft=r.nleft+2 'move the text 1 pixel when button pressed
             else
               call drawframecontrol(byval @t.hdc,@t.rcitem,%dfc_button,%dfcs_buttonpush)  
             end if
           end if
    
      'we've drawn the button - now put text or graphics onto it
           control get text cbhndl,cbctl to txt$
           settextcolor @t.hdc,%red
           setbkmode @t.hdc,%transparent
           drawtext @t.hdc,bycopy txt$,-1,r,%dt_singleline or %dt_center or %dt_vcenter
           function=%true
                         
       end select
    end function
    
    function pbmain
       local hdlg as dword
       dialog new 0,"themed owner draw buttons",0,0,150,100,%ws_caption or %ws_sysmenu to hdlg
       control add button, hdlg, 100, "owner draw 1",5,20,50,14 ,%ws_tabstop or %bs_ownerdraw 
       control add button, hdlg, 101, "owner draw 2",5,40,50,24 ,%ws_tabstop or %bs_ownerdraw
       control add button, hdlg, 102, "standard",5,80,50,14 'standard button for comparison
       dialog show modal hdlg, call ownerdrawproc  
    end function

  • #2
    Hm, still no joy with 'hotlighting'. I came across the BCN_HOTITEMCHANGE notification message on msdn (%BCN_HOTITEMCHANGE = -1249), but I'm only getting this for normal buttons, not my owner-drawn ones. It seems that on my version of XP (Home SP2), M$ has neglected to implement the documented %ODS_HotLight state of the WM_DrawItem message for owner-drawn buttons. Perhaps it works with other types of control, otherwise it is a totally redundant facility, since WM_DrawItem is only used with owner draw.

    I suppose I could do my own hit testing in a WM_MouseMove handler, or perhaps a sub-classed button would retain its themed look, but that seems rather a lot of work just to get a button to highlight when the mouse is on it.

    Any comments or suggestions please?

    Comment


    • #3
      Seems like you will have to subclass the button, trap mouse-over and draw this state "by hand".

      See: http://www.codeguru.com/Cpp/controls...cle.php/c5161/


      ------------------
      PowerBASIC Staff
      ------------------
      Private web-site: http://www.tolkenxp.com/pb
      Free downloads: POFFS, incLean, PBcodec, custom controls and PB samples.

      Comment


      • #4
        Thanks, Borje.

        Well here's a much simpler way of doing XP themeing of 'special' buttons, using sub-classing rather than owner-draw, making Windows do all the work of button drawing, hotlighting, etc. No special includes are now needed.

        This code is a bit primitive at the moment - it clearly need a some arrays if there are more than two buttons to be treated in this way. The global oldProc could be avoided by storing it in the window properties with SetProp. This would also provide a separate value for each button for the address of the normal button procedure, which Windows seems to use.
        Code:
        #RESOURCE "Themed"   'include XML manifest file
        #INCLUDE "Win32API.inc"
        
        GLOBAL oldProc AS DWORD  'use for both sub-classed buttons
        
        FUNCTION SCButtonProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS LONG, _
                               BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
          LOCAL hDC AS DWORD, R AS RECT, hOldObject AS DWORD
          FUNCTION=CallWindowProc(oldProc,hWnd,wMsg,wParam,lParam)
             'done normal painting first, now add our finishing touches
          IF wMsg=%WM_PAINT THEN
            GETClientRECT hWnd,R
            hDC=GetDC(hWnd)  
              SELECT CASE GetDlgCtrlID(hWnd)
              CASE 100   'put red text on the button
                 hOldObject=SelectObject(hDC,GetStockObject(%Default_GUI_Font))
                 SETTEXTCOLOR hDC,%RED
                 SETBKMODE hDC,%TRANSPARENT
                 DRAWTEXT hDC,"Sub-classed",-1,R,%DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                 SelectObject hDC,hOldObject
              CASE 101    'draw an ellipse on the button
                 hOldObject=SelectObject (hDC,GetStockObject(%Gray_Brush))
                 ELLIPSE hDC, R.nLeft+20, R.nTop+10, R.nRight-20, R.nBottom-10
                 SelectObject hDC,hOldObject
              END SELECT 
            ReleaseDC hWnd,hDC   
          END IF
        END FUNCTION  
        
        CALLBACK FUNCTION ButtonProc
           STATIC hCtrl1,hCtrl2 AS DWORD 
        
           SELECT CASE CBMSG
         
           CASE %WM_INITDIALOG
             CONTROL HANDLE CBHNDL,100 TO hCtrl1
             oldProc=SETWINDOWLONG(hCtrl1,%GWL_WndProc, CODEPTR(SCButtonProc))
             CONTROL HANDLE CBHNDL,101 TO hCtrl2
             IF SETWINDOWLONG(hCtrl2,%GWL_WndProc, CODEPTR(SCButtonProc))<>oldProc THEN _
                 MSGBOX "False assumption!" 'works OK using the same oldProc for both buttons
             
           CASE %WM_Destroy  
             SETWINDOWLONG hCtrl1,%GWL_WndProc, oldProc
             SETWINDOWLONG hCtrl2,%GWL_WndProc, oldProc
           END SELECT
        END FUNCTION
        
        FUNCTION PBMAIN
           LOCAL hDlg AS DWORD 
           DIALOG NEW 0,"Themed sub-classed buttons",,,150,100,%WS_CAPTION OR %WS_SYSMENU TO hDlg
           CONTROL ADD BUTTON, hDlg, 100, "",5,20,50,14 
           CONTROL ADD BUTTON, hDlg, 101, "",5,40,50,30 
           CONTROL ADD BUTTON, hDlg, 102, "Standard",5,80,50,14 'standard button for comparison
           DIALOG SHOW MODAL hDlg, CALL ButtonProc  
        END FUNCTION

        Comment


        • #5
          Just tried Simon's code and, hitting Left-Alt or one of the
          Arrow-Keys, encountered a problem with disappearing text and icon
          of both subclassed buttons, respectively (XP/PB8). The problem
          was cured after replacing

          "IF wMsg=%WM_PAINT THEN"
          with
          "IF wMsg=%WM_PAINT OR wMsg=%WM_UPDATEUISTATE THEN"

          I hope there are no objections...

          Thanks, Simon, for your code. This subclassing thing was really
          over my head!

          Regards, Hanns.


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


          [This message has been edited by Hanns Ackermann (edited September 23, 2006).]

          Comment


          • #6
            Glad you found it useful, Hanns. Thanks for improving my code.

            I'd never come across %WM_UPDATEUISTATE before. I see it only came in with Win 2000. MSDN:
            An application sends the WM_UPDATEUISTATE message to change the user interface (UI) state for the specified window and all its child windows.
            Hmm, not quite sure what that means in practical terms. Hitting Alt causes the keyboard accelerator characters to be underlined, which is presumably achieved with this message, but not sure why the arrow keys cause it to be sent.

            Also, I would have thought that %WM_UPDATEUISTATE would cause a %WM_Paint to be generated if a button needed to change its appearance, but obviously not.

            Comment


            • #7
              Perhaps the "correct" method would be to call RedrawWindow in response to WM_UPDATEUISTATE?

              ------------------
              kgpsoftware.com
              Slam Database Manager - simple, but effective database system.
              PrpT Property List - kiss those complex 'options dialogs' goodbye!
              kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

              Comment


              • #8
                Didn't Jose or one of those guys post something to do just this on
                their forum??? I got the code in a zip file right in front of me.

                Even handles themed and no theme and does very nice.

                ------------------
                If you aim at nothing...you will hit it.
                sigpic
                Mobile Solutions
                Sys Analyst and Development

                Comment


                • #9
                  Theme aware XP push button that can also act as a toggle button and
                  display an icon or bitmap.

                  http://www.forum.it-berater.org/index.php?topic=11.0


                  ------------------
                  Website: http://com.it-berater.org
                  SED Editor, TypeLib Browser, COM Wrappers.
                  Forum: http://www.forum.it-berater.org
                  Forum: http://www.jose.it-berater.org/smfforum/index.php

                  Comment


                  • #10
                    See...when all else fails, ask Jose. If he can't fix it, it's broke.

                    ------------------
                    If you aim at nothing...you will hit it.
                    sigpic
                    Mobile Solutions
                    Sys Analyst and Development

                    Comment

                    Working...
                    X