FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Drawing custom themed buttons
Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Drawing custom themed buttons
Posted: Wed Feb 15, 2006 05:13 AM

Hi,

Apps like Windows Media player add a button to the title bar, that removes the outside frame of its window. Other apps draw a button to minimize to tray. All these are coloured according to the current xp colour theme

I don't want to put one in the title bar. I'd just like a button like the combobox to put next to a get control, which has a browse attached to it.

Has anyone done something like this, or stumbled across a way of doing this?

I don't want to keep a copy of the combo box button as a bmp, because the colours can change.

Alex

Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Drawing custom themed buttons
Posted: Wed Feb 15, 2006 12:41 PM

Alex,

You may use a Class TButtonBmp button. Please review samples\TestBuBm.prg

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
XP Button bitmaps
Posted: Wed Feb 15, 2006 02:02 PM

Hi,

I know about those, but I want a button drawn that looks like the xp combobox arrow button. It must also use the colours of the current xp theme (like blue, silver and olive green defaults)

Alex

Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Themed button
Posted: Wed Feb 15, 2006 02:42 PM
Hi,

Below is some cpp code that does it:

TEMPLATE void CDialogMinTrayBtn<BASE>::MinTrayBtnDraw()
{
    if (!MinTrayBtnIsVisible())
       return;

    CDC *pDC= GetWindowDC();
    if (!pDC)
       return; // panic!

    if (IsWindowsClassicStyle())
    {
        CBrush black(GetSysColor(COLOR_BTNTEXT));
        CBrush gray(GetSysColor(COLOR_GRAYTEXT));
        CBrush gray2(GetSysColor(COLOR_BTNHILIGHT));

        // button
        if (m_bMinTrayBtnUp)
           pDC->DrawFrameControl(MinTrayBtnGetRect(), DFC_BUTTON, DFCS_BUTTONPUSH);
        else
           pDC->DrawFrameControl(MinTrayBtnGetRect(), DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED);

        // dot
        CRect btn = MinTrayBtnGetRect();
        btn.DeflateRect(2,2);
        UINT caption = MinTrayBtnGetSize().cy + (CAPTION_BUTTONSPACE * 2);
        UINT pixratio = (caption >= 14) ? ((caption >= 20) ? 2 + ((caption - 20) / 8) : 2) : 1;
        UINT pixratio2 = (caption >= 12) ? 1 + (caption - 12) / 8: 0;
        UINT dotwidth = (1 + pixratio * 3) >> 1;
        UINT dotheight = pixratio;
        CRect dot(CPoint(0,0), CPoint(dotwidth, dotheight));
        CSize spc((1 + pixratio2 * 3) >> 1, pixratio2);
        dot -= dot.Size();
        dot += btn.BottomRight();
        dot -= spc;
        if (!m_bMinTrayBtnUp)
           dot += CPoint(1,1);
        if (m_bMinTrayBtnEnabled)
        {
           pDC->FillRect(dot, &black);
        }
        else
        {
           pDC->FillRect(dot + CPoint(1,1), &gray2);
           pDC->FillRect(dot, &gray);
        }
    }
	else
	{
		// VisualStylesXP
		CRect btn = MinTrayBtnGetRect();
		int iState;
		if (!m_bMinTrayBtnEnabled)
			iState = TRAYBS_DISABLED;
		else if (GetStyle() & WS_DISABLED)
			iState = MINBS_NORMAL;
		else if (m_bMinTrayBtnHitTest)
			iState = (m_bMinTrayBtnCapture) ? MINBS_PUSHED : MINBS_HOT;
		else
			iState = MINBS_NORMAL;
		// inactive
		if (!m_bMinTrayBtnActive)
			iState += 4; // inactive state TRAYBS_Ixxx

		if (m_bmMinTrayBtnBitmap.m_hObject && _TransparentBlt)
		{
			// known theme (bitmap)
			CBitmap *pBmpOld;
			CDC dcMem;
			if (dcMem.CreateCompatibleDC(pDC) && (pBmpOld = dcMem.SelectObject(&m_bmMinTrayBtnBitmap)) != NULL)
			{
				_TransparentBlt(pDC->m_hDC, btn.left, btn.top, btn.Width(), btn.Height(), dcMem.m_hDC, 0, BMP_TRAYBTN_HEIGHT * (iState - 1), BMP_TRAYBTN_WIDTH, BMP_TRAYBTN_HEIGHT, BMP_TRAYBTN_TRANSCOLOR);
				dcMem.SelectObject(pBmpOld);
			}
		}
		else
		{
			// unknown theme (ThemeData)
			HTHEME hTheme = g_xpStyle.OpenThemeData(m_hWnd, L"Window");
			if (hTheme)
			{
				btn.top += btn.Height() / 8;
				g_xpStyle.DrawThemeBackground(hTheme, pDC->m_hDC, WP_TRAYBUTTON, iState, &btn, NULL);
				g_xpStyle.CloseThemeData(hTheme);
			}
		}
	}

    ReleaseDC(pDC);
}
Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
New class help
Posted: Thu Feb 16, 2006 06:39 AM
Hi,

I created a new class based on tpanel, in which the paint event becomes:

METHOD Paint() CLASS QButton

  DrawQBBackground(::hWnd, ::hDc)

RETURN NIL


DrawQBBackground comes from:

#include <WinTen.h>
#include <Windows.h>
#include <ClipApi.h>

#ifdef __FLAT__
   #include <ShellApi.h>
#endif

#ifdef __HARBOUR__
   #include <hbapiitm.h>
   #include <hbdate.h>
   #include <hbset.h>
#endif
#include "uxtheme.h"

HB_FUNC( DRAWQBBACKGROUND )
{
   HTHEME hTheme;
   HDC hDc;
   HWND hWnd;
   RECT rcWnd;
   int iStateId = 1;

   hWnd    = ( HWND ) _parnl( 1 );
   hDc = ( HDC ) _parl(2);

   GetClientRect( hWnd, &rcWnd );

   hTheme = OpenThemeData(hWnd, L"BUTTON");

   if ( hTheme)
   {
      DrawThemeBackground(hTheme,
                    hDc,
                    0,
                    0,
                    &rcWnd,
                    NULL);
    _retni(1);
   }
   else
   {
    _retni(0);
   }

}


Unfortunately, I don't see anything :-)

Is there a C wizard which can help me out here
Posts: 9020
Joined: Thu Oct 06, 2005 08:17 PM
Re: New class help
Posted: Thu Feb 16, 2006 08:42 AM
AlexSchaft wrote:
hDc = ( HDC ) _parl(2);


Try

hDc = ( HDC ) _parnl(2);


Perils of the cast. :-)

EMG
Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Themed button working
Posted: Sat Feb 18, 2006 06:17 AM
Thanks, that change works, along with changing the first zero to 1 in the DrawThemeBackground call, and the second parameter is 1 for normal 2 for "hot", 3 for down, and 4 for disabled.

Only problem now is detecting when mouse leaves the control. I've copied the basics from btnbmp:mousemove but no luck so far. What am I missing?

METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS QButton

//   Super:MouseMove( nRow, nCol, nKeyFlags )


   if IsOverWnd( ::hWnd, nRow, nCol )
      ::nState := 2
   else
      ::nState := 1
   endif

   ::Refresh()
return nil
//---------------------------------------------------------------------------------------------//
METHOD Paint() CLASS QButton

  // 1 Regular
  // 2 Mouse over
  // 3 Down
  // 4 Disabled

  DrawQBBackground(::hWnd, ::hDc, ::nState)

RETURN NIL
Posts: 9020
Joined: Thu Oct 06, 2005 08:17 PM
Re: Themed button working
Posted: Sat Feb 18, 2006 12:40 PM

Try adding hb prefix to all the _par and _ret functions.

EMG

Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Themed button working
Posted: Sat Feb 18, 2006 12:49 PM

I don't have a problem in my C code anymore. It links and works perfectly. I now need to detect in my control events when the mouse leaves my control.

I suppose you receive mousemove while in the control, but what do you receive when the mouse moves out of the control?

Alex

Posts: 9020
Joined: Thu Oct 06, 2005 08:17 PM
Re: Themed button working
Posted: Sat Feb 18, 2006 12:54 PM

Have a look at how tooltips are managed. Or TBtnBmp states.

EMG

Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Got it
Posted: Sat Feb 18, 2006 01:05 PM

Hi,

It's working now, thanks.

Posts: 9020
Joined: Thu Oct 06, 2005 08:17 PM
Re: Got it
Posted: Sat Feb 18, 2006 01:08 PM

How you solved the problem?

EMG

Posts: 172
Joined: Fri Oct 07, 2005 01:29 PM
Working button
Posted: Sat Feb 18, 2006 01:18 PM
I copied the whole btnbmp mousemove event, and removed everything I didn't need :-)

METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS QButton

   if ::lDrag .or. ! Empty( ::oDragCursor )
      return Super:MouseMove( nRow, nCol, nKeyFlags )
   endif

   Super:MouseMove( nRow, nCol, nKeyFlags )

   if IsOverWnd( ::hWnd, nRow, nCol )
      if !::lCaptured
        ::Capture()
        if ::nState != 2
          ::nState := 2
          ::Refresh()
        endif
      else
        ::Refresh()
      endif
   else
      if !::lCaptured
         ReleaseCapture()
        if ::nState != 1
          ::nState := 1
          ::Refresh()
        endif
      else
        ::Refresh()
      endif
   endif

   ::oWnd:SetMsg( ::cMsg )

return 0
//---------------------------------------------------------------------------------------------//
METHOD Paint() CLASS QButton

  // 1 Regular
  // 2 Mouse over
  // 3 Down
  // 4 Disabled

  DrawQBBackground(::hWnd, ::hDc, ::nState)

RETURN NIL


C Code:
#include <WinTen.h>
#include <Windows.h>
#include <ClipApi.h>

#ifdef __FLAT__
   #include <ShellApi.h>
#endif

#ifdef __HARBOUR__
   #include <hbapiitm.h>
   #include <hbdate.h>
   #include <hbset.h>
#endif
#include "uxtheme.h"

HB_FUNC( DRAWQBBACKGROUND )
{
   HTHEME hTheme;
   HDC hDc;
   HWND hWnd;
   RECT rcWnd;
   int iStateId = 1;

   hWnd    = ( HWND ) _parnl( 1 );
   hDc = ( HDC ) _parnl(2);

   GetClientRect( hWnd, &rcWnd );

   hTheme = OpenThemeData(hWnd, L"COMBOBOX");

   if ( hTheme)
   {
      DrawThemeBackground(hTheme,
                    hDc,
                    1,
                    ( ISNUM(3) ? _parni( 3 ) : 1 ),
                    &rcWnd,
                    NULL);

    CloseThemeData(hTheme);
    _retni(1);
   }
   else
   {
    _retni(0);
   }

}
Posts: 9020
Joined: Thu Oct 06, 2005 08:17 PM

Continue the discussion