📄 xptabctrl.cpp
字号:
#include "StdAfx.h"
#include "XPTabCtrl.h"
#include "..\StudentRecords.h"
#include "..\IndexSet.h"
#include "..\InputData.h"
#include "..\QueryData.h"
#include "..\PaiTxtData.h"
#include "..\About.h"
//#define USE_DEFAULT_XP_TOPTAB // XP top tab is drawn only for test purpose. To use default, uncoment this line
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/***********************************************************************************************************/
// constant string definitions here (or you can put it into resource string table)
#define IDS_UTIL_TAB "TAB"
#define IDS_UTIL_UXTHEME "UxTheme.dll"
#define IDS_UTIL_THEMEACT "IsThemeActive"
#define IDS_UTIL_THEMEOPN "OpenThemeData"
#define IDS_UTIL_THEMEBCKG "DrawThemeBackground"
/***********************************************************************************************************/
// CXPTabCtrl
/***********************************************************************************************************/
CXPTabCtrl::CXPTabCtrl()
{
m_bTabExtended=TRUE; // default is to use extended tab (if it is Themes XP)
m_eTabOrientation=e_tabBottom; // default initial orientation is: bottom
m_ixSelOld=-1;
m_tabPages[0]=new CIndexSet;
m_tabPages[1]=new CInputData;
m_tabPages[2]=new CQueryData;
m_tabPages[3]=new CPaiTxtData;
m_tabPages[4]=new CAboutDlg;
m_nNumberOfPages=5;
}
CXPTabCtrl::~CXPTabCtrl()
{
for(int nCount=0; nCount < m_nNumberOfPages; nCount++)
{
delete m_tabPages[nCount];
}
}
//----------------------------------------------------------------------------------------------------------
// nBitmapID Resource IDs of the bitmap to be associated with the image list.
void CXPTabCtrl::InitImageList(UINT nBitmapID)
{
if(!::IsWindow(GetSafeHwnd()) || m_ilTabs.operator HIMAGELIST())
{ ASSERT(FALSE); return; } // tab control has to be created first and image list can be created only once
if(m_ilTabs.Create(nBitmapID, 16, 1, RGB(0xFF,0,0xFF))) // add an images list with appropriate background (transparent) color
SetImageList(&m_ilTabs);
}
//----------------------------------------------------------------------------------------------------------
// only three messages used
BEGIN_MESSAGE_MAP(CXPTabCtrl, CTabCtrl)
//{{AFX_MSG_MAP(CXPTabCtrl)
ON_WM_PAINT()
ON_NOTIFY_REFLECT(TCN_SELCHANGING,OnTabSelChanging)
ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnTabSelChanged)
//}}AFX_MSG_MAP
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
//----------------------------------------------------------------------------------------------------------
void CXPTabCtrl::OnPaint()
{
if(!IsExtendedTabTheamedXP()) // if it is not XP or it is not Themes, behave as default
{ Default(); return; }
CPaintDC dc(this); // device context for painting
CRect rcClip; rcClip.SetRectEmpty();
dc.GetClipBox(rcClip);
// 1st paint the tab body
CRect rcPage,rcItem,rcClient;
GetClientRect(&rcPage);
rcClient=rcPage;
AdjustRect(FALSE,rcPage);
switch(m_eTabOrientation)
{ case e_tabTop: rcClient.top =rcPage.top -2; break;
case e_tabBottom: rcClient.bottom=rcPage.bottom+3; break;
case e_tabLeft: rcClient.left =rcPage.left -1; break;
case e_tabRight: rcClient.right =rcPage.right +3; break;
default: ASSERT(FALSE); return;
}
UINT uiVertBottm;
uiVertBottm =(m_eTabOrientation&1)? 8:0; // 8=bottom
uiVertBottm|=(m_eTabOrientation&2)?16:0; // 16=vertical
UINT uiFlags=1|uiVertBottm; // 1=body
DrawThemesXpTabItem(&dc, -1, rcClient,uiFlags); // TABP_PANE=9,0,'TAB'
int nTab=GetItemCount(); // paint the tabs first and then the borders
if(!nTab) return; // no tab pages added
// 2nd paint the inactive tabs
CRect ;
TCHITTESTINFO hti; hti.flags=0;
::GetCursorPos(&hti.pt); ScreenToClient(&hti.pt);
int ixHot=HitTest(&hti);
int ixSel=GetCurSel();
for(int ixTab=0; ixTab<nTab; ixTab++)
{ if(ixTab==ixSel)
continue;
VERIFY(GetItemRect(ixTab, &rcItem));
if(m_eTabOrientation==e_tabLeft) rcItem.right++;
uiFlags=uiVertBottm|(ixTab==ixHot?4:0); // 4= hot
DrawThemesXpTabItem(&dc,ixTab,rcItem,uiFlags);
}
// 3rd paint the active selected tab
VERIFY(GetItemRect(ixSel, &rcItem)); // now selected tab
rcItem.InflateRect(2,2);
if(m_eTabOrientation==e_tabTop) rcItem.bottom--;
uiFlags=uiVertBottm|2; // 2= selected
DrawThemesXpTabItem(&dc, ixSel, rcItem,uiFlags);
}
//----------------------------------------------------------------------------------------------------------
// This function draws Themes Tab control parts: a) Tab-Body and b) Tab-tabs
void CXPTabCtrl::DrawThemesXpTabItem(CDC* pDC, int ixItem, const CRect& rcItem, UINT uiFlag)
{ // uiFlag(1/0):1=Type(body/tab);2=Sel(y/n);4=Hot(y/n);8=bBottom(y/n);16=rotate(y/n)
BOOL bBody =(uiFlag& 1)?TRUE:FALSE;
BOOL bSel =(uiFlag& 2)?TRUE:FALSE;
BOOL bHot =(uiFlag& 4)?TRUE:FALSE;
BOOL bBottom=(uiFlag& 8)?TRUE:FALSE; // mirror
BOOL bVertic=(uiFlag&16)?TRUE:FALSE; // rotate
BOOL bLeftTab=!bBottom && bVertic && !bBody;
CSize szBmp=rcItem.Size();
if(bVertic) SwapVars(szBmp.cx,szBmp.cy);
// 1st draw background
CDC dcMem; dcMem .CreateCompatibleDC(pDC);
CBitmap bmpMem; bmpMem.CreateCompatibleBitmap(pDC,szBmp.cx,szBmp.cy);
CBitmap* pBmpOld=dcMem.SelectObject(&bmpMem);
CRect rcMem(CPoint(0,0),szBmp); if(bSel) rcMem.bottom++;
if(bBody)
DrawThemesPart(dcMem.GetSafeHdc(), 9, 0, (LPCSTR)IDS_UTIL_TAB, &rcMem); // TABP_PANE=9, 0, 'TAB'
else DrawThemesPart(dcMem.GetSafeHdc(), 1, bSel?3:(bHot?2:1), (LPCSTR)IDS_UTIL_TAB, &rcMem);
// TABP_TABITEM=1, TIS_SELECTED=3:TIS_HOT=2:TIS_NORMAL=1, 'TAB'
// 2nd init some extra parameters
BITMAPINFO biOut; ZeroMemory(&biOut,sizeof(BITMAPINFO)); // Fill local pixel arrays
BITMAPINFOHEADER& bihOut=biOut.bmiHeader;
bihOut.biSize =sizeof (BITMAPINFOHEADER);
bihOut.biCompression=BI_RGB;
bihOut.biPlanes=1; bihOut.biBitCount=24; // force as RGB: 3 bytes,24 bits -> good for rotating bitmap in any resolution
bihOut.biWidth =szBmp.cx; bihOut.biHeight=szBmp.cy;
int nBmpWdtPS=DWordAlign(szBmp.cx*3);
int nSzBuffPS=((nBmpWdtPS*szBmp.cy)/8+2)*8;
LPBYTE pcImg=NULL;
if(bBottom || bVertic) { pcImg=new BYTE[nSzBuffPS]; ASSERT(pcImg); }
int nStart=0,nLenSub=0;
if(bBody && bBottom && !bVertic) nStart=3,nLenSub=4; // if bottom oriented flip the body contest only (no shadows were flipped)
// 3rd if it is left oriented tab, draw tab context before mirroring or rotating (before GetDIBits)
if(bVertic)
{ if(bBody || !bBottom) bihOut.biHeight=-szBmp.cy;
if(!bBottom && !bBody && ixItem>=0) //
{ if(bSel) rcMem.bottom--;
DrawTabItem(&dcMem, ixItem, rcMem, uiFlag); ixItem=-1;
} } // rotate or mirror
// 4th get bits (for rotate) and mirror: body=(all except top) tab=(all except top)
if(bVertic || bBottom) // get bits:
{ GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
if(bBottom) // mirror: body=(bottom and right) tab=(bottom and right)
{ bihOut.biHeight=-szBmp.cy; // to mirror bitmap is eough to use negative height between Get/SetDIBits
SetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
if(bBody && bVertic) // when it is right oriented body -> flip twice, first flip border shadows, than flip shaded inside body again
{ nStart=2; nLenSub=4; bihOut.biHeight=szBmp.cy;
GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
bihOut.biHeight=-szBmp.cy; // to mirror bitmap is eough to use negative height between Get/SetDIBits
SetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
} } }
// 5th if it is bottom or right oriented tab, draw after mirroring background (do GetDIBits again)
if(!bBody && ixItem>=0) //
{ if(bSel) rcMem.bottom--;
DrawTabItem(&dcMem, ixItem, rcMem, uiFlag);
if(bVertic) // if it is right tab, do GetDIBits again
{ bihOut.biHeight=-szBmp.cy;
GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
} }
// 6th: do rotate now, finaly
if(bVertic) // force rotating bitmap as RGB -> good for any resolution
{ SwapVars(szBmp.cx,szBmp.cy);
int nBmpWdtPD=DWordAlign(szBmp.cx*3);
int nPadD=nBmpWdtPD-szBmp.cx*3;
int nSzBuffPD=((nBmpWdtPD*szBmp.cy)/8+2)*8;
LPBYTE pcImgRotate=new BYTE[nSzBuffPD]; ASSERT(pcImgRotate);
int nWidth,nHeight=szBmp.cy,nHeight1=nHeight-1;
//====================================
//------------------------------------
// here is the example how to speed up lengthy repeatetive processing by using inline assembler
#define __USE_MASM__ // the same processing is in C and in asm. To use C -> comment the beginning of this line
// Do the actual whole RGB bitmap rotating in C or assembler
#ifndef __USE_MASM__
LPBYTE pcImgS=pcImg;
LPBYTE pcImgD=pcImgRotate;
int ixHeight=0;
BOOL bLast=FALSE;
while(ixHeight<nHeight) // for all destination height lines
{ nWidth=szBmp.cx;
if(ixHeight==nHeight1) { bLast=TRUE; nWidth--; }
while(nWidth--)
{ *(PDWORD)pcImgD=*(PDWORD)pcImgS; // do all Rgb triplets read/write qicker as DWORD
pcImgS+=nBmpWdtPS; // increment source in padded source lines
pcImgD+=3; // increment destination in rgb triplets
}
if(bLast) // when the last line, the last pixel - colud be a problem if bitmap DWORD alligned
for(int c=3;c;c--) *pcImgD++=*pcImgS++; // (only last three bytes available->could not read/write DWORD)!!
else
{ ixHeight++;
pcImgD+=nPadD; // destination bitmap horizontal padding to DWORD
pcImgS=pcImg+(ixHeight*3); // reset the source to the begining of the next vertical line
} }
#else // __USE_MASM__
nBmpWdtPS-=4; // adjust esi increment (due to esi self-incrementing by movsd)
nWidth=szBmp.cx;
__asm
{ mov esi, pcImg // source index
mov edi, pcImgRotate // destination index
xor ebx, ebx // vertical counter
loop_height:
mov ecx, nWidth // horizontal counter
cmp ebx, nHeight1 // check is it the last line
jne loop_width
dec ecx // if it is decremnt for the last pixel
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -