Windows2003-3790/termsrv/newclient/core/bbar.cpp
2020-09-30 16:53:55 +02:00

1961 lines
53 KiB
C++

//
// bbar.cpp
//
// Implementation of CBBar
// Drop down connection status + utility bar
//
// Copyright(C) Microsoft Corporation 2000
// Author: Nadim Abdo (nadima)
//
//
#include "adcg.h"
#ifdef USE_BBAR
#define TRC_GROUP TRC_GROUP_UI
#define TRC_FILE "bbar"
#include <atrcapi.h>
#include "bbar.h"
#include "commctrl.h"
#ifndef OS_WINCE
#define BBAR_CLASSNAME _TEXT("BBARCLASS")
#else
#define BBAR_CLASSNAME _T("BBARCLASS")
#endif
#define IDM_MINIMIZE 101
#define IDM_RESTORE 102
#define IDM_CLOSE 103
#define IDM_PIN 104
//
// BBar is 50% of parent's width
//
#define BBAR_PERCENT_WIDTH 50
#define BBAR_NUM_BUTTONS 3
#define BBAR_BUTTON_WIDTH 12
#define BBAR_BUTTON_HEIGHT 11
#define BBAR_BUTTON_SPACE 3
#define BBAR_MIN_HEIGHT 16
//
// Two pixels of vertical space are
// unavailable (due to lines at bottom)
//
#define BBAR_VERT_SPACE_NO_USE 3
#define COLOR_BLACK RGB(0,0,0)
#define COLOR_DKGREY RGB(128,128,128)
#ifndef OS_WINCE
#define BBAR_TIMERID_ANIM 0
#else
#define BBAR_TIMERID_ANIM (WM_USER + 1001)
#endif
#define BBAR_TIMERID_AUTOHIDE 1
//
// Total animation period for animation (E.g lower)
// in milliseconds
//
#define BBAR_ANIM_TIME 300
#define BBAR_AUTOHIDE_TIME 1400
#define BBAR_FIRST_AUTOHIDE_TIME 5000
CBBar::CBBar(HWND hwndParent, HINSTANCE hInstance, CUI* pUi,
BOOL fBBarEnabled)
{
DC_BEGIN_FN("CBBar");
_hwndBBar = NULL;
_hwndParent = hwndParent;
_hInstance = hInstance;
_state = bbarNotInit;
_pUi = pUi;
_fBlockZOrderChanges = FALSE;
_nBBarVertOffset = 0;
_ptLastAutoHideMousePos.x = -0x0FF;
_ptLastAutoHideMousePos.y = -0x0FF;
_nBBarAutoHideTime = 0;
_hwndPinBar = NULL;
_hwndWinControlsBar = NULL;
_fPinned = FALSE;
_nPinUpImage = 0;
_nPinDownImage = 0;
_hbmpLeftImage = NULL;
_hbmpRightImage = NULL;
_fBBarEnabled = fBBarEnabled;
_fLocked = FALSE;
_fShowMinimize = TRUE;
_fShowRestore = TRUE;
SetDisplayedText(_T(""));
DC_END_FN();
}
CBBar::~CBBar()
{
}
BOOL CBBar::StartupBBar(int desktopX, int desktopY, BOOL fStartRaised)
{
BOOL bRet = FALSE;
DC_BEGIN_FN("StartupBBar");
if(bbarNotInit == _state)
{
// First drop interval is long
_nBBarAutoHideTime = BBAR_FIRST_AUTOHIDE_TIME;
bRet = Initialize( desktopX, desktopY, fStartRaised );
if(!bRet)
{
return FALSE;
}
}
else
{
// First drop interval is long
_nBBarAutoHideTime = BBAR_AUTOHIDE_TIME;
//re-init existing bbar
BringWindowToTop( _hwndBBar );
ShowWindow( _hwndBBar, SW_SHOWNOACTIVATE);
//
// Bring the window to the TOP of the Z order
//
SetWindowPos( _hwndBBar,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
bRet = TRUE;
}
//
// Note: The bbar is used as a security feature so we do the initial
// drop even if the bbar feature is not enabled. It's only subsequent
// drops (e.g. on the timer) that are disabled if bbar is OFF
//
if(_pUi->UI_IsFullScreen())
{
//First autohide interval is long
//to make sure user gets to notice the bbar
StartLowerBBar();
}
DC_END_FN();
return bRet;
}
//
// Destroy the window and reset bbar state
// for another session
//
BOOL CBBar::KillAndCleanupBBar()
{
BOOL fRet = TRUE;
DC_BEGIN_FN("KillAndCleanupBBar");
if(_state != bbarNotInit)
{
TRC_NRM((TB,_T("Cleaning up the bbar")));
if(_hwndBBar)
{
if(::DestroyWindow( _hwndBBar ))
{
_state = bbarNotInit;
_hwndBBar = NULL;
_fBlockZOrderChanges = FALSE;
if(!UnregisterClass( BBAR_CLASSNAME, _hInstance ))
{
TRC_ERR((TB,_T("UnregisterClass bbar class failed 0x%x"),
GetLastError()));
}
}
else
{
TRC_ERR((TB,_T("DestroyWindow bbar failed 0x%x"),
GetLastError()));
fRet = FALSE;
}
if (_hbmpLeftImage)
{
DeleteObject(_hbmpLeftImage);
_hbmpLeftImage = NULL;
}
if (_hbmpRightImage)
{
DeleteObject(_hbmpRightImage);
_hbmpRightImage = NULL;
}
}
}
DC_END_FN();
return fRet;
}
BOOL CBBar::StartLowerBBar()
{
INT parentWidth = 0;
RECT rc;
DC_BEGIN_FN("StartLowerBBar");
if(_state == bbarRaised)
{
//
// Kick off a timer to lower the bar
//
TRC_ASSERT(0 == _nBBarVertOffset,
(TB,_T("_nBBarVertOffset (%d) should be 0"),
_nBBarVertOffset));
TRC_ASSERT(_hwndBBar,
(TB,_T("_hwndBBar is NULL")));
//
// Set the last cursor pos at the time
// the bbar is lowered to prevent it from being
// autohidden if the mouse doesn't move
//
GetCursorPos(&_ptLastAutoHideMousePos);
//
// Main window size could have changed
// so make sure the bbar is centered
// before lowering it.
// (keep constant bbar width)
if(_pUi->_UI.hwndMain)
{
GetClientRect(_pUi->_UI.hwndMain, &rc);
parentWidth = rc.right - rc.left;
if(!parentWidth)
{
return FALSE;
}
_rcBBarLoweredAspect.left = parentWidth / 2 - _sizeLoweredBBar.cx / 2;
_rcBBarLoweredAspect.right = parentWidth / 2 + _sizeLoweredBBar.cx / 2;
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
_pUi->UI_OnNotifyBBarRectChange(&_rcBBarLoweredAspect);
_pUi->UI_OnNotifyBBarVisibleChange(1);
#endif
}
#ifndef OS_WINCE
if(!SetTimer( _hwndBBar, BBAR_TIMERID_ANIM,
BBAR_ANIM_TIME / _sizeLoweredBBar.cy,
NULL ))
{
TRC_ERR((TB,_T("SetTimer failed - 0x%x"),
GetLastError()));
return FALSE;
}
_state = bbarLowering;
#else
ImmediateLowerBBar();
#endif
return TRUE;
}
else
{
TRC_NRM((TB,_T("StartLowerBBar called when bar in wrong state 0x%x"),
_state));
return FALSE;
}
DC_END_FN();
}
BOOL CBBar::StartRaiseBBar()
{
DC_BEGIN_FN("StartRaiseBBar");
if(_state == bbarLowered && !_fPinned && !_fLocked)
{
//
// Kick off a timer to lower the bar
//
TRC_ASSERT(_sizeLoweredBBar.cy == _nBBarVertOffset,
(TB,_T("_nBBarVertOffset (%d) should be %d"),
_nBBarVertOffset,
_sizeLoweredBBar.cy));
TRC_ASSERT(_hwndBBar,
(TB,_T("_hwndBBar is NULL")));
#ifndef OS_WINCE
if(!SetTimer( _hwndBBar, BBAR_TIMERID_ANIM,
BBAR_ANIM_TIME / _sizeLoweredBBar.cy,
NULL ))
{
TRC_ERR((TB,_T("SetTimer failed - 0x%x"),
GetLastError()));
return FALSE;
}
_state = bbarRaising;
#else
ImmediateRaiseBBar();
#endif
return TRUE;
}
else
{
TRC_NRM((TB,_T("StartRaiseBBar called when bar in wrong state 0x%x"),
_state));
return FALSE;
}
DC_END_FN();
return TRUE;
}
BOOL CBBar::Initialize(int desktopX, int desktopY, BOOL fStartRaised)
{
#ifndef OS_WINCE
RECT rc;
#endif
HWND hwndBBar;
int parentWidth = desktopX;
int bbarHeight = 0;
int bbarWidth = 0;
DC_BEGIN_FN("Initialize");
TRC_ASSERT( bbarNotInit == _state,
(TB,_T("bbar already initialized - state:0x%x"),
_state));
//
// Compute BBAR position based on remote desktop size
//
#ifndef OS_WINCE
bbarHeight = GetSystemMetrics( SM_CYMENUSIZE ) + 2;
#else
bbarHeight = GetSystemMetrics( SM_CYMENU ) + 2;
#endif
bbarHeight = max(bbarHeight, BBAR_MIN_HEIGHT);
_rcBBarLoweredAspect.bottom = bbarHeight;
_rcBBarLoweredAspect.left = (LONG)( (100 - BBAR_PERCENT_WIDTH) / 200.0 *
parentWidth );
_rcBBarLoweredAspect.right = parentWidth - _rcBBarLoweredAspect.left;
_rcBBarLoweredAspect.top = 0;
bbarWidth = _rcBBarLoweredAspect.right - _rcBBarLoweredAspect.left;
_sizeLoweredBBar.cx = bbarWidth;
_sizeLoweredBBar.cy = bbarHeight;
hwndBBar = CreateWnd( _hInstance, _hwndParent,
&_rcBBarLoweredAspect );
if(hwndBBar)
{
if( fStartRaised )
{
//
// Move the bar up by it's height to raise it
//
if(SetWindowPos(hwndBBar,
NULL,
_rcBBarLoweredAspect.left, //x
-_sizeLoweredBBar.cy, //y
0,0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
{
TRC_NRM((TB,_T("BBAR SetWindowPos failed - 0x%x"),
GetLastError()));
}
}
BringWindowToTop( hwndBBar );
ShowWindow( hwndBBar, SW_SHOWNOACTIVATE);
//
// Create the polygon region for the bounds of the BBar window
// This cuts the corners off the edges.
//
POINT pts[4];
int xOffset = parentWidth / 2 - _rcBBarLoweredAspect.left;
pts[3].x = -bbarWidth/2 + xOffset;
pts[3].y = 0;
pts[2].x = bbarWidth/2 + xOffset;
pts[2].y = 0;
pts[1].x = bbarWidth/2 - bbarHeight + xOffset;
pts[1].y = bbarHeight;
pts[0].x = -bbarWidth/2 + bbarHeight + xOffset;
pts[0].y = bbarHeight;
#ifndef OS_WINCE
//
// Polygon does not self intersect so winding mode is not
// relevant
//
HRGN hRgn = CreatePolygonRgn( pts,
4,
ALTERNATE );
#else
HRGN hRgn = GetBBarRgn(pts);
#endif
if(hRgn)
{
if(!SetWindowRgn( hwndBBar, hRgn, TRUE))
{
TRC_ERR((TB,_T("SetWindowRgn failed - 0x%x"),
GetLastError()));
//
// In the success case the system will free
// the region handle when it is done with it.
// Here however, the call failed...
//
DeleteObject( hRgn );
}
}
else
{
//
// Not fatal, continue
//
TRC_ERR((TB,_T("CreatePolygonRgn failed - 0x%x"),
GetLastError()));
}
//
// Bring the window to the TOP of the Z order
//
if(!SetWindowPos( hwndBBar,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ))
{
TRC_ERR((TB,_T("SetWindowPos failed - 0x%x"),
GetLastError()));
return FALSE;
}
//
// Compute the rectangle for displayed text
//
// First figure out how much space to trim in the
// x direction
//
int xDelta = _sizeLoweredBBar.cy * 2 + //diagonal corners
BBAR_NUM_BUTTONS *
(BBAR_BUTTON_WIDTH + BBAR_BUTTON_SPACE); //button space
GetClientRect( hwndBBar, &_rcBBarDisplayTextArea);
if(!InflateRect( &_rcBBarDisplayTextArea,
-xDelta,
0 ))
{
TRC_ABORT((TB,_T("InflateRect failed 0x%x"),
GetLastError()));
return FALSE;
}
// Shave off from the bottom
_rcBBarDisplayTextArea.bottom -= 1;
if (!CreateToolbars())
{
TRC_ERR((TB,_T("CreateToolbars failed")));
return FALSE;
}
//
// Trigger a repaint of the background
//
InvalidateRect( hwndBBar, NULL, TRUE);
}
else
{
TRC_ERR((TB,_T("CreateWnd for BBar failed")));
return FALSE;
}
if( fStartRaised )
{
SetState( bbarRaised );
_nBBarVertOffset = 0;
}
else
{
SetState( bbarLowered );
_nBBarVertOffset = _sizeLoweredBBar.cy;
}
DC_END_FN();
return TRUE;
}
//
// DIBs use RGBQUAD format:
// 0xbb 0xgg 0xrr 0x00
//
// Reasonably efficient code to convert a COLORREF into an
// RGBQUAD.
//
#define RGB_TO_RGBQUAD(r,g,b) (RGB(b,g,r))
#define CLR_TO_RGBQUAD(clr) (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
//
// Internal helper that loads a bitmap and remaps it's colors
// to the system colors. Use this instead of LoadImage with the
// LR_LOADMAP3DCOLORS flag because that fn doesn't work well on NT4.
//
HBITMAP _LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc, BOOL bMono)
{
struct COLORMAP
{
// use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
DWORD rgbqFrom;
int iSysColorTo;
};
static const COLORMAP sysColorMap[] =
{
// mapping from color in DIB to system color
{ RGB_TO_RGBQUAD(0x00, 0x00, 0x00), COLOR_BTNTEXT }, // black
{ RGB_TO_RGBQUAD(0x80, 0x80, 0x80), COLOR_BTNSHADOW }, // dark grey
{ RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0), COLOR_BTNFACE }, // bright grey
{ RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF), COLOR_BTNHIGHLIGHT } // white
};
const int nMaps = 4;
HGLOBAL hglb;
if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
return NULL;
LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
if (lpBitmap == NULL)
return NULL;
// make copy of BITMAPINFOHEADER so we can modify the color table
const int nColorTableSize = 16;
UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)
LocalAlloc(LPTR, nSize);
if (lpBitmapInfo == NULL)
return NULL;
memcpy(lpBitmapInfo, lpBitmap, nSize);
// color table is in RGBQUAD DIB format
DWORD* pColorTable =
(DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);
for (int iColor = 0; iColor < nColorTableSize; iColor++)
{
// look for matching RGBQUAD color in original
for (int i = 0; i < nMaps; i++)
{
if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
{
if (bMono)
{
// all colors except text become white
if (sysColorMap[i].iSysColorTo != COLOR_BTNTEXT)
pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255);
}
else
pColorTable[iColor] =
CLR_TO_RGBQUAD(
GetSysColor(sysColorMap[i].iSysColorTo));
break;
}
}
}
int nWidth = (int)lpBitmapInfo->biWidth;
int nHeight = (int)lpBitmapInfo->biHeight;
HDC hDCScreen = GetDC(NULL);
HBITMAP hbm = CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
if (hbm != NULL)
{
HDC hDCGlyphs = CreateCompatibleDC(hDCScreen);
HBITMAP hbmOld = (HBITMAP)SelectObject(hDCGlyphs, hbm);
LPBYTE lpBits;
lpBits = (LPBYTE)(lpBitmap + 1);
lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
StretchDIBits(hDCGlyphs, 0, 0, nWidth,
nHeight, 0, 0, nWidth, nHeight,
lpBits, (LPBITMAPINFO)lpBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
SelectObject(hDCGlyphs, hbmOld);
DeleteDC(hDCGlyphs);
}
ReleaseDC(NULL, hDCScreen);
// free copy of bitmap info struct and resource itself
LocalFree(lpBitmapInfo);
#ifndef OS_WINCE
FreeResource(hglb);
#endif
return hbm;
}
BOOL CBBar::CreateToolbars()
{
DC_BEGIN_FN("CreateToolbars");
//
// Create toolbars
//
INT ret = 0;
UINT imgIdx = 0;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_BAR_CLASSES;
if(!InitCommonControlsEx( &icex ))
{
TRC_ERR((TB,_T("InitCommonControlsEx failed 0x%x"),
GetLastError()));
return FALSE;
}
//
// Right bar (close window,disconnect etc)
//
{
TBBUTTON tbButtons [] = {
{0, IDM_MINIMIZE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
#ifndef OS_WINCE
{0, IDM_RESTORE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
#endif
{0, IDM_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}
};
TBBUTTON tbRealButtons[3];
HWND hwndRightToolbar = CreateToolbarEx( GetHwnd(),
WS_CHILD | WS_VISIBLE |
TBSTYLE_FLAT |
CCS_NODIVIDER | CCS_NORESIZE,
IDB_BBAR_TOOLBAR_RIGHT,
0,
_hInstance,
0,
NULL,
0,
12,
12,
16,
16,
sizeof(TBBUTTON) );
if(!hwndRightToolbar)
{
TRC_ERR((TB,_T("CreateToolbarEx failed 0x%x"),
GetLastError()));
return FALSE;
}
//
// Add images
//
if (!AddReplaceImage(hwndRightToolbar,
IDB_BBAR_TOOLBAR_RIGHT,
#ifndef OS_WINCE
3, //image makes up 3 buttons
#else
2, //2 buttons on CE
#endif
&_hbmpRightImage,
&imgIdx))
{
TRC_ERR((TB,_T("AddReplaceImage for rt toolbar failed")));
return FALSE;
}
//
// Associate images with buttons
//
tbButtons[0].iBitmap = imgIdx;
tbButtons[1].iBitmap = imgIdx + 1;
#ifndef OS_WINCE
tbButtons[2].iBitmap = imgIdx + 2;
#endif
//
// Not all buttons are to be added, figure out which here
// and setup the real buttons array
//
ULONG nNumButtons = 0;
if (_fShowMinimize) {
tbRealButtons[nNumButtons++] = tbButtons[0];
}
if (_fShowRestore) {
tbRealButtons[nNumButtons++] = tbButtons[1];
}
// Always show the close button
#ifndef OS_WINCE
tbRealButtons[nNumButtons++] = tbButtons[2];
#endif
//
// Add the buttons
//
ret = SendMessage( hwndRightToolbar,
TB_ADDBUTTONS,
nNumButtons,
(LPARAM)(LPTBBUTTON) &tbRealButtons );
if(-1 == ret)
{
TRC_ERR((TB,_T("TB_ADDBUTTONS failed")));
return FALSE;
}
//
// Move the toolbar
//
if(!MoveWindow( hwndRightToolbar,
_sizeLoweredBBar.cx - _sizeLoweredBBar.cy -
((BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH)*(nNumButtons+1)),
0,
((BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH)*(nNumButtons+1)),
BBAR_BUTTON_HEIGHT*2,
TRUE))
{
TRC_ERR((TB,_T("MoveWindow failed")));
return FALSE;
}
if(!ShowWindow ( hwndRightToolbar,
SW_SHOWNORMAL) )
{
TRC_ERR((TB,_T("ShowWindow failed")));
return FALSE;
}
_hwndWinControlsBar = hwndRightToolbar;
}
//
// Left bar (pin)
//
{
TBBUTTON tbButtons [] = {
{0, IDM_PIN,
TBSTATE_ENABLED | (_fPinned ? TBSTATE_PRESSED : 0),
TBSTYLE_BUTTON, 0L, 0}
};
HWND hwndLeftToolbar = CreateToolbarEx( GetHwnd(),
WS_CHILD | WS_VISIBLE |
TBSTYLE_FLAT |
CCS_NODIVIDER | CCS_NORESIZE,
IDB_BBAR_TOOLBAR_LEFT,
0,
_hInstance,
0,
NULL,
0,
12,
12,
16,
16,
sizeof(TBBUTTON) );
if(!hwndLeftToolbar)
{
TRC_ERR((TB,_T("CreateToolbarEx failed 0x%x"),
GetLastError()));
return FALSE;
}
//
// Add images
//
if (!AddReplaceImage(hwndLeftToolbar,
IDB_BBAR_TOOLBAR_LEFT,
2, //image makes up 2 buttons
&_hbmpLeftImage,
&imgIdx))
{
TRC_ERR((TB,_T("AddReplaceImage for lt toolbar failed")));
return FALSE;
}
_nPinUpImage = imgIdx;
_nPinDownImage = imgIdx + 1;
//
// Associate images with buttons
//
tbButtons[0].iBitmap = _fPinned ? _nPinDownImage : _nPinUpImage;
//
// Add the button
//
ret = SendMessage( hwndLeftToolbar,
TB_ADDBUTTONS,
1,
(LPARAM)(LPTBBUTTON) &tbButtons );
if(-1 == ret)
{
TRC_ERR((TB,_T("TB_ADDBUTTONS failed")));
return FALSE;
}
//
// Move the toolbar
//
if(!MoveWindow( hwndLeftToolbar,
_sizeLoweredBBar.cy + BBAR_BUTTON_SPACE,
0,
(BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH) * 2,
BBAR_BUTTON_HEIGHT*2,
TRUE))
{
TRC_ERR((TB,_T("MoveWindow failed")));
return FALSE;
}
if(!ShowWindow ( hwndLeftToolbar,
SW_SHOWNORMAL) )
{
TRC_ERR((TB,_T("ShowWindow failed")));
return FALSE;
}
_hwndPinBar = hwndLeftToolbar;
}
DC_END_FN();
return TRUE;
}
//
// ReloadImages for the toolbar including
// refreshing the colors
//
BOOL CBBar::ReloadImages()
{
BOOL rc = FALSE;
#ifndef OS_WINCE
INT ret;
#endif
DC_BEGIN_FN("ReloadImages");
if (!_hwndWinControlsBar || !_hwndPinBar)
{
TRC_ERR((TB,_T("Toolbars not initialized")));
DC_QUIT;
}
//
// Replace images
//
if (!AddReplaceImage(_hwndWinControlsBar,
IDB_BBAR_TOOLBAR_RIGHT,
3, //image makes up 3 buttons
&_hbmpRightImage,
NULL))
{
TRC_ERR((TB,_T("AddReplaceImage for rt toolbar failed")));
return FALSE;
}
if (!AddReplaceImage(_hwndPinBar,
IDB_BBAR_TOOLBAR_LEFT,
2, //image makes up 3 buttons
&_hbmpLeftImage,
NULL))
{
TRC_ERR((TB,_T("AddReplaceImage for lt toolbar failed")));
return FALSE;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
//
// Adds or replaces an image to a toolbar
// Params:
// hwndToolbar - toolbar to act on
// rsrcId - resource ID of the bitmap
// nCells - number of image cells
// phbmpOldImage - [IN/OUT] handle to previous image, on return is
// set to current image
// pImgIndex - [OUT] index to the first image added
//
BOOL CBBar::AddReplaceImage(HWND hwndToolbar,
UINT rsrcId,
UINT nCells,
HBITMAP* phbmpOldImage,
PUINT pImgIndex)
{
BOOL rc = FALSE;
INT ret = 0;
HBITMAP hbmpNew = NULL;
HRSRC hBmpRsrc = NULL;
DC_BEGIN_FN("AddReplaceImage");
//
// Replace images
//
hBmpRsrc = FindResource(_hInstance,
MAKEINTRESOURCE(rsrcId),
RT_BITMAP);
if (hBmpRsrc)
{
hbmpNew = _LoadSysColorBitmap(_hInstance, hBmpRsrc, FALSE);
if (hbmpNew)
{
if (NULL == *phbmpOldImage)
{
TBADDBITMAP tbAddBitmap;
tbAddBitmap.hInst = NULL;
tbAddBitmap.nID = (UINT_PTR)hbmpNew;
ret = SendMessage( hwndToolbar,
TB_ADDBITMAP,
nCells,
(LPARAM)(LPTBADDBITMAP)&tbAddBitmap );
}
else
{
TBREPLACEBITMAP tbRplBitmap;
tbRplBitmap.hInstOld = NULL;
tbRplBitmap.nIDOld = (UINT_PTR)*phbmpOldImage;
tbRplBitmap.hInstNew = NULL;
tbRplBitmap.nIDNew = (UINT_PTR)hbmpNew;
tbRplBitmap.nButtons = nCells;
ret = SendMessage(hwndToolbar,
TB_REPLACEBITMAP,
0,
(LPARAM)(LPTBADDBITMAP)&tbRplBitmap);
}
if (-1 != ret)
{
//Delete the old bitmap
if (*phbmpOldImage)
{
DeleteObject(*phbmpOldImage);
}
*phbmpOldImage = hbmpNew;
if (pImgIndex)
{
*pImgIndex = ret;
}
}
else
{
TRC_ERR((TB,_T("TB_ADDBITMAP failed")));
DC_QUIT;
}
}
else
{
TRC_ERR((TB,_T("LoadSysColorBitmap failed rsrcid:%d"), rsrcId));
DC_QUIT;
}
}
else
{
TRC_ERR((TB,_T("Unable to find rsrc: %d"), rsrcId));
DC_QUIT;
}
rc = TRUE;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
//
// Create the window
// params:
// hInstance - app instance
// _hwndBBarParent - parent window
// szClassName - window class name (will create)
// dwStyle - window style
// returns:
// window handle
//
HWND CBBar::CreateWnd(HINSTANCE hInstance,HWND _hwndBBarParent,
LPRECT lpInitialRect)
{
BOOL rc = FALSE;
#ifndef OS_WINCE
WNDCLASSEX wndclass;
#else
WNDCLASS wndclass;
#endif
WNDCLASS tmpwc;
DC_BEGIN_FN("CreateWnd");
TRC_ASSERT(hInstance, (TB, _T("hInstance is null")));
TRC_ASSERT(lpInitialRect, (TB, _T("lpInitialRect is null")));
if(!hInstance || !lpInitialRect)
{
return NULL;
}
TRC_ASSERT(!_hwndBBar, (TB,_T("Double create window. Could be leaking!!!")));
_hInstance = hInstance;
#ifndef OS_WINCE
wndclass.cbSize = sizeof (wndclass);
#endif
wndclass.style = CS_DBLCLKS;
wndclass.lpfnWndProc = CBBar::StaticBBarWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_INFOBK);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = BBAR_CLASSNAME;
#ifndef OS_WINCE
wndclass.hIconSm = NULL;
#endif
SetLastError(0);
if(!GetClassInfo( hInstance, BBAR_CLASSNAME, &tmpwc))
{
#ifndef OS_WINCE
if ((0 == RegisterClassEx(&wndclass)) &&
#else
if ((0 == RegisterClass(&wndclass)) &&
#endif
(ERROR_CLASS_ALREADY_EXISTS != GetLastError()))
{
TRC_ERR((TB,_T("RegisterClassEx failed: %d"),GetLastError()));
return NULL;
}
}
_hwndBBar = CreateWindowEx(0,
BBAR_CLASSNAME,
NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
lpInitialRect->left,
lpInitialRect->top,
lpInitialRect->right - lpInitialRect->left,
lpInitialRect->bottom - lpInitialRect->top,
_hwndBBarParent,
NULL,
hInstance,
this);
if(_hwndBBar)
{
// put a reference to the current object into the hwnd
// so we can access the object from the WndProc
SetLastError(0);
if(!SetWindowLongPtr(_hwndBBar, GWLP_USERDATA, (LONG_PTR)this))
{
if(GetLastError())
{
TRC_ERR((TB,_T("SetWindowLongPtr failed 0x%x"),
GetLastError()));
return NULL;
}
}
}
else
{
TRC_ERR((TB,_T("CreateWindow failed 0x%x"), GetLastError()));
return NULL;
}
DC_END_FN();
return _hwndBBar;
}
LRESULT CALLBACK CBBar::StaticBBarWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
DC_BEGIN_FN("StatiCBBarProc");
// pull out the pointer to the container object associated with this hwnd
CBBar *pwnd = (CBBar *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(pwnd)
{
return pwnd->BBarWndProc( hwnd, uMsg, wParam, lParam);
}
else
{
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
DC_END_FN();
}
LRESULT CALLBACK CBBar::BBarWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
DC_BEGIN_FN("BBarWndProc");
switch (uMsg)
{
case WM_ERASEBKGND:
{
return OnEraseBkgnd(hwnd, uMsg, wParam, lParam);
}
break;
case WM_LBUTTONDBLCLK:
{
OnCmdRestore();
return 0L;
}
break;
case WM_PAINT:
{
return OnPaint(hwnd, uMsg, wParam, lParam);
}
break;
case WM_SYSCOLORCHANGE:
{
InvalidateRect( hwnd, NULL, TRUE);
return 0L;
}
break;
case WM_TIMER:
{
if( BBAR_TIMERID_ANIM == wParam)
{
#ifndef OS_WINCE
if(_state == bbarLowering ||
_state == bbarRaising)
{
BOOL fReachedEndOfAnimation = FALSE;
int delta = (bbarLowering == _state ) ? 1 : -1;
_nBBarVertOffset+= delta;
if(SetWindowPos(_hwndBBar,
NULL,
_rcBBarLoweredAspect.left, //x
_nBBarVertOffset - _sizeLoweredBBar.cy, //y
0,0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
{
TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"),
GetLastError()));
}
if(_state == bbarLowering)
{
if(_nBBarVertOffset >= _sizeLoweredBBar.cy)
{
_nBBarVertOffset = _sizeLoweredBBar.cy;
_state = bbarLowered;
fReachedEndOfAnimation = TRUE;
OnBBarLowered();
}
}
else if(_state == bbarRaising)
{
if(_nBBarVertOffset <= 0)
{
_nBBarVertOffset = 0;
_state = bbarRaised;
fReachedEndOfAnimation = TRUE;
OnBBarRaised();
}
}
if(fReachedEndOfAnimation)
{
if(!KillTimer( _hwndBBar, BBAR_TIMERID_ANIM ))
{
TRC_ERR((TB,_T("KillTimer failed - 0x%x"),
GetLastError()));
}
}
}
#endif
}
else if (BBAR_TIMERID_AUTOHIDE == wParam)
{
//
// If the mouse is within the hotzone
// then don't autohide. Otherwise kill the autohide
// timer and kick off a bbar raise
//
if(_state == bbarLowered)
{
POINT pt;
RECT rc;
GetCursorPos(&pt);
//
// Don't hide if mouse hasn't moved
//
if(_ptLastAutoHideMousePos.x != pt.x &&
_ptLastAutoHideMousePos.y != pt.y)
{
_ptLastAutoHideMousePos.x = pt.x;
_ptLastAutoHideMousePos.y = pt.y;
//
// Get window rect in screen coordinates
//
GetWindowRect( _hwndBBar, &rc);
//
// Don't hide if the cursor is within
// the bbar rect
//
if(!PtInRect(&rc, pt))
{
// Stop the autohide timer because we're going
// to hide
if(!KillTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE ))
{
TRC_ERR((TB,_T("KillTimer failed - 0x%x"),
GetLastError()));
}
StartRaiseBBar();
}
}
else
{
//
// Don't autohide the bbar because the mouse
// has not moved, this prevents the raise/lower
// loop problem because the hotzone (see IH) region and
// auto-hide prevention regions are different
// (by design).
//
TRC_NRM((TB,
_T("Autohide timer fired but mouse not moved")));
}
}
}
return 0L;
}
break;
#ifndef OS_WINCE
case WM_WINDOWPOSCHANGING:
{
if(_fBlockZOrderChanges)
{
LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
lpwp->flags |= SWP_NOZORDER;
}
return 0L;
}
break;
#endif
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDM_MINIMIZE:
{
OnCmdMinimize();
}
break;
case IDM_RESTORE:
{
OnCmdRestore();
}
break;
case IDM_CLOSE:
{
OnCmdClose();
}
break;
case IDM_PIN:
{
OnCmdPin();
}
break;
}
return 0L;
}
break;
default:
{
return DefWindowProc( hwnd, uMsg, wParam, lParam);
}
break;
}
DC_END_FN();
}
VOID CBBar::SetState(BBarState newState)
{
DC_BEGIN_FN("SetState");
TRC_NRM((TB,_T("BBar old state: 0x%x - new state: 0x%x"),
_state, newState));
_state = newState;
DC_END_FN();
}
LRESULT CBBar::OnEraseBkgnd(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT rc;
HDC hDC = NULL;
HBRUSH hBrToolTipBgCol = NULL;
#ifndef OS_WINCE
HGDIOBJ hPrevBr = NULL;
COLORREF prevCol;
#endif
HPEN hPenNew = NULL, hPenOld = NULL, hPenOri = NULL;
DC_BEGIN_FN("OnEraseBkgnd");
hDC = (HDC)wParam;
GetClientRect( hwnd, &rc );
//
// Repaint the background as follows
// 1) fill the window with the TOOLTIP bg color
// 2) draw the edges in solid black
// 3) add a grey line to the bottom horizontal edge because it looks
// really cool
//
hBrToolTipBgCol = (HBRUSH) GetSysColorBrush(COLOR_INFOBK);
FillRect(hDC, &rc, hBrToolTipBgCol);
#ifdef OS_WINCE
//On CE, the toolbar sends an extra WM_ERASEBKGND message to the parent with its DC in wParam.
//The origin of that DC, is the where the toolbar is located. So we want to use supplied DC for FillRect
//but not for drawing lines
hDC = GetDC(hwnd);
#endif
hPenNew = CreatePen( PS_SOLID, 0 , COLOR_BLACK);
if (NULL != hPenNew) {
hPenOri = SelectPen(hDC, hPenNew);
}
//
// Left diagonal corner (assumes 45degree line)
//
MoveToEx( hDC, 0, 0, NULL);
LineTo( hDC,
_sizeLoweredBBar.cy,
_sizeLoweredBBar.cy );
//
// Right diagonal corner (assumes 45degree line)
// (bias by one pixel to end up inside the clipping region)
//
MoveToEx( hDC, _sizeLoweredBBar.cx - 1, 0, NULL);
LineTo( hDC,
_sizeLoweredBBar.cx - _sizeLoweredBBar.cy -1,
_sizeLoweredBBar.cy );
//
// Bottom black line
// bias by 1 pixel up to lie inside clip region
//
MoveToEx( hDC, _sizeLoweredBBar.cy,
_sizeLoweredBBar.cy - 1, NULL);
LineTo( hDC,
_sizeLoweredBBar.cx - _sizeLoweredBBar.cy,
_sizeLoweredBBar.cy - 1);
if (NULL != hPenOri) {
SelectPen(hDC, hPenOri);
}
if (NULL != hPenNew) {
DeleteObject(hPenNew);
hPenNew = NULL;
}
//
// Thin grey line above bottom gray line
//
hPenNew = CreatePen( PS_SOLID, 0 , COLOR_DKGREY);
if (NULL != hPenNew) {
hPenOri = SelectPen(hDC, hPenNew);
}
MoveToEx( hDC, _sizeLoweredBBar.cy - 1,
_sizeLoweredBBar.cy - 2, NULL);
LineTo( hDC,
_sizeLoweredBBar.cx - _sizeLoweredBBar.cy + 1,
_sizeLoweredBBar.cy - 2);
//
// Restore DC
//
#ifndef OS_WINCE
if (NULL != hPenOri) {
SelectPen( hDC, hPenOri);
}
#else
SelectPen( hDC, GetStockObject(BLACK_PEN));
#endif
if (NULL != hPenNew) {
DeleteObject( hPenNew);
hPenNew = NULL;
}
#ifdef OS_WINCE
ReleaseDC(hwnd, hDC);
#endif
DC_END_FN();
return TRUE;
}
VOID CBBar::SetDisplayedText(LPTSTR szText)
{
HRESULT hr;
DC_BEGIN_FN("SetDisplayedText");
if(szText) {
hr = StringCchCopy(_szDisplayedText,
SIZE_TCHARS(_szDisplayedText),
szText);
if (FAILED(hr)) {
TRC_ERR((TB,_T("StringCopy for dispayed text failed: 0x%x"),hr));
}
}
else {
_szDisplayedText[0] = NULL;
}
if(_hwndBBar && _state != bbarNotInit) {
//Trigger a repaint
InvalidateRect( _hwndBBar, NULL, TRUE);
}
DC_END_FN();
}
LRESULT CBBar::OnPaint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
DC_BEGIN_FN("OnPaint");
if(_state != bbarNotInit)
{
COLORREF oldCol;
INT oldMode;
HFONT hOldFont;
COLORREF oldTextCol;
//
// Draw the displayed text
//
BeginPaint( hwnd, &ps);
oldCol = SetBkColor( ps.hdc, GetSysColor(COLOR_INFOBK));
oldMode = SetBkMode( ps.hdc, OPAQUE);
oldTextCol = SetTextColor( ps.hdc, GetSysColor(COLOR_INFOTEXT));
hOldFont = (HFONT)SelectObject( ps.hdc,
#ifndef OS_WINCE
GetStockObject( DEFAULT_GUI_FONT));
#else
GetStockObject( SYSTEM_FONT));
#endif
DrawText(ps.hdc,
_szDisplayedText,
_tcslen(_szDisplayedText),
&_rcBBarDisplayTextArea,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
SetBkColor( ps.hdc, oldCol);
SetBkMode( ps.hdc, oldMode);
SetTextColor( ps.hdc, oldTextCol);
SelectObject( ps.hdc, hOldFont);
EndPaint( hwnd, &ps);
}
DC_END_FN();
return 0;
}
//
// Internal event handler for bbar lowered
//
VOID CBBar::OnBBarLowered()
{
DC_BEGIN_FN("OnBBarLowered");
//
// Kick off the autohide timer
//
TRC_ASSERT(_state == bbarLowered,
(TB,_T("_state should be lowered...0x%x"),
_state));
TRC_ASSERT(_nBBarAutoHideTime,
(TB,_T("_nBBarAutoHideTime is 0")));
if(bbarLowered == _state)
{
if (!_fPinned || !_fLocked)
{
if(!SetTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE,
_nBBarAutoHideTime, NULL ))
{
TRC_ERR((TB,_T("SetTimer failed - 0x%x"),
GetLastError()));
//
// Bail out
//
return;
}
// After bbar has lowered once reset
// the autohide interval time to the shorter
// interval.
_nBBarAutoHideTime = BBAR_AUTOHIDE_TIME;
}
}
DC_END_FN();
}
//
// Internal event handler for bbar raised
//
VOID CBBar::OnBBarRaised()
{
DC_BEGIN_FN("OnBBarRaised");
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
_pUi->UI_OnNotifyBBarVisibleChange(0);
#endif
DC_END_FN();
}
VOID CBBar::OnBBarHotzoneFired()
{
DC_BEGIN_FN("OnBBarHotzoneFired");
//
// Only allow the bbar to drop on the timer if it's enabled
//
if (_fBBarEnabled &&
_state == bbarRaised &&
_pUi->UI_IsFullScreen())
{
StartLowerBBar();
}
DC_END_FN();
}
VOID CBBar::OnCmdMinimize()
{
DC_BEGIN_FN("OnCmdLock");
TRC_NRM((TB,_T("BBAR Command Minimize")));
TRC_ASSERT( bbarNotInit != _state,
(TB,_T("bbar not initalized - state:0x%x"),
_state));
if(bbarNotInit != _state &&
_pUi->UI_IsFullScreen())
{
_pUi->UI_RequestMinimize();
}
DC_END_FN();
}
VOID CBBar::OnCmdRestore()
{
DC_BEGIN_FN("OnCmdLock");
TRC_NRM((TB,_T("BBAR Command Restore")));
TRC_ASSERT( bbarNotInit != _state,
(TB,_T("bbar not initalized - state:0x%x"),
_state));
if(bbarNotInit != _state)
{
_pUi->UI_ToggleFullScreenMode();
}
DC_END_FN();
}
VOID CBBar::OnCmdClose()
{
DC_BEGIN_FN("OnCmdClose");
TRC_NRM((TB,_T("BBAR Command Close")));
TRC_ASSERT( bbarNotInit != _state,
(TB,_T("bbar not initalized - state:0x%x"),
_state));
if (bbarNotInit != _state)
{
//
// Dispatch a close request to the core
//
if (!_pUi->UI_UserRequestedClose())
{
// Request for clean close down (including firing of events
// asking container if they really want to close) has failed
// so trigger an immediate disconnection without user prompts
TRC_ALT((TB,_T("UI_UserRequestedClose failed, disconnect now!")));
_pUi->UI_UserInitiatedDisconnect(NL_DISCONNECT_LOCAL);
}
}
DC_END_FN();
}
VOID CBBar::OnCmdPin()
{
DC_BEGIN_FN("OnCmdPin");
TRC_NRM((TB,_T("BBAR Command Pin")));
TRC_ASSERT( bbarNotInit != _state,
(TB,_T("bbar not initalized - state:0x%x"),
_state));
TRC_ASSERT(_hwndPinBar, (TB,_T("Left bar not created")));
if (bbarNotInit != _state)
{
//
// The pin button acts like a toggle
//
_fPinned = !_fPinned;
SendMessage(_hwndPinBar, TB_PRESSBUTTON,
IDM_PIN, MAKELONG(_fPinned,0));
SendMessage(_hwndPinBar, TB_CHANGEBITMAP,
IDM_PIN,
MAKELPARAM( _fPinned ?_nPinDownImage : _nPinUpImage, 0));
if(!_fPinned && bbarLowered == _state )
{
// We just unpinned trigger an OnLowered event
// to startup the autohide timers
OnBBarLowered();
}
}
DC_END_FN();
}
//
// Notification from core that we entered fullscreen mode
//
VOID CBBar::OnNotifyEnterFullScreen()
{
DC_BEGIN_FN("OnNotifyEnterFullScreen");
//
// Lower bbar to give a visual cue
//
if(_state != bbarNotInit)
{
StartLowerBBar();
}
DC_END_FN();
}
//
// Notification from core that we left fullscreen mode
//
VOID CBBar::OnNotifyLeaveFullScreen()
{
DC_BEGIN_FN("OnNotifyLeaveFullScreen");
//
// Disable the bbar in windowed mode
//
if(_state != bbarNotInit)
{
//Kill timers
KillTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE);
KillTimer( _hwndBBar, BBAR_TIMERID_ANIM);
//Immediate raise of the bbar
if(_state != bbarRaised)
{
ImmediateRaiseBBar();
}
}
DC_END_FN();
}
//
// Raise the bbar without much fanfare (i.e animations)
// this is used to quickly 'hide' the bbar
//
BOOL CBBar::ImmediateRaiseBBar()
{
DC_BEGIN_FN("ImmediateRaiseBBar");
if(_state != bbarNotInit &&
_state != bbarRaised)
{
_nBBarVertOffset = 0;
_state = bbarRaised;
if(SetWindowPos(_hwndBBar,
NULL,
_rcBBarLoweredAspect.left, //x
_nBBarVertOffset - _sizeLoweredBBar.cy, //y
0,0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
{
TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"),
GetLastError()));
}
OnBBarRaised();
}
DC_END_FN();
return TRUE;
}
#ifdef OS_WINCE
//
// Lower the bbar without much fanfare (i.e animations)
// this is used to quickly 'show' the bbar
//
BOOL CBBar::ImmediateLowerBBar()
{
DC_BEGIN_FN("ImmediateLowerBBar");
if(_state != bbarNotInit &&
_state != bbarLowered)
{
_nBBarVertOffset = _sizeLoweredBBar.cy;
_state = bbarLowered;
if(!SetWindowPos(_hwndBBar,
NULL,
_rcBBarLoweredAspect.left, //x
_nBBarVertOffset - _sizeLoweredBBar.cy, //y
0,0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ))
{
TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"),
GetLastError()));
}
OnBBarLowered();
}
DC_END_FN();
return TRUE;
}
#endif
VOID CBBar::OnSysColorChange()
{
DC_BEGIN_FN("OnSysColorChange");
if (_state != bbarNotInit)
{
//
// Force a reload of the images
// so they get updated for the new system colors
//
ReloadImages();
}
DC_END_FN();
}
#ifdef OS_WINCE
//Assumes four points in the array
HRGN CBBar::GetBBarRgn(POINT *pts)
{
DC_BEGIN_FN("CBBar::GetBBarRgn");
HRGN hRgn=NULL, hRgn1=NULL;
int nRect, nTotalRects, nStart;
RGNDATA *pRgnData = NULL;
RECT *pRect = NULL;
BOOL bSuccess = FALSE;
TRC_ASSERT((pts[2].x - pts[1].x == pts[0].x - pts[3].x), (TB,_T("Invalid points!")));
nTotalRects = (pts[2].x - pts[1].x + 1) /2;
pRgnData = (RGNDATA *)LocalAlloc(0, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects));
if (!pRgnData)
return NULL;
pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
pRgnData->rdh.iType = RDH_RECTANGLES;
pRgnData->rdh.nCount = nTotalRects;
pRgnData->rdh.nRgnSize = (sizeof(RECT)*nTotalRects);
pRect = (RECT *)pRgnData->Buffer;
hRgn = CreateRectRgn(pts[0].x + 1, pts[3].y, pts[1].x, pts[1].y);
if (!hRgn)
DC_QUIT;
SetRect(&(pRgnData->rdh.rcBound), 0, 0, pts[0].x, pts[0].y);
//The left triangle
nStart = pts[3].x + 1;
for (nRect = 0; nRect < nTotalRects; nRect++)
{
SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, nStart);
TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom));
nStart += 2;
}
hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData);
if (!hRgn1)
DC_QUIT;
if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR))
DC_QUIT;
DeleteObject(hRgn1);
//The left triangle offset by one pixel to avoid a striped triangle
nStart = pts[3].x + 2;
for (nRect = 0; nRect < nTotalRects; nRect++)
{
SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, nStart);
TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom));
nStart += 2;
}
hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData);
if (!hRgn1)
DC_QUIT;
if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR))
DC_QUIT;
DeleteObject(hRgn1);
//The right triangle
nStart = pts[1].x - 1;
for (nRect = 0; nRect < nTotalRects; nRect++)
{
SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, pts[2].x - nStart);
TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom));
nStart += 2;
}
hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData);
if (!hRgn1)
DC_QUIT;
if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR))
DC_QUIT;
DeleteObject(hRgn1);
//The right triangle offset by one pixel to avoid a striped triangle
nStart = pts[1].x;
for (nRect = 0; nRect < nTotalRects; nRect++)
{
SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, pts[2].x - nStart);
TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom));
nStart += 2;
}
hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData);
if (!hRgn1)
DC_QUIT;
if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR))
DC_QUIT;
DeleteObject(hRgn1);
hRgn1 = NULL;
bSuccess = TRUE;
DC_EXIT_POINT:
LocalFree(pRgnData);
if (hRgn1)
DeleteObject(hRgn1);
if (!bSuccess && hRgn)
{
DeleteObject(hRgn);
hRgn = NULL;
}
DC_END_FN();
return hRgn;
}
#endif //OS_WINCE
#endif // USE_BBAR