|
|
//////////////////////////////////////////////////////////////////////////////
// Copyright 1990-1993 Microsoft corporation
// all rights reservered
//////////////////////////////////////////////////////////////////////////////
//
// Program: (nominally)Bloodhound
// Module: tab.c
// Purpose: creates and operates a book tab (big file folder) custom control
//
// Note: the current implementation is limited to 4 booktabs, sorry.
//
//
// ---------------------------- TABSTOP = 4 -------------------
//
// Entry Points:
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// BookTab
//
//
//
// Input:
// hwnd - our window handle
//
// Returns:
//
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
#define STRICT
#include "switches.h"
#include <windows.h>
#include <windowsx.h>
#include "tab.h"
// #include "..\bhmem.h"
//////////////////////////////////////////////////////////////////////////////
// Constants
//////////////////////////////////////////////////////////////////////////////
#define MAX_TABS 4
#define MAX_TAB_LABEL_LEN 128
#define ANGLE_X 5
#define ANGLE_Y 5
#define CARAT_X 2
#define CARAT_Y 2
#define FLUFF_X 0
#define FLUFF_Y 0
#define FOOTROOM_Y 3
// We use the selected tab for these calculations:
//
// tab_rect:
//
// ANGLE_X|--|
//
// - BBBBBBBBBBBBBBB
// ANGLE_Y | BWWWWWWWWWWWWWWW
// | BWWWWWWWWWWWWWWWW
// - BWWW
// BWW * <-- this is where the text_rect starts
// BWW
// BWW
//
//
// text_rect: (defined by the *'s)
//
// FLUFF_X|----|
//
// - * *
// |
// FLUFF_Y |
// | CARAT_X
// | |---|
// - ............................. -
// . . |
// . . | CARAT_Y
// . . |
// - . XXXXX XXXXX X X XXXXX . -
// text hght| . X X X X X .
// is from | . X XXX X X .
// font | . X X X X X .
// _ . X XXXXX X X X .
// . .
// . .
// . .
// .............................
//
// |---------------------|
// text width is directly
// from the font itself
// * *
//
//
//////////////////////////////////////////////////////////////////////////////
// Data Structures for this file
//////////////////////////////////////////////////////////////////////////////
typedef struct _ONETAB { TCHAR label[ MAX_TAB_LABEL_LEN + 1 ]; DWORD data; RECT tab_rect; RECT text_rect; } ONETAB;
typedef struct _TABDATA { // do the tabs need updating ?
BOOL fUpdate; RECT tabs_rect;
// font data
HFONT hfSelected; HFONT hfUnselected;
// windows data
HWND hwndParent;
// tab data
UINT total_tabs; UINT selected_tab; ONETAB tab[ MAX_TABS ];
} TABDATA; typedef TABDATA *LPTABDATA;
//////////////////////////////////////////////////////////////////////////////
// Variables Global to this file
//////////////////////////////////////////////////////////////////////////////
TCHAR szBookTabName[]=BOOK_TAB_CONTROL;
//////////////////////////////////////////////////////////////////////////////
// Macros Global to this file
//////////////////////////////////////////////////////////////////////////////
#define GetInstanceDataPtr(hwnd) ((LPTABDATA)GetWindowLongPtr(hwnd, 0))
#define SetInstanceDataPtr(hwnd,x) (SetWindowLongPtr(hwnd, 0, (DWORD_PTR)x))
//////////////////////////////////////////////////////////////////////////////
// Functional Prototypes for Functions Local to this File
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK BookTab_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL BookTab_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct); void BookTab_OnDestroy(HWND hwnd); void BookTab_OnLButtonDown(HWND hwnd, BOOL fDblClk, int x, int y, UINT keyFlags); void BookTab_OnPaint(HWND hwnd); UINT BookTab_OnGetDlgCode(HWND hwnd, MSG FAR* lpmsg); void BookTab_OnSize(HWND hwnd, UINT state, int cx, int cy); void BookTab_OnSetFocus(HWND hwnd, HWND hwndOldFocus); void BookTab_OnKillFocus(HWND hwnd, HWND hwndNewFocus); void BookTab_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags); void BookTab_OnEnable(HWND hwnd, BOOL fEnable);
UINT BookTab_OnAddItem( HWND hwnd, LPTSTR text ); UINT BookTab_OnInsertItem( HWND hwnd, UINT index, LPTSTR text); BOOL BookTab_OnDeleteItem( HWND hwnd, UINT index ); BOOL BookTab_OnDeleteAllItems( HWND hwnd); BOOL BookTab_OnSetItem( HWND hwnd, UINT index, LPTSTR text ); BOOL BookTab_OnGetItem( HWND hwnd, UINT index, LPTSTR text ); UINT BookTab_OnSetCurSel( HWND hand, UINT newsel ); UINT BookTab_OnGetCurSel( HWND hand ); UINT BookTab_OnGetItemCount( HWND hwnd ); BOOL BookTab_OnSetItemData( HWND hwnd, UINT index, DWORD data ); DWORD BookTab_OnGetItemData( HWND hwnd, UINT index); void BookTab_OnPutInBack( HWND hwnd );
BOOL IsPointInRect( int given_x, int given_y, LPRECT pRect ); void BookTab_UpdateButtons( HWND hwnd );
//////////////////////////////////////////////////////////////////////////////
// BookTab_Initialize()
//
// Initializes and registers the BookTab custom class
//
// Input:
// hInstance - the handle to our parent's instance
//
// Returns:
// True if successful, else False
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_Initialize(HINSTANCE hInstance) { WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS | CS_PARENTDC; wndclass.lpfnWndProc = BookTab_WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = sizeof( LPTABDATA ); wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szBookTabName;
RegisterClass ( &wndclass ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_WndProc()
//
// Distributes messages coming in to the BookTab control
//
// Input:
// hwnd - Our handle
// message - the ordinal of the incoming message
// wParam - half of the incoming data
// lParam - the other half of the incoming data
//
// Returns:
// True if we handled the message, else False
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK BookTab_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { // standard windows messages
HANDLE_MSG( hwnd, WM_CREATE, BookTab_OnCreate); HANDLE_MSG( hwnd, WM_DESTROY, BookTab_OnDestroy); HANDLE_MSG( hwnd, WM_LBUTTONDOWN, BookTab_OnLButtonDown); HANDLE_MSG( hwnd, WM_PAINT, BookTab_OnPaint); HANDLE_MSG( hwnd, WM_SIZE, BookTab_OnSize); HANDLE_MSG( hwnd, WM_SETFOCUS, BookTab_OnSetFocus); HANDLE_MSG( hwnd, WM_KILLFOCUS, BookTab_OnKillFocus); HANDLE_MSG( hwnd, WM_KEYDOWN, BookTab_OnKey); HANDLE_MSG( hwnd, WM_KEYUP, BookTab_OnKey);
// messages specific to all custom controls
HANDLE_MSG( hwnd, WM_GETDLGCODE, BookTab_OnGetDlgCode); HANDLE_MSG( hwnd, WM_ENABLE, BookTab_OnEnable);
// messages specific to THIS custom control
case BT_ADDITEM: return( BookTab_OnAddItem( hwnd, (LPTSTR)lParam )); case BT_INSERTITEM: return( BookTab_OnInsertItem( hwnd, (UINT)wParam, (LPTSTR)lParam )); case BT_DELETEITEM: return( BookTab_OnDeleteItem( hwnd, (UINT)wParam )); case BT_DELETEALLITEMS: return( BookTab_OnDeleteAllItems( hwnd )); case BT_SETITEM: return( BookTab_OnSetItem( hwnd, (UINT)wParam, (LPTSTR)lParam )); case BT_GETITEM: return( BookTab_OnGetItem( hwnd, (UINT)wParam, (LPTSTR)lParam )); case BT_SETCURSEL: return( BookTab_OnSetCurSel( hwnd, (UINT)wParam )); case BT_GETCURSEL: return( BookTab_OnGetCurSel( hwnd )); case BT_GETITEMCOUNT: return( BookTab_OnGetItemCount( hwnd )); case BT_SETITEMDATA: return( BookTab_OnSetItemData( hwnd, (UINT)wParam, (DWORD)lParam )); case BT_GETITEMDATA: return( BookTab_OnGetItemData( hwnd, (UINT)wParam )); case BT_PUTINBACK: BookTab_OnPutInBack( hwnd ); return (TRUE); } // pass unprocessed messages to DefWndProc...
return DefWindowProc(hwnd, message, wParam, lParam); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnCreate()
//
// Initializes a new instance of our lovely custom control
//
// Input:
// hwnd - our window handle
// lpcreatestruct - pointer to the data with which to do our thing
//
// Returns:
// True if the instance is created, else false
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) { LPTABDATA pData; UINT i;
// allocate the instance data for this control
pData = LocalAlloc( LPTR, sizeof( TABDATA )); if( pData == NULL ) return FALSE; SetInstanceDataPtr( hwnd, pData );
// initialize values in the control
pData->total_tabs = 0; pData->selected_tab = 0;
pData->hwndParent = lpCreateStruct->hwndParent;
// fill the prospective tab slots with data
for( i = 0; i < MAX_TABS; i++ ) { pData->tab[i].label[0] = TEXT('\0'); pData->tab[i].data = (DWORD)0; }
// create the proper fonts:
// 8 pt sans serif bold for selected and
// 8 pt sans serif regular for not selected
pData->hfSelected = CreateFont( -MulDiv(9, GetDeviceCaps(GetDC(hwnd), LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 0x4, TEXT("MS Shell Dlg") ); pData->hfUnselected = CreateFont( -MulDiv(9, GetDeviceCaps(GetDC(hwnd), LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 0x4, TEXT("MS Shell Dlg") );
// fill the rest of the sizing info
BookTab_OnSize( hwnd, 0, lpCreateStruct->cx, lpCreateStruct->cy );
// make sure that we are on the bottom
SetWindowPos( hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW );
// make sure we update
pData->fUpdate = TRUE;
// put us last
BookTab_PutInBack( hwnd );
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnDestroy()
//
// Cleans up as our control goes away
//
// Input:
// hwnd - our window handle
//
// Returns:
// nothing
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnDestroy(HWND hwnd) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// delete our fonts
DeleteObject( pData->hfSelected ); DeleteObject( pData->hfUnselected );
// free up our instance data
LocalFree( pData ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnLButtonDown()
//
// Handles the event where a user has the left mouse button down
//
// Input:
// hwnd - our window handle
// fDblClk - an indication on the second message of a double click
// x - the mouses x coordinate at the time of the message
// y - the mouses y coordinate at the time of the message
// keyFlags - an indication of which keys were pressed at the time
//
// Returns:
// nuthin'
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnLButtonDown(HWND hwnd, BOOL fDblClk, int x, int y, UINT keyFlags) { LPTABDATA pData; UINT i;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// where did they click the mouse...
// loop thru the tabs to find the one struck
for( i = 0; i < pData->total_tabs; i++ ) { if( IsPointInRect( x, y, &(pData->tab[i].tab_rect) ) ) { // this is the correct spot
BookTab_OnSetCurSel( hwnd, i );
// notify our parent that the selection has changed
SendMessage( pData->hwndParent, BTN_SELCHANGE, pData->selected_tab, (DWORD_PTR)hwnd);
SetFocus( hwnd ); return; } }
// the mouse was clicked outside any of the button areas
}
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnPaint()
//
// Handles requests from windows that the control repaint itself
//
// Input:
// hwnd - our window handle
//
// Returns:
// hopefully :)
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnPaint(HWND hwnd) { LPTABDATA pData; PAINTSTRUCT ps; HDC hdc; TEXTMETRIC tm; UINT i; HWND hwndFocus;
HPEN hOldPen; HPEN hShadowPen; HPEN hHighlightPen; HPEN hFramePen; HPEN hBackPen; HBRUSH hBackBrush; HFONT hfOldFont;
WORD cyChar; WORD yWidth; WORD xWidth; RECT total; RECT temp; LPRECT pTab; LPRECT pText;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// right before drawing, make sure that the button sizes are accurate
BookTab_UpdateButtons( hwnd );
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// get the handle to the window with the current focus
hwndFocus = GetFocus();
// prepare for painting...
BeginPaint( hwnd, &ps ); hdc = GetDC( hwnd );
// set text stuff
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); SetTextAlign( hdc, TA_TOP | TA_LEFT );
// determine proper sizes
GetTextMetrics(hdc, &tm); cyChar = (WORD)tm.tmHeight; xWidth = (WORD) GetSystemMetrics(SM_CXBORDER); yWidth = (WORD) GetSystemMetrics(SM_CYBORDER); GetClientRect( hwnd, &total ); //BUGBUG fudge the rectangle so that the bottom and left do not get cut off
total.bottom -= yWidth; total.right -= xWidth;
// set up the pens that we will need
hHighlightPen = CreatePen(PS_SOLID, yWidth, GetSysColor(COLOR_BTNHIGHLIGHT)); hShadowPen = CreatePen(PS_SOLID, yWidth, GetSysColor(COLOR_BTNSHADOW)); hFramePen = CreatePen(PS_SOLID, yWidth, GetSysColor(COLOR_WINDOWFRAME)); hBackPen = CreatePen(PS_SOLID, yWidth, GetSysColor(COLOR_BTNFACE)); hBackBrush = CreateSolidBrush( GetSysColor(COLOR_BTNFACE));
// get the old pen by setting a new one
hOldPen = SelectPen( hdc, hHighlightPen );
// clear out behind the tabs if we need to
if( pData->fUpdate == TRUE ) { FillRect( hdc, &(pData->tabs_rect), hBackBrush ); pData->fUpdate = FALSE; }
// draw the box...
// left side dark border
SelectPen( hdc, hFramePen ); MoveToEx( hdc, total.left, pData->tab[0].tab_rect.bottom+yWidth, NULL ); LineTo ( hdc, total.left, total.bottom ); // bottom dark border
LineTo ( hdc, total.right, total.bottom ); // right side dark border
LineTo ( hdc, total.right, pData->tab[0].tab_rect.bottom+yWidth); // top dark border, right half (over to selection)
LineTo ( hdc, pData->tab[pData->selected_tab].tab_rect.right-yWidth, pData->tab[0].tab_rect.bottom+yWidth); // skip area under the selected tab
MoveToEx( hdc, pData->tab[pData->selected_tab].tab_rect.left, pData->tab[0].tab_rect.bottom+yWidth, NULL); // top dark border, left half (from selection to left border)
LineTo ( hdc, total.left, pData->tab[0].tab_rect.bottom+yWidth);
// left side highlight #1
SelectPen( hdc, hHighlightPen ); MoveToEx( hdc, total.left+xWidth, pData->tab[0].tab_rect.bottom+2*yWidth, NULL ); LineTo( hdc, total.left+xWidth, total.bottom-yWidth );
// bottom shadow #1
SelectPen( hdc, hShadowPen ); LineTo( hdc, total.right-xWidth, total.bottom-yWidth ); // right side shadow #1
LineTo( hdc, total.right-xWidth, pData->tab[0].tab_rect.bottom+2*yWidth );
// top hilite #1
SelectPen( hdc, hHighlightPen ); // top hilite, right half (over to selection)
LineTo ( hdc, pData->tab[pData->selected_tab].tab_rect.right-yWidth, pData->tab[0].tab_rect.bottom+2*yWidth); // skip area under the selected tab
MoveToEx( hdc, pData->tab[pData->selected_tab].tab_rect.left, pData->tab[0].tab_rect.bottom+2*yWidth, NULL); // top hilite, left half (from selection to left border)
if( pData->selected_tab != 0 ) LineTo ( hdc, total.left+2*xWidth, pData->tab[0].tab_rect.bottom+2*yWidth);
// left side highlight #2
SelectPen( hdc, hHighlightPen ); MoveToEx( hdc, total.left+2*xWidth, pData->tab[0].tab_rect.bottom+3*yWidth, NULL ); LineTo( hdc, total.left+2*xWidth, total.bottom-2*yWidth );
// bottom shadow #2
SelectPen( hdc, hShadowPen ); LineTo( hdc, total.right-2*xWidth, total.bottom-2*yWidth ); // right side shadow #2
LineTo( hdc, total.right-2*xWidth, pData->tab[0].tab_rect.bottom+3*yWidth );
// top hilite #2
SelectPen( hdc, hHighlightPen ); // top hilite, right half (over to selection)
LineTo ( hdc, pData->tab[pData->selected_tab].tab_rect.right-2*yWidth, pData->tab[0].tab_rect.bottom+3*yWidth); // skip area under the selected tab
MoveToEx( hdc, pData->tab[pData->selected_tab].tab_rect.left, pData->tab[0].tab_rect.bottom+3*yWidth, NULL); // top hilite, left half (from selection to left border)
if( pData->selected_tab != 0 ) LineTo ( hdc, total.left+2*xWidth, pData->tab[0].tab_rect.bottom+3*yWidth);
// Draw the tabs...
// loop thru the tabs
for( i = 0; i < pData->total_tabs; i++ ) { // point our local variables at the current rects
pTab = &(pData->tab[i].tab_rect); pText = &(pData->tab[i].text_rect);
if( i == pData->selected_tab ) { // this is the selection, it should not be pushed down...
// left side dark border
SelectPen( hdc, hFramePen ); MoveToEx(hdc, pTab->left, pTab->bottom, NULL); LineTo(hdc, pTab->left, pTab->top + ANGLE_Y*yWidth); // left side angle dark border
LineTo(hdc, pTab->left + ANGLE_X*xWidth, pTab->top); // top dark border
LineTo(hdc, pTab->right - ANGLE_X*xWidth, pTab->top); // right side angle dark border
LineTo(hdc, pTab->right, pTab->top + ANGLE_Y*yWidth); // right side dark border (overshoot by one)
LineTo(hdc, pTab->right, pTab->bottom+yWidth);
// left side hilite #1 (extends down 3 below the box to handle
// melding the hilites with the box below)
SelectPen( hdc, hHighlightPen); MoveToEx(hdc, pTab->left+xWidth, pTab->bottom+3*yWidth, NULL); LineTo(hdc, pTab->left+xWidth, pTab->top+ANGLE_Y*yWidth ); // left side angle hilight #1
LineTo(hdc, pTab->left+ANGLE_X*xWidth, pTab->top+yWidth ); // top hilite #1
LineTo(hdc, pTab->right-ANGLE_X*xWidth, pTab->top+yWidth ); // right side angle shadow #1
SelectPen( hdc, hShadowPen); LineTo(hdc, pTab->right-xWidth, pTab->top+ANGLE_Y*yWidth ); // right side shadow #1 (overshoot by one) (see above)
LineTo(hdc, pTab->right-xWidth, pTab->bottom+3*yWidth);
// left side hilite #2 (the 2* are becaus we are the 2nd hilite)
SelectPen( hdc, hHighlightPen); MoveToEx(hdc, pTab->left+2*xWidth, pTab->bottom+3*yWidth, NULL); LineTo(hdc, pTab->left+2*xWidth, pTab->top+ANGLE_Y*yWidth ); // left side angle hilight #2
LineTo(hdc, pTab->left+ANGLE_X*xWidth, pTab->top+2*yWidth ); // top hilite #2
LineTo(hdc, pTab->right-ANGLE_X*xWidth, pTab->top+2*yWidth ); // right side angle shadow #2
SelectPen( hdc, hShadowPen); LineTo(hdc, pTab->right-2*xWidth, pTab->top+ANGLE_Y*yWidth ); // right side shadow #2 (overshoot by one)
LineTo(hdc, pTab->right-2*xWidth, pTab->bottom+4*yWidth );
// clear out the chunk below the active tab
SelectPen(hdc, hBackPen ); MoveToEx(hdc, pTab->left+3*xWidth, pTab->bottom+yWidth, NULL); LineTo(hdc, pTab->right-2*xWidth, pTab->bottom+yWidth); MoveToEx(hdc, pTab->left+3*xWidth, pTab->bottom+2*yWidth, NULL); LineTo(hdc, pTab->right-2*xWidth, pTab->bottom+2*yWidth); MoveToEx(hdc, pTab->left+3*xWidth, pTab->bottom+3*yWidth, NULL); LineTo(hdc, pTab->right-2*xWidth, pTab->bottom+3*yWidth);
// clear out the old label...
FillRect( hdc, pText, hBackBrush ); // now print in the label ...
hfOldFont = SelectObject( hdc, pData->hfSelected ); ExtTextOut( hdc, pText->left+ CARAT_X*xWidth + FLUFF_X*xWidth, pText->top + CARAT_Y*yWidth + FLUFF_Y*yWidth, 0, NULL, pData->tab[i].label, lstrlen(pData->tab[i].label), NULL ); SelectFont( hdc, hfOldFont );
// if we have the focus, print the caret
if( hwnd == hwndFocus ) { // we have the focus
temp.top = pText->top + FLUFF_X*xWidth; temp.left = pText->left + FLUFF_Y*yWidth; temp.bottom = pText->bottom - FLUFF_X*xWidth; temp.right = pText->right - FLUFF_Y*yWidth; DrawFocusRect( hdc, &temp ); }
} else { // push this tab down one border width...
// this will mean an extra +1 on all ANGLE_Ys...
// left side dark border
SelectPen( hdc, hFramePen ); MoveToEx(hdc, pTab->left, pTab->bottom, NULL); LineTo(hdc, pTab->left, pTab->top + (ANGLE_Y+1)*yWidth); // left side angle dark border
LineTo(hdc, pTab->left + ANGLE_X*xWidth, pTab->top+yWidth); // top dark border
LineTo(hdc, pTab->right - ANGLE_X*yWidth, pTab->top+yWidth); // right side angle dark border
LineTo(hdc, pTab->right, pTab->top + (ANGLE_Y+1)*yWidth); // right side dark border (overshoot by one)
LineTo(hdc, pTab->right, pTab->bottom+yWidth);
// left side hilite
SelectPen( hdc, hHighlightPen); MoveToEx(hdc, pTab->left+xWidth, pTab->bottom, NULL); LineTo(hdc, pTab->left+xWidth, pTab->top+(ANGLE_Y+1)*yWidth); // left side angle hilight
LineTo(hdc, pTab->left+ANGLE_X*xWidth, pTab->top+2*yWidth); // top hilite
LineTo(hdc, pTab->right-ANGLE_X*xWidth, pTab->top+2*yWidth); // right side angle shadow
SelectPen( hdc, hShadowPen); LineTo(hdc, pTab->right-xWidth, pTab->top+(ANGLE_Y+1)*yWidth); // right side shadow (overshoot by one)
LineTo(hdc, pTab->right-xWidth, pTab->bottom+yWidth);
// clean above left angle
SelectPen( hdc, hBackPen ); MoveToEx(hdc, pTab->left, pTab->top+ANGLE_Y*yWidth, NULL ); LineTo(hdc, pTab->left+ANGLE_X*xWidth, pTab->top ); // clean above top
LineTo(hdc, pTab->right-ANGLE_X*xWidth, pTab->top); // clean above right angle
LineTo(hdc, pTab->right, pTab->top+ANGLE_Y*yWidth ); // clean last corner
LineTo(hdc, pTab->right, pTab->top+(ANGLE_Y+1)*yWidth );
// clean up inside left hilite
MoveToEx(hdc, pTab->left+2*xWidth, pTab->bottom, NULL ); LineTo(hdc, pTab->left+2*xWidth, pTab->top+(ANGLE_Y+1)*yWidth); // clean up inside left angle hilite
LineTo(hdc, pTab->left+ANGLE_X*xWidth, pTab->top+3*yWidth); // clean up inside top hilite (noop)
LineTo(hdc, pTab->right-ANGLE_X*xWidth, pTab->top+3*yWidth); // clean up inside right angle shadow (noop)
LineTo(hdc, pTab->right-2*xWidth, pTab->top+(ANGLE_Y+1)*yWidth); // clean up inside left hilite (overshoot by one)
LineTo(hdc, pTab->right-2*xWidth, pTab->bottom+yWidth);
// clear out the old label...
FillRect( hdc, pText, hBackBrush ); // now print in the label ...
hfOldFont = SelectObject( hdc, pData->hfUnselected ); ExtTextOut( hdc, pText->left+ CARAT_X*xWidth + FLUFF_X*xWidth, pText->top + CARAT_Y*yWidth + FLUFF_Y*yWidth + yWidth, 0, NULL, pData->tab[i].label, lstrlen(pData->tab[i].label), NULL ); SelectFont( hdc, hfOldFont ); } }
SelectPen( hdc, hOldPen);
// put the DC we used back into circulation
ReleaseDC( hwnd, hdc );
// tell windows that we're done
EndPaint( hwnd, &ps ); // clean up
DeleteObject( hHighlightPen ); DeleteObject( hShadowPen ); DeleteObject( hFramePen ); DeleteObject( hBackPen ); DeleteObject( hBackBrush ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnSize()
//
// Handles requests from windows that we should resize ourselves
//
// Input:
// hwnd - our window handle
// state - an indication of Minimized, maximized, iconic, blah blah blah
// cx - our new width
// cy - our new height
//
// Returns:
// hopefully :)
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnSize(HWND hwnd, UINT state, int cx, int cy) { // need to update the button size stuff, just for hit testing
BookTab_UpdateButtons(hwnd); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnSetFocus()
//
// Handles windows telling us that we just got the focus
//
// Input:
// hwnd - our window handle
// hwndOld - the guy who used to have the focus (i don't use)
//
// Returns:
// nyaytay
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnSetFocus(HWND hwnd, HWND hwndOldFocus) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that we are on the bottom
SetWindowPos( hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW );
// we gotta repaint just the rect for the active tab
InvalidateRect( hwnd, &(pData->tab[pData->selected_tab].tab_rect), FALSE ); UpdateWindow( hwnd ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnKillFocus()
//
// Handles windows telling us that we are just about to lose the focus
//
// Input:
// hwnd - our window handle
// hwndNew - the lucky guy who is about to have the focus (i don't use)
//
// Returns:
// nyaytay
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnKillFocus(HWND hwnd, HWND hwndNewFocus) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// we gotta repaint just the rect for the active tab
InvalidateRect( hwnd, &(pData->tab[pData->selected_tab].tab_rect), FALSE ); UpdateWindow( hwnd ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnKey()
//
// Handes key messages sent to the control
//
// Input:
// hwnd - our window handle
// vk - the virtual key code
// fDown - is the key down?
// cRepeat - how many times it was pressed
// flags - i don't use
//
// Returns:
// nada
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// don't want key up messages
if( fDown == FALSE ) return;
// we only handle left and right cursor
switch( vk ) { case VK_LEFT: // move to the tab to the left (wrap if needed)
BookTab_OnSetCurSel( hwnd, (pData->selected_tab == 0)? (pData->total_tabs-1):(pData->selected_tab-1));
// notify our parent that the selection has changed
SendMessage( pData->hwndParent, BTN_SELCHANGE, pData->selected_tab, (DWORD_PTR)hwnd); break;
case VK_RIGHT: BookTab_OnSetCurSel( hwnd, (pData->selected_tab+1) % (pData->total_tabs));
// notify our parent that the selection has changed
SendMessage( pData->hwndParent, BTN_SELCHANGE, pData->selected_tab, (DWORD_PTR)hwnd); break; } }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnGetDlgCode()
//
// The windows dialog manager is asking us what type of user inputs we want
//
// Input:
// hwnd - our window handle
// lpmsg - who knows, I don't use it, it's not in the paper docs...
//
// Returns:
// a word which is a bitmap of input types
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnGetDlgCode(HWND hwnd, MSG FAR* lpmsg) { // We just want cursor keys and character keys
return( DLGC_WANTARROWS | DLGC_WANTCHARS ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnEnable()
//
// Windows is telling us that we are being enabled/disabled
//
// Input:
// hwnd - our window handle
// fEnable - Are we being enabled?
//
// Returns:
// nada
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnEnable(HWND hwnd, BOOL fEnable) { // BUGBUG - we look no different in either state
}
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnAddItem()
//
// Adds an item to the end of the tab list
//
// Input:
// hwnd - our window handle
// text - the label of the tab to add
//
// Returns:
// the index of the item as added
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnAddItem( HWND hwnd, LPTSTR text ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// call the worker for insert with the current end of the tab lizst
return( BookTab_OnInsertItem( hwnd, pData->total_tabs, text) ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnInsertItem()
//
// Inserts the given item at the spot indicated and shoves the others down
//
// Input:
// hwnd - our window handle
// index - the proposed index of the new item
// text - the label to add to the new tab
//
// Returns:
// the ACTUAL new index of the item (we could sort or have to reduce
// the initial request if it would leave a gap)
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnInsertItem( HWND hwnd, UINT index, LPTSTR text) { LPTABDATA pData; int i;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that the text will fit
if( lstrlen( text ) > MAX_TAB_LABEL_LEN-1 ) return (UINT)-1;
// are we full
// BUGBUG, limit in the future
if( pData->total_tabs >= MAX_TABS ) // we can not add at this time
return (UINT)-1;
// make sure that the requested index is within or adjacent to currently
// used spots
if( index > pData->total_tabs ) // change it so that index now points at the next open slot
index = pData->total_tabs;
// slide over all tabs above
for( i = (int)pData->total_tabs; i > (int)index; i-- ) { memcpy( &(pData->tab[i]), &(pData->tab[i-1]), sizeof( ONETAB) ); }
// your room is ready sir
lstrcpy( pData->tab[index].label, text ); pData->total_tabs++;
// should clear the background
pData->fUpdate = TRUE;
return index; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnDeleteItem()
//
// Deletes the item at the index given and closes up the gaps
//
// Input:
// hwnd - our window handle
// index - item to be deleted
//
// Returns:
// nuthin'
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnDeleteItem( HWND hwnd, UINT index ) { LPTABDATA pData; UINT i;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that we even have an element like this
if( index >= pData->total_tabs ) return FALSE;
// slide all of the deceased successors over
for( i = index+1; i < pData->total_tabs; i++ ) { memcpy( &(pData->tab[i-1]), &(pData->tab[i]), sizeof( ONETAB) ); }
// reduce the count to account for the deletion
pData->total_tabs--;
// should clear the background
pData->fUpdate = TRUE;
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnDeleteAllItems()
//
// Genocide on tabs
//
// Input:
// hwnd - our window handle
//
// Returns:
// nothing
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnDeleteAllItems( HWND hwnd) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// BUGBUG just set our count to zero
pData->total_tabs = 0;
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnSetItem()
//
// Sets the title of the booktab given
//
// Input:
// hwnd - our window handle
// index - the tab to label
// text - the words to put on the tab
//
// Returns:
// TRUE if successful, else False
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnSetItem( HWND hwnd, UINT index, LPTSTR text ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that the text will fit
if( lstrlen( text ) > MAX_TAB_LABEL_LEN-1 ) return FALSE;
// make sure that the index is legal
if( index >= pData->total_tabs ) return FALSE;
// set the title
lstrcpy( pData->tab[index].label, text );
// we are changing the size of the tab, we will need to clean out behind
pData->fUpdate = TRUE;
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnGetItem()
//
// Retrieves a booktab title
//
// Input:
// hwnd - our window handle
// index - the tab to label
// text - the buffer to fill with the tab title
//
// Returns:
// a pointer to the filled buffer if successful, else NULL
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnGetItem( HWND hwnd, UINT index, LPTSTR text ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that the index is legal
if( index >= pData->total_tabs ) return FALSE;
// get the title
lstrcpy( text, pData->tab[index].label ); return( TRUE ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnSetCurSel()
//
// Sets the current selection
//
// Input:
// hwnd - our window handle
// newsel - the requested selection
//
// Returns:
// the new current selection
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnSetCurSel( HWND hwnd, UINT newsel ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// make sure that the requested selection is within the proper bounds
if( newsel >= pData->total_tabs ) return( pData->selected_tab );
// make sure that the selection actually changed
if( newsel != pData->selected_tab ) { // set selection
pData->selected_tab = newsel;
// make us redraw
InvalidateRect( hwnd, NULL, FALSE ); UpdateWindow( hwnd ); }
return( pData->selected_tab ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_GetCurSel()
//
// Retrieves the current selection
//
// Input:
// hwnd - our window handle
//
// Returns:
// the current selection
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnGetCurSel( HWND hwnd ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// get selection
return( pData->selected_tab ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnGetItemCount()
//
// Retrieves the number of tabs currently in use
//
// Input:
// hwnd - our window handle
//
// Returns:
// the number of tabs in use
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
UINT BookTab_OnGetItemCount( HWND hwnd ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// get the number of tabs
return( pData->total_tabs ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnSetItemData()
//
// Adds a DWORD of data to the data structure for the given tab
//
// Input:
// hwnd - our window handle
// index - which tab to add data to
// data - what to add
//
// Returns:
// TRUE if succcessful, else FALSE
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL BookTab_OnSetItemData( HWND hwnd, UINT index, DWORD data ) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// set the instance data
pData->tab[index].data = data;
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnPutInBack()
//
// Sets the focus to the booktab and then back to whoever had it first,
// this seemes to put this control in the very back.
//
// Input:
// hwnd - our window handle
//
// Returns:
// <nothing>
//
// History
// Arthur Brooking 1/21/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_OnPutInBack( HWND hwnd ) { HWND hwndOldFocus;
// set the focus to us
hwndOldFocus = SetFocus( hwnd );
// if there was an old focus, set it back to that.
if( hwndOldFocus ) SetFocus( hwndOldFocus );
}
//////////////////////////////////////////////////////////////////////////////
// BookTab_OnGetItemData()
//
// Gets the DWORD of data stored in the data structure for the given tab
//
// Input:
// hwnd - our window handle
// index - which tab to get data from
//
// Returns:
// the stored DWORD
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
DWORD BookTab_OnGetItemData( HWND hwnd, UINT index) { LPTABDATA pData;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// get the instance data
return( (DWORD)pData->tab[index].data ); }
//////////////////////////////////////////////////////////////////////////////
// IsPointInRect()
//
// determines if the point specifier is in the rectangle specified
//
// Input:
// given_x - x coordinate of the point to be tested
// given_y - y coordinate of the point to be tested
// pTab - a pointer to the rectangle to test against
//
// Returns:
// True if the point is within the rectangle, False if not
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
BOOL IsPointInRect( int given_x, int given_y, LPRECT pRect ) { // is it above
if( given_y < pRect->top ) return FALSE;
// is it below
if( given_y > pRect->bottom ) return FALSE;
// is it to the left
if( given_x < pRect->left ) return FALSE;
// is it to the right
if( given_x > pRect->right ) return FALSE;
// well, it must be inside
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
// BookTab_UpdateButtons()
//
// Takes the current data and updates the sizes of the tabs
//
// Input:
// hwnd - our window handle
//
// Returns:
// nuthin
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
void BookTab_UpdateButtons( HWND hwnd ) { LPTABDATA pData; HDC hdc; SIZE cur_size; RECT total_rect; WORD yWidth; WORD xWidth; UINT left; UINT i; HFONT hfOldFont;
// get the instance data
pData = GetInstanceDataPtr( hwnd );
// preset this so that the MAXes later will work
pData->tabs_rect.bottom = 0; xWidth = (WORD) GetSystemMetrics(SM_CXBORDER); yWidth = (WORD) GetSystemMetrics(SM_CYBORDER); GetClientRect( hwnd, &total_rect); // BUGBUG cheat to see the whole thing
total_rect.bottom -= yWidth; total_rect.right -= xWidth;
hdc = GetDC( hwnd );
// use the selected font (BOLD) to size the tabs
hfOldFont = SelectObject( hdc, pData->hfSelected );
// loop thru the tabs
left = total_rect.left; for( i = 0; i < pData->total_tabs; i++ ) { // get the size of the data for this tab
GetTextExtentPoint( hdc, pData->tab[i].label, lstrlen( pData->tab[i].label), &cur_size);
// calculate the text rectatangle first ...
// the text top is down the size of the angle
pData->tab[i].text_rect.top = total_rect.top + ANGLE_Y*yWidth;
// the text left is over the size of the angle
pData->tab[i].text_rect.left = left + ANGLE_X*xWidth;
// the text bottom is down from the top the size of the text +
// 2x the fluff(top and bottom) + 2x the carat space
pData->tab[i].text_rect.bottom = pData->tab[i].text_rect.top + cur_size.cy + 2*FLUFF_Y*yWidth + 2*CARAT_Y*yWidth;
// the text right is over from the left the size of the text +
// 2x the fluff(left and right) + 2x the carat space
pData->tab[i].text_rect.right = pData->tab[i].text_rect.left + cur_size.cx + 2*FLUFF_X*xWidth + 2*CARAT_X*xWidth;
// then calculate the full tab rectangle
// the tab top is the top of the control
pData->tab[i].tab_rect.top = total_rect.top;
// the left side of the tab is next to the previous right
pData->tab[i].tab_rect.left = left;
// the tab bottom is down the footroom from the text bottom
pData->tab[i].tab_rect.bottom = pData->tab[i].text_rect.bottom + FOOTROOM_Y*yWidth;
// the tab right is over the size of the angle from the text right
pData->tab[i].tab_rect.right = pData->tab[i].text_rect.right + ANGLE_Y*yWidth;
// set the left for the next guy to be our right
left = pData->tab[i].tab_rect.right;
// set the bottom of the all tabs rectangle
pData->tabs_rect.bottom = max( pData->tabs_rect.bottom, pData->tab[i].tab_rect.bottom);
// BUGBUG check for run off the side
}
// set the rest of the cumulative tabs rect
pData->tabs_rect.top = total_rect.top; pData->tabs_rect.right = total_rect.right; pData->tabs_rect.left = total_rect.left; // BUGBUG why
pData->tabs_rect.bottom++;
// reset the font
SelectObject( hdc, hfOldFont );
// free up the resources used
ReleaseDC( hwnd, hdc ); }
//////////////////////////////////////////////////////////////////////////////
// BookTab_()
//
//
//
// Input:
// hwnd - our window handle
//
// Returns:
//
//
// History
// Arthur Brooking 8/06/93 created
//////////////////////////////////////////////////////////////////////////////
|