Page 1 of 1
Drawing custom themed buttons
Posted: Wed Feb 15, 2006 5:13 am
by AlexSchaft
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
Posted: Wed Feb 15, 2006 12:41 pm
by Antonio Linares
Alex,
You may use a Class TButtonBmp button. Please review samples\TestBuBm.prg
XP Button bitmaps
Posted: Wed Feb 15, 2006 2:02 pm
by AlexSchaft
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
Themed button
Posted: Wed Feb 15, 2006 2:42 pm
by AlexSchaft
Hi,
Below is some cpp code that does it:
Code: Select all
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);
}
New class help
Posted: Thu Feb 16, 2006 6:39 am
by AlexSchaft
Hi,
I created a new class based on tpanel, in which the paint event becomes:
Code: Select all
METHOD Paint() CLASS QButton
DrawQBBackground(::hWnd, ::hDc)
RETURN NIL
DrawQBBackground comes from:
Code: Select all
#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
Re: New class help
Posted: Thu Feb 16, 2006 8:42 am
by Enrico Maria Giordano
Try
Perils of the cast.
EMG
Themed button working
Posted: Sat Feb 18, 2006 6:17 am
by AlexSchaft
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?
Code: Select all
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
Re: Themed button working
Posted: Sat Feb 18, 2006 12:40 pm
by Enrico Maria Giordano
Try adding hb prefix to all the _par* and _ret* functions.
EMG
Themed button working
Posted: Sat Feb 18, 2006 12:49 pm
by AlexSchaft
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
Re: Themed button working
Posted: Sat Feb 18, 2006 12:54 pm
by Enrico Maria Giordano
Have a look at how tooltips are managed. Or TBtnBmp states.
EMG
Got it
Posted: Sat Feb 18, 2006 1:05 pm
by AlexSchaft
Hi,
It's working now, thanks.
Re: Got it
Posted: Sat Feb 18, 2006 1:08 pm
by Enrico Maria Giordano
How you solved the problem?
EMG
Working button
Posted: Sat Feb 18, 2006 1:18 pm
by AlexSchaft
I copied the whole btnbmp mousemove event, and removed everything I didn't need
Code: Select all
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:
Code: Select all
#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);
}
}
Re: Working button
Posted: Sat Feb 18, 2006 1:24 pm
by Enrico Maria Giordano
Great!
EMG