Created
August 27, 2012 19:36
-
-
Save tig/3491637 to your computer and use it in GitHub Desktop.
ItsyBitsy window support module (itsybits)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///////////////////////////////////////////////////////////////////////// | |
// | |
// Project: ItsyBitsy window support module | |
// Module: itsybits.c | |
// | |
// | |
// ItsyBitsy is a support module that allows you to create windows | |
// that look and act very much like a popup window witha system | |
// menu and caption bar, except everything is scaled to about 2/3 | |
// scale. | |
// | |
// For documentation on how to use ItsyBits, read the document | |
// ITSYBITS.DOC. | |
// | |
// Revisions: | |
// 9/27/91 Charlie Kindel (cek/ckindel) | |
// Wrote and documented it. | |
// | |
// 1/14/93 cek | |
// 2/23/93 cek Added minimize/maximize buttons. | |
// 3/18/93 cek Fixed system menu bug where system menu | |
// popped back up if you clicked on the | |
// icon again while it was up. | |
// 3/24/93 cek More comments. Fixed DS_MODALDIALOG style | |
// problem. Use auto precompiled headers | |
// in MSVC. | |
// | |
////////////////////////////////////////////////////////////////////////// | |
#include <windows.h> | |
#include <windowsx.h> | |
#include <memory.h> | |
#include "itsybits.h" | |
#include <stdlib.h> | |
#ifdef __BORLANDC__ | |
#define max(a,b) (((a) > (b)) ? (a) : (b)) | |
#define min(a,b) (((a) < (b)) ? (a) : (b)) | |
#endif | |
// CAPTIONXY is the default size of the system menu icon. This | |
// determines the height/width of the caption. | |
// | |
// The value that results from the following formula works out | |
// nicely for the veritcal caption on VGA, 8514 (Large Fonts), | |
// 8514 (Small Fonts), XGA (Small Fonts), XGA (Large Fonts), | |
// and TIGA (Small Fonts). It may not be good on other displays. | |
// | |
// The problem is that TT fonts turn into bitmap fonts when they | |
// are sized below a certain threshold. The idea is to make the | |
// size of the caption just big enough to get the smallest TT | |
// (scalable) font to fit. | |
// | |
#define CAPTIONXY (GetSystemMetrics( SM_CYCAPTION ) / 2 + 1) | |
#define TestWinStyle( hWnd, dwStyleBit ) \ | |
(((DWORD)GetWindowLong( hWnd, GWL_STYLE ) & (DWORD)dwStyleBit) ? TRUE : FALSE ) | |
#define HASCAPTION( hwnd ) (TestWinStyle( hwnd, IBS_VERTCAPTION ) ||\ | |
TestWinStyle( hwnd, IBS_HORZCAPTION )) | |
#define SETCAPTIONSIZE(h,i) (UINT)SetProp(h,"ibSize",(HANDLE)i) | |
#define GETCAPTIONSIZE(h) (UINT)GetProp(h,"ibSize") | |
#define FREECAPTIONSIZE(h) RemoveProp(h,"ibSize") | |
#define SETMENUWASUPFLAG(h,i) (UINT)SetProp(h,"ibFlag",(HANDLE)i) | |
#define GETMENUWASUPFLAG(h) (UINT)GetProp(h,"ibFlag") | |
#define FREEMENUWASUPFLAG(h) RemoveProp(h,"ibFlag") | |
///////////////////////////////////////////////////////////////////// | |
// Little known fact: | |
// ExtTextOut() is the fastest way to draw a filled rectangle | |
// in Windows (if you don't want dithered colors or borders). | |
// | |
// Unfortunately there is a bug in the Windows 3.0 8514 driver | |
// in using ExtTextOut() to a memory DC. If you are drawing | |
// to an off screen bitmap, then blitting that bitmap to the | |
// display, do not #define USE_EXTTEXTOUT below. | |
// | |
// The following macro (DRAWFASTRECT) draws a filled rectangle | |
// with no border and a solid color. It uses the current back- | |
// ground color as the fill color. | |
////////////////////////////////////////////////////////////////////// | |
#define USE_EXTTEXTOUT | |
#ifdef USE_EXTTEXTOUT | |
#define DRAWFASTRECT(hdc,lprc) ExtTextOut(hdc,0,0,ETO_OPAQUE,lprc,NULL,0,NULL) | |
#else | |
#define DRAWFASTRECT(hdc,lprc) {\ | |
HBRUSH hbr = CreateSolidBrush( GetBkColor( hdc ) ) ;\ | |
hbr = SelectObject(hdc, hbr) ;\ | |
PatBlt(hdc,(lprc)->left,(lprc)->top,(lprc)->right-(lprc)->left,(lprc)->bottom-(lprc)->top,PATCOPY) ;\ | |
hbr = SelectObject(hdc, hbr) ;\ | |
DeleteObject( hbr ) ;\ | |
} | |
#endif | |
// The DrawArrow function takes the following to indicate what | |
// kind of arrow to draw. | |
// | |
#define ARROW_UP 0 | |
#define ARROW_DOWN 1 | |
#define ARROW_RESTORE 2 | |
BOOL NEAR PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT ) ; | |
BOOL NEAR PASCAL DoMenu( HWND hWnd ) ; | |
void NEAR PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu ) ; | |
BOOL NEAR PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc ) ; | |
BOOL NEAR PASCAL GetIconRect( HWND hWnd, LPRECT lprc ) ; | |
BOOL NEAR PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc ) ; | |
BOOL NEAR PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc ) ; | |
BOOL NEAR PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc ) ; | |
BOOL NEAR PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc, | |
BOOL fVert, BOOL fSysMenu, | |
BOOL fMin, BOOL fMax, BOOL fActive ) ; | |
VOID NEAR PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert ) ; | |
VOID NEAR PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed ) ; | |
VOID NEAR PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle ) ; | |
// Global vars | |
// | |
static BOOL fWin31 ; | |
/////////////////////////////////////////////////////////////////////// | |
// External/Public functions | |
/////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////// | |
// UINT WINAPI ibGetCaptionSize( HWND hWnd ) | |
// | |
// Description: | |
// | |
// Gets the size of the caption (height if horz, width if | |
// vertical). | |
// | |
// Comments: | |
// | |
/////////////////////////////////////////////////////////////// | |
UINT WINAPI ibGetCaptionSize( HWND hWnd ) | |
{ | |
return GETCAPTIONSIZE( hWnd ) + 1 ; | |
} // ibSetCaptionSize() | |
///////////////////////////////////////////////////////////////// | |
// UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize ) | |
// | |
// Description: | |
// | |
// Changes the size of the caption (height if horz, width if | |
// vertical). | |
// | |
// Comments: | |
// | |
////////////////////////////////////////////////////////////////// | |
UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize ) | |
{ | |
UINT ui ; | |
if (nSize <= 0) | |
return 0 ; | |
nSize-- ; | |
ui = SETCAPTIONSIZE( hWnd, nSize ) ; | |
// Once we change the window style, we need a WM_NCCALCRECT | |
// to be generated. | |
// | |
// SWP_FRAMECHANGED is not documented in the 3.1 SDK docs, | |
// but *is* in WINDOWS.H. | |
// | |
SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | | |
SWP_NOSIZE | SWP_NOMOVE | | |
SWP_NOACTIVATE | SWP_NOZORDER) ; | |
return ui ; | |
} // ibSetCaptionSize() | |
///////////////////////////////////////////////////////////////// | |
// LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) | |
// | |
// Description: | |
// | |
// This function should be called instead of DefWindowProc() for | |
// windows that want to have itsybitsy captions. | |
// | |
// Comments: | |
// | |
////////////////////////////////////////////////////////////////// | |
LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) | |
{ | |
LRESULT lRet ; | |
UINT nCapSize ; | |
switch( uiMsg ) | |
{ | |
case WM_SYSCHAR: | |
// If ALT-SPACE | |
// was hit then pop up the menu | |
// | |
if (HASCAPTION( hWnd ) && (wParam == VK_SPACE)) | |
{ | |
DoMenu( hWnd ) ; | |
break ; | |
} | |
// FALL THROUGH!!!! | |
// | |
case WM_SYSKEYDOWN: | |
case WM_SYSKEYUP: | |
case WM_KEYDOWN: | |
case WM_KEYUP: | |
{ | |
DWORD dw = GetWindowLong( hWnd, GWL_STYLE ) ; | |
// Fool DefWindowProc into thinking we do not have | |
// a system menu. Otherwise it will try to | |
// pop up its own. | |
// | |
SetWindowLong( hWnd, GWL_STYLE, dw &~WS_SYSMENU ) ; | |
lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
SetWindowLong( hWnd, GWL_STYLE, dw ) ; | |
return lRet ; | |
} | |
break ; | |
case WM_COMMAND: | |
// The menu that is poped up for the system menu with | |
// TrackPopupMenu() sends it's notifications as WM_COMMAND | |
// messages. We need to translate these into | |
// WM_SYSCOMMAND messages. All standard WM_SYSCOMMAND | |
// ids are greater than 0xF000. | |
// | |
// This could be a possible cause of confusion if the | |
// itsybitsy window had children that used SC_MOVE or SC_CLOSE | |
// as their IDs. Take note and be careful. | |
// | |
// Also, because ibDefWindowProc looks at WM_COMMAND messages, | |
// you will need to be careful to call ibDefWindowProc() for | |
// any wm_command messages that you would normally ignore. | |
// Otherwise the system menu won't work. | |
// | |
if (wParam >= 0xF000) | |
// Call PostMessage() here instead of SendMessage! | |
// Here's why: | |
// Our menu was created by TrackPopupMenu(). TPM() does | |
// not return until after the menu has been destroyed | |
// (and thus the command associated with the menu selection | |
// sent). Therefore when we get here, we are still | |
// *inside* TPM(). If we Send WM_SYSCOMMAND, SC_CLOSE | |
// to the window, the window will be destroyed before | |
// TPM() returns to our code within DoMenu() below. Wel... | |
// We do stuff with the window handle after DoMenu() | |
// returns (namely GetProp()). Since the window has | |
// been destroyed,this is bad. | |
PostMessage( hWnd, WM_SYSCOMMAND, wParam, lParam ) ; | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
case WM_GETMINMAXINFO: | |
{ | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
if (HASCAPTION( hWnd ) && TestWinStyle( hWnd, WS_THICKFRAME )) | |
{ | |
LPPOINT lppt = (LPPOINT)lParam ; | |
RECT rcMenu ; | |
RECT rcMin ; | |
RECT rcMax ; | |
int nX ; | |
int cx, cy ; // window frame/border width | |
if (TestWinStyle( hWnd, WS_THICKFRAME )) | |
{ | |
cx = GetSystemMetrics( SM_CXFRAME ) ; | |
cy = GetSystemMetrics( SM_CYFRAME ) ; | |
} | |
else | |
if (TestWinStyle(hWnd, WS_BORDER )) | |
{ | |
cx = GetSystemMetrics( SM_CXBORDER ) ; | |
cy = GetSystemMetrics( SM_CYBORDER ) ; | |
} | |
GetIconRect( hWnd, &rcMenu ) ; | |
GetMinButtonRect( hWnd, &rcMin ) ; | |
GetMaxButtonRect( hWnd, &rcMax ) ; | |
nX = (rcMenu.right-rcMenu.left) + | |
(rcMin.right-rcMin.left) + | |
(rcMin.right-rcMin.left) ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION ) ) | |
{ | |
lppt[3].x = nCapSize + cx * 2 - 1 ; | |
lppt[3].y = nX + (2* nCapSize) ; | |
} | |
else | |
{ | |
lppt[3].x = nX + (2* nCapSize) ; | |
lppt[3].y = nCapSize + cy * 2 - 1 ; | |
} | |
} | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
} | |
break ; | |
///////////////////////////////////////////////////////////////////// | |
// Non-client area messages. These are used to allow the | |
// minature caption bar to be handled correctly. | |
// | |
case WM_NCCREATE: | |
{ | |
DWORD dwStyle ; | |
// We have two things that we need to store somewhere: | |
// 1) The caption height (width). | |
// and 2) A flag indicating whether the sysmenu was | |
// just up or not. | |
// | |
// CAPTIONXY is a macro that calls GetSystemMetrics. | |
// | |
SETCAPTIONSIZE( hWnd, CAPTIONXY ) ; | |
// Set our flag that tells us whether the system menu was | |
// 'just up'. | |
// | |
SETMENUWASUPFLAG( hWnd, FALSE ) ; | |
// Are we in 3.1? If so we have some neat features | |
// we can use like rotated TrueType fonts. | |
// | |
fWin31 = (BOOL)(LOWORD( GetVersion() ) >= 0x030A) ; | |
// If IBS_????CAPTION was specified and the WS_DLGFRAME (or | |
// WS_DLGFRAME 'cause it == WS_CAPTION | WS_BORDER) | |
// was specified the creator made a mistake. Things get really | |
// ugly if DefWindowProc sees WS_DLGFRAME, so we strip | |
// the WS_DLGFRAME part off! | |
// | |
dwStyle = GetWindowLong( hWnd, GWL_STYLE ) ; | |
if ((dwStyle & IBS_VERTCAPTION || dwStyle & IBS_HORZCAPTION) && | |
dwStyle & WS_DLGFRAME) | |
{ | |
dwStyle &= (DWORD)~WS_DLGFRAME ; | |
SetWindowLong( hWnd, GWL_STYLE, dwStyle ) ; | |
} | |
} | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
case WM_NCDESTROY: | |
// We store the caption size in a window prop. so we | |
// must remove props. | |
// | |
FREECAPTIONSIZE( hWnd ) ; | |
FREEMENUWASUPFLAG( hWnd ) ; | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
case WM_NCCALCSIZE: | |
// This is sent when the window manager wants to find out | |
// how big our client area is to be. If we have a mini-caption | |
// then we trap this message and calculate the cleint area rect, | |
// which is the client area rect calculated by DefWindowProc() | |
// minus the width/height of the mini-caption bar | |
// | |
lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
if (!IsIconic( hWnd ) && HASCAPTION( hWnd )) | |
{ | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION ) ) | |
((LPRECT)lParam)->left += nCapSize ; | |
else | |
((LPRECT)lParam)->top += nCapSize ; | |
} | |
return lRet ; | |
case WM_NCHITTEST: | |
// This message is sent whenever the mouse moves over us. | |
// We will depend on DefWindowProc for everything unless | |
// there is a mini-caption, in which case we will | |
// return HTCAPTION or HTSYSMENU. When the user clicks | |
// or double clicks, NC_LBUTTON/ message are sent with | |
// wParam equal to what we return here. | |
// This means that this is an ideal place to figure out | |
// where we are! | |
// | |
// let defwindowproc handle the standard borders etc... | |
// | |
lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && lRet == HTNOWHERE) | |
{ | |
RECT rc ; | |
RECT rcMenu ; | |
RECT rcMinButton ; | |
RECT rcMaxButton ; | |
POINT pt ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
// if DefWindowProc returned HTCAPTION then we have to | |
// refine the area and return HTSYSMENU if appropriate | |
// | |
pt.x = LOWORD( lParam ) ; | |
pt.y = HIWORD( lParam ) ; | |
GetCaptionRect( hWnd, &rc ) ; // window coords | |
if (PtInRect( &rc, pt )) | |
{ | |
lRet = HTCAPTION ; | |
// rely on the fact that Get???Rect() return an invalid | |
// (empty) rectangle if the menu/buttons don't exist | |
// | |
GetIconRect( hWnd, &rcMenu ) ; | |
GetMinButtonRect( hWnd, &rcMinButton ) ; | |
GetMaxButtonRect( hWnd, &rcMaxButton ) ; | |
if (PtInRect( &rcMenu, pt )) | |
lRet = HTSYSMENU ; | |
if (PtInRect( &rcMinButton, pt )) | |
lRet = HTMINBUTTON ; | |
else | |
if (PtInRect( &rcMaxButton, pt )) | |
lRet = HTMAXBUTTON ; | |
} | |
} | |
if (lRet != HTSYSMENU) | |
SETMENUWASUPFLAG( hWnd, FALSE ) ; | |
return lRet ; | |
case WM_NCLBUTTONDBLCLK: | |
// Windows recieve WM_NC?BUTTONDBLCLK messages whether they | |
// have CS_DBLCLKS or not. We watch for one of these | |
// to see if the user double clicked on the system menu (to | |
// close the window) or on the caption (to maximize the window). | |
// | |
if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && wParam == HTSYSMENU) | |
{ | |
SendMessage( hWnd, WM_CLOSE, 0, 0L ) ; | |
break ; | |
} | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
case WM_NCLBUTTONDOWN: | |
{ | |
RECT rc ; | |
// If we're iconic or we don't have a caption then | |
// DefWindowProc will do the job just fine. | |
// | |
if (IsIconic( hWnd ) || !HASCAPTION( hWnd )) | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
// Here's were we handle the system menu, the min and max buttons. | |
// If you wanted to change the behavior of the min/max buttons | |
// do something like swap tool palettes or something, you | |
// would change the SendMessage() calls below. | |
// | |
switch (wParam) | |
{ | |
case HTSYSMENU: | |
if (GETMENUWASUPFLAG( hWnd ) == FALSE && DoMenu( hWnd )) | |
SETMENUWASUPFLAG( hWnd, TRUE ) ; | |
else | |
SETMENUWASUPFLAG( hWnd, FALSE ) ; | |
break ; | |
case HTMINBUTTON: | |
GetMinButtonRect( hWnd, &rc ) ; | |
// Note that DepressMinMaxButton() goes into | |
// a PeekMessage() loop waiting for the mouse | |
// to come back up. | |
// | |
if (DepressMinMaxButton( hWnd, wParam, &rc )) | |
SendMessage( hWnd, WM_SYSCOMMAND, SC_MINIMIZE, lParam ) ; | |
break ; | |
case HTMAXBUTTON: | |
GetMaxButtonRect( hWnd, &rc ) ; | |
// Note that DepressMinMaxButton() goes into | |
// a PeekMessage() loop waiting for the mouse | |
// to come back up. | |
// | |
if (DepressMinMaxButton( hWnd, wParam, &rc )) | |
{ | |
if (IsZoomed(hWnd)) | |
SendMessage( hWnd, WM_SYSCOMMAND, SC_RESTORE, lParam ) ; | |
else | |
SendMessage( hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, lParam ) ; | |
} | |
break ; | |
default: | |
// Well, it appears as though the user clicked somewhere other | |
// than the buttons. We let DefWindowProc do it's magic. | |
// This is where things like dragging and sizing the | |
// window happen. | |
// | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
} | |
} | |
break ; | |
case WM_NCPAINT: | |
case WM_NCACTIVATE: | |
if (IsIconic( hWnd )) | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
// Paint the non-client area here. We will call DefWindowProc | |
// after we are done so it can paint the borders and so | |
// forth... | |
// | |
lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
if (HASCAPTION( hWnd )) | |
{ | |
RECT rcCap ; | |
RECT rc ; | |
HDC hDC = GetWindowDC( hWnd ) ; | |
BOOL fActive ; | |
GetCaptionRect( hWnd, &rcCap ) ; // Convert to window coords | |
GetWindowRect( hWnd, &rc ) ; | |
OffsetRect( &rcCap, -rc.left, -rc.top ) ; | |
if (uiMsg == WM_NCPAINT) | |
fActive = (hWnd == GetActiveWindow()) ; | |
else | |
fActive = wParam ; | |
DrawCaption( hDC, hWnd, &rcCap, | |
TestWinStyle(hWnd, IBS_VERTCAPTION), | |
TestWinStyle(hWnd, WS_SYSMENU), | |
TestWinStyle(hWnd, WS_MINIMIZEBOX), | |
TestWinStyle(hWnd, WS_MAXIMIZEBOX), | |
fActive ) ; | |
ReleaseDC( hWnd, hDC ) ; | |
} | |
return lRet; | |
break; | |
default: | |
return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ; | |
} | |
return 0L ; | |
} // ibDefWindowProc() | |
// ibAdjustWindowRect( HWND hWnd, LPRECT lprc ) | |
// | |
// Does the same thing as the USER function AdjustWindowRect(), | |
// but knows about itsybitsy windows. AdjustWindowRect() is | |
// bogus for stuff like this. | |
// | |
VOID WINAPI ibAdjustWindowRect( HWND hWnd, LPRECT lprc ) | |
{ | |
short cx = 0, cy = 0 ; | |
UINT nCapSize ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
// First check Windows's styles, then our own. | |
// | |
if (TestWinStyle( hWnd, WS_THICKFRAME )) | |
{ | |
cx = GetSystemMetrics( SM_CXFRAME ) ; | |
cy = GetSystemMetrics( SM_CYFRAME ) ; | |
} | |
else | |
if (TestWinStyle(hWnd, DS_MODALFRAME )) | |
{ | |
cx = GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ; | |
cy = GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ; | |
} | |
else | |
if (TestWinStyle(hWnd, WS_BORDER )) | |
{ | |
cx = GetSystemMetrics( SM_CXBORDER ) ; | |
cy = GetSystemMetrics( SM_CYBORDER ) ; | |
} | |
InflateRect( lprc, cx, cy ) ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
lprc->left -= nCapSize ; | |
else | |
if (TestWinStyle( hWnd, IBS_HORZCAPTION )) | |
lprc->top -= nCapSize ; | |
} // ibAdjustWindowRect() | |
/////////////////////////////////////////////////////////////////////// | |
// Internal functions | |
/////////////////////////////////////////////////////////////////////// | |
// DepressMinMaxButton() | |
// | |
// This function is called when the user has pressed either the min or | |
// max button (i.e. WM_NCLBUTTONDOWN). We go into a Peekmessage() loop, | |
// waiting for the mouse to come back up. This allows us to make the | |
// button change up/down state like a real button does. | |
// | |
// lprc points to the rectangle that describes the button the | |
// user has clicked on. | |
// | |
BOOL NEAR PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT lprc ) | |
{ | |
BOOL fDepressed = TRUE ; | |
MSG msg ; | |
// Draw button in down state | |
DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed ) ; | |
SetCapture( hWnd ) ; | |
while (TRUE) | |
{ | |
if (PeekMessage((LPMSG)&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) | |
{ | |
switch (msg.message) | |
{ | |
case WM_LBUTTONUP: | |
if (fDepressed) | |
DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, !fDepressed ) ; | |
ReleaseCapture(); | |
return PtInRect( lprc, msg.pt ) ; | |
case WM_MOUSEMOVE: | |
if (PtInRect( lprc, msg.pt )) | |
{ | |
if (!fDepressed) | |
DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = TRUE ) ; | |
} | |
else | |
{ | |
if (fDepressed) | |
DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = FALSE ) ; | |
} | |
break; | |
} | |
} | |
} | |
} // DepressMinMaxButton() | |
// DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc, | |
// BOOL fVert, BOOL fSysMenu, BOOL fActive ) | |
// | |
// This function draws an itsy bitsy caption bar with or | |
// without system menu to the dc specified by hDC. The | |
// caption is drawn to fit within the lprc RECT and is | |
// drawn//withOut/ borders. | |
// | |
BOOL NEAR PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc, | |
BOOL fVert, BOOL fSysMenu, BOOL fMin, | |
BOOL fMax, BOOL fActive ) | |
{ | |
RECT rc ; | |
RECT rcCap ; | |
COLORREF rgbCaptionBG ; | |
COLORREF rgbText ; | |
COLORREF rgbWindowFrame ; | |
HBRUSH hbrCaption ; | |
UINT ui ; | |
UINT nCapSize ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
// Get the colors. | |
// | |
rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ; | |
// if we have focus use the active caption color | |
// otherwise use the inactive caption color | |
// | |
if (fActive) | |
{ | |
rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ; | |
rgbCaptionBG = GetSysColor( COLOR_ACTIVECAPTION ) ; | |
} | |
else | |
{ | |
if (fWin31) | |
rgbText = GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ; | |
else | |
rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ; | |
rgbCaptionBG = GetSysColor( COLOR_INACTIVECAPTION ) ; | |
} | |
SetBkMode( hDC, TRANSPARENT ) ; | |
SelectObject( hDC, GetStockObject( NULL_BRUSH ) ) ; | |
SelectObject( hDC, GetStockObject( NULL_PEN ) ) ; | |
rcCap = *lprc ; | |
if (fSysMenu) | |
{ | |
if (fVert) | |
rcCap.top += nCapSize ; | |
else | |
rcCap.left += nCapSize ; | |
} | |
if (fMax) | |
{ | |
if (fVert) | |
rcCap.bottom -= nCapSize ; | |
else | |
rcCap.right -= nCapSize ; | |
} | |
if (fMin) | |
{ | |
if (fVert) | |
rcCap.bottom -= nCapSize ; | |
else | |
rcCap.right -= nCapSize ; | |
} | |
if (fVert) | |
{ | |
rc.left = lprc->right - 1 ; | |
rc.right = lprc->right ; | |
rc.top = lprc->top ; | |
rc.bottom = lprc->bottom ; | |
} | |
else | |
{ | |
rc.left = lprc->left ; | |
rc.right = lprc->right ; | |
rc.bottom = lprc->bottom ; | |
rc.top = rc.bottom - 1 ; | |
} | |
SetBkColor( hDC, rgbWindowFrame ) ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
hbrCaption = CreateSolidBrush( rgbCaptionBG ) ; | |
hbrCaption = SelectObject( hDC, hbrCaption ) ; | |
SelectObject( hDC, GetStockObject( NULL_PEN ) ) ; | |
if (fVert) | |
Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right, rcCap.bottom + 1 ) ; | |
else | |
Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right+1, rcCap.bottom ) ; | |
hbrCaption = SelectObject( hDC, hbrCaption ) ; | |
DeleteObject( hbrCaption ) ; | |
// Draw caption text here. Only do it in 3.1 'cause 3.1 gives | |
// us 'small fonts'. | |
// | |
ui = GetWindowTextLength( hWnd ) ; | |
if (fWin31) | |
{ | |
HFONT hFont ; | |
LPSTR lpsz ; | |
LOGFONT lf ; | |
TEXTMETRIC tm ; | |
int cx ; | |
int cy ; | |
SIZE Size ; | |
if (lpsz = (char*)GlobalAllocPtr( GHND, ui + 2 )) | |
{ | |
UINT nBkMode ; | |
GetWindowText( hWnd, lpsz, ui + 1 ) ; | |
nBkMode = SetBkMode( hDC, TRANSPARENT ) ; | |
rgbText = SetTextColor( hDC, rgbText ) ; | |
memset( &lf, '\0', sizeof(LOGFONT) ) ; | |
lf.lfHeight = -(int)(nCapSize - 3) ; | |
lf.lfCharSet = ANSI_CHARSET ; | |
lf.lfQuality = DEFAULT_QUALITY ; | |
lf.lfClipPrecision = CLIP_LH_ANGLES | CLIP_STROKE_PRECIS ; | |
if (nCapSize >= 20) | |
{ | |
lf.lfWeight = FW_BOLD ; | |
} | |
if (fVert) | |
{ | |
// Can only rotate true type fonts (well, ok, we could | |
// try and use "modern"). | |
lstrcpy( lf.lfFaceName, "Arial" ) ; | |
lf.lfPitchAndFamily = FF_SWISS | 0x04; | |
lf.lfEscapement = 900 ; | |
// Note: The Win 3.1 documentation for CreateFont() say's | |
// that the lfOrientation member is ignored. It appears, | |
// that on Windows 16 3.1 this is true, but when running | |
// as a 16 bit WinApp on WindowsNT 3.1 the lfOrientation | |
// must be set or the text does not rotate! | |
// | |
lf.lfOrientation = 900 ; | |
hFont = CreateFontIndirect( &lf ) ; | |
hFont = SelectObject( hDC, hFont ) ; | |
GetTextExtentPoint( hDC, lpsz, ui, &Size ) ; | |
cx = rcCap.bottom - ((rcCap.bottom - rcCap.top - Size.cx) / 2) ; | |
cy = rcCap.left - 1 + ((rcCap.right - rcCap.left - Size.cy) / 2) ; | |
// Make sure we got a rotatable font back. | |
// | |
GetTextMetrics( hDC, &tm ) ; | |
if (tm.tmPitchAndFamily & TMPF_VECTOR || | |
tm.tmPitchAndFamily & TMPF_TRUETYPE) | |
{ | |
ExtTextOut( hDC, | |
cy, | |
min( (long)cx, rcCap.bottom), | |
ETO_CLIPPED, &rcCap, | |
lpsz, ui, NULL ) ; | |
} | |
hFont = SelectObject( hDC, hFont ) ; | |
DeleteObject( hFont ) ; | |
} | |
else | |
{ | |
// Use small fonts always for the horizontal. Cause it looks | |
// more like "System" than Arial. | |
// | |
lf.lfPitchAndFamily = FF_SWISS ; | |
hFont = CreateFontIndirect( &lf ) ; | |
hFont = SelectObject( hDC, hFont ) ; | |
GetTextExtentPoint( hDC, lpsz, ui, &Size ) ; | |
cx = rcCap.left + ((rcCap.right - rcCap.left - Size.cx) / 2) ; | |
cy = rcCap.top + ((rcCap.bottom - rcCap.top - Size.cy) / 2) ; | |
// Figger out how big the string is | |
// | |
ExtTextOut( hDC, | |
max( (long)cx, rcCap.left ), | |
cy, | |
ETO_CLIPPED, &rcCap, | |
lpsz, ui, NULL ) ; | |
hFont = SelectObject( hDC, hFont ) ; | |
DeleteObject( hFont ) ; | |
} | |
// Unsetup the DC | |
// | |
rgbText = SetTextColor( hDC, rgbText ) ; | |
SetBkMode( hDC, nBkMode ) ; | |
GlobalFreePtr( lpsz ) ; | |
} | |
} | |
if (fSysMenu) | |
DrawSysMenu( hDC, hWnd, FALSE ) ; | |
if (fMin) | |
DrawButton( hDC, hWnd, TRUE, FALSE ) ; | |
if (fMax) | |
DrawButton( hDC, hWnd, FALSE, FALSE ) ; | |
return TRUE ; | |
} // DrawCaption() | |
// DrawSysMenu( HDC hDC, hWnd, BOOL fInvert ) | |
// | |
// Draws the little system menu icon. | |
// | |
VOID NEAR PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert ) | |
{ | |
RECT rcIcon ; | |
RECT rcTemp ; | |
RECT rc ; | |
COLORREF rgbIconFace ; | |
COLORREF rgbWindowFrame ; | |
BOOL fDC ; | |
UINT nCapSize ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
if (!hDC) | |
{ | |
fDC = TRUE ; | |
hDC = GetWindowDC( hWnd ) ; | |
} | |
else | |
fDC = FALSE ; | |
if (hDC) | |
{ | |
rgbIconFace = GetNearestColor( hDC, RGBLTGRAY ) ; | |
rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ; | |
GetIconRect( hWnd, &rcIcon ) ; | |
GetWindowRect( hWnd, &rc ) ; | |
OffsetRect( &rcIcon, -rc.left, -rc.top ) ; | |
rcTemp = rcIcon ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
{ | |
rc = rcIcon ; // separator line | |
rc.top = ++rc.bottom - 1 ; | |
} | |
else | |
{ | |
rc = rcIcon ; // separator line | |
rc.left = ++rc.right - 1 ; | |
} | |
// Fill | |
SetBkColor( hDC, rgbIconFace ) ; | |
DRAWFASTRECT( hDC, &rcTemp ) ; | |
// Draw separator line | |
SetBkColor( hDC, rgbWindowFrame ) ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
if (nCapSize > 4) | |
{ | |
// Draw the little horizontal doo-hickey | |
// | |
rcTemp.top = rcIcon.top + ((nCapSize-1) / 2) ; | |
rcTemp.bottom = rcTemp.top + 3 ; | |
rcTemp.left = rcTemp.left + 3 ; | |
rcTemp.right = rcTemp.right - 1 ; | |
SetBkColor( hDC, RGBGRAY ) ; | |
DRAWFASTRECT( hDC, &rcTemp ) ; | |
rc = rcTemp ; | |
OffsetRect( &rc, -1, -1 ) ; | |
SetBkColor( hDC, RGBBLACK ) ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
InflateRect( &rc, -1, -1 ) ; | |
SetBkColor( hDC, RGBWHITE ) ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
} | |
if (fInvert) | |
InvertRect( hDC, &rcIcon ) ; | |
if (fDC) | |
ReleaseDC( hWnd, hDC ) ; | |
} | |
} // DrawSysMenu() | |
// DoMenu( HWND hWnd ) | |
// | |
// Pops up the system menu. | |
// | |
BOOL NEAR PASCAL DoMenu( HWND hWnd ) | |
{ | |
HDC hDC ; | |
RECT rcIcon ; | |
RECT rc ; | |
POINT pt ; | |
HMENU hMenu ; | |
DWORD dw ; | |
if (!TestWinStyle(hWnd, WS_SYSMENU)) | |
return FALSE ; | |
if (hDC = GetWindowDC( hWnd )) | |
{ | |
// Invert the icon | |
// | |
DrawSysMenu( hDC, hWnd, TRUE ) ; | |
// Pop up the menu | |
// | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
{ | |
pt.x = -1 ; | |
pt.y = 0 ; | |
} | |
else | |
{ | |
pt.x = 0 ; | |
pt.y = -1 ; | |
} | |
GetIconRect( hWnd, &rcIcon ) ; | |
GetWindowRect( hWnd, &rc ) ; | |
OffsetRect( &rcIcon, -rc.left, -rc.top ) ; | |
ClientToScreen( hWnd, &pt ) ; | |
ClientToScreen( hWnd, (LPPOINT)&rc.right ) ; | |
dw = GetWindowLong( hWnd, GWL_STYLE ) ; | |
SetWindowLong( hWnd, GWL_STYLE, dw | WS_SYSMENU ) ; | |
hMenu = GetSystemMenu( hWnd, FALSE ) ; | |
SetupSystemMenu( hWnd, hMenu ) ; | |
SetWindowLong( hWnd, GWL_STYLE, dw ) ; | |
TrackPopupMenu( hMenu, 0, //TPM_LEFTALIGN, | |
pt.x, | |
pt.y, | |
0, | |
hWnd, | |
&rc ) ; | |
DrawSysMenu( hDC, hWnd, FALSE ) ; | |
ReleaseDC( hWnd, hDC ) ; | |
} | |
return TRUE ; | |
} // DoMenu() | |
// SetupSystemMenu( HWND hWnd, HMENU hMenu ) | |
// | |
// Enables/Disables the appropriate menu items on the | |
// menu passed for the window passed. | |
// | |
void NEAR PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu ) | |
{ | |
UINT wMove ; | |
UINT wSize ; | |
UINT wMinBox ; | |
UINT wMaxBox ; | |
UINT wRestore ; | |
// Assume all should be grayed. | |
// | |
wSize = wMove = wMinBox = wMaxBox = wRestore = MF_GRAYED ; | |
if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ) || IsIconic( hWnd )) | |
wMaxBox = MF_ENABLED ; | |
if (TestWinStyle( hWnd, WS_MINIMIZEBOX )) | |
wMinBox = MF_ENABLED ; | |
if (IsZoomed( hWnd )) | |
wRestore = MF_ENABLED ; | |
if (TestWinStyle( hWnd, WS_THICKFRAME ) && | |
!(IsIconic( hWnd ) || IsZoomed( hWnd ))) | |
wSize = MF_ENABLED ; | |
if (!IsZoomed( hWnd ) && | |
!IsIconic( hWnd ) && | |
TestWinStyle( hWnd, WS_CAPTION ) ) | |
wMove = MF_ENABLED ; | |
EnableMenuItem( hMenu, SC_MOVE, wMove ) ; | |
EnableMenuItem( hMenu, SC_SIZE, wSize ) ; | |
EnableMenuItem( hMenu, SC_MINIMIZE, wMinBox ) ; | |
EnableMenuItem( hMenu, SC_MAXIMIZE, wMaxBox ) ; | |
EnableMenuItem( hMenu, SC_RESTORE, wRestore ) ; | |
} // SetupSystemMenu() | |
// GetCaptionRect( HWND hWnd, LPRECT lprc ) | |
// | |
// calcluales the rectangle of the mini-caption in screen coords. | |
// | |
BOOL NEAR PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc ) | |
{ | |
UINT nCapSize ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
if (!HASCAPTION( hWnd )) | |
{ | |
SetRectEmpty( lprc ) ; | |
return FALSE ; | |
} | |
GetWindowRect( hWnd, lprc ) ; | |
// the window might have other non-client components like | |
// borders | |
// | |
if (TestWinStyle( hWnd, WS_THICKFRAME )) | |
{ | |
lprc->left += GetSystemMetrics( SM_CXFRAME ) ; | |
lprc->top += GetSystemMetrics( SM_CYFRAME ) ; | |
lprc->right -= GetSystemMetrics( SM_CXFRAME ) ; | |
lprc->bottom -= GetSystemMetrics( SM_CYFRAME ) ; | |
} | |
else | |
if (TestWinStyle( hWnd, DS_MODALFRAME )) // if it's a dialog box | |
{ | |
lprc->left += GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ; | |
lprc->top += GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ; | |
lprc->right -= GetSystemMetrics( SM_CXDLGFRAME ) + GetSystemMetrics( SM_CXBORDER ) ; | |
lprc->bottom -= GetSystemMetrics( SM_CYDLGFRAME ) + GetSystemMetrics( SM_CYBORDER ) ; | |
} | |
else | |
if (TestWinStyle( hWnd, WS_BORDER )) | |
{ | |
lprc->left += GetSystemMetrics( SM_CXBORDER ) ; | |
lprc->top += GetSystemMetrics( SM_CYBORDER ) ; | |
lprc->right -= GetSystemMetrics( SM_CXBORDER ) ; | |
lprc->bottom -= GetSystemMetrics( SM_CYBORDER ) ; | |
} | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
lprc->right = lprc->left + nCapSize ; | |
else | |
lprc->bottom = lprc->top + nCapSize ; | |
return TRUE ; | |
} // GetCaptionRect() | |
// GetIconRect( HWND hWnd, LPRECT lprc ) | |
// | |
// Calculates the rect of the icon in screen coordinates. | |
// | |
BOOL NEAR PASCAL GetIconRect( HWND hWnd, LPRECT lprc ) | |
{ | |
UINT nCapSize ; | |
BOOL fMenu, fVert ; | |
fMenu= TestWinStyle( hWnd, WS_SYSMENU ) ; | |
fVert = TestWinStyle( hWnd, IBS_VERTCAPTION ) ; | |
if (!GetCaptionRect( hWnd, lprc )) // window coords | |
return FALSE ; | |
if (!fMenu) | |
{ | |
SetRectEmpty( lprc ) ; | |
return FALSE ; | |
} | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
if (fVert) | |
lprc->bottom = lprc->top + nCapSize ; | |
else | |
lprc->right = lprc->left + nCapSize ; | |
lprc->bottom-- ; | |
lprc->right-- ; | |
return TRUE ; | |
} // GetIconRect() | |
// GetMinButtonRect() | |
// | |
// Calculates the rect of the minimize button in screen | |
// coordinates. | |
// | |
// For horizontal captions, we have the following situation ('Y' is minimize | |
// and '^' is maximize or restore): | |
// | |
// +---------------------------------+ | |
// | - | | Y | ^ | | |
// +---------------------------------+ | |
// | |.......| <-- This is the width (nSize) | |
// | |
// For vertical captions, we have the following: | |
// | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// |--|-- | |
// | Y| . | |
// |--| . <-- This is the height of the rectangle (nSize) | |
// | ^| . | |
// +--+-- | |
// | |
// In order to figure out where the minimize button goes, we first need | |
// to know if there is a maximize button. If so, use GetMaxButtonRect() | |
// to place... | |
// | |
BOOL NEAR PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc ) | |
{ | |
if (!TestWinStyle( hWnd, WS_MINIMIZEBOX )) | |
{ | |
SetRectEmpty( lprc ) ; | |
return FALSE ; | |
} | |
// The minimize button can be in either position 1 or 2. If there | |
// is a maximize button, it's in position 2. | |
// | |
if (TestWinStyle( hWnd, WS_MAXIMIZEBOX )) | |
return GetButtonRect( hWnd, 2, lprc ) ; | |
else | |
return GetButtonRect( hWnd, 1, lprc ) ; | |
} | |
// GetMaxButtonRect() | |
// | |
// Calculates the rect of the maximize button in screen | |
// coordinates. | |
// | |
// The maximize button, if present, is always to the far right | |
// or bottom. | |
// | |
BOOL NEAR PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc ) | |
{ | |
//The maximize button can only be in position 1. | |
// | |
if (TestWinStyle( hWnd, WS_MAXIMIZEBOX )) | |
return GetButtonRect( hWnd, 1, lprc ) ; | |
else | |
{ | |
SetRectEmpty( lprc ) ; | |
return FALSE ; | |
} | |
} | |
// Get the rect where a button would go. | |
// | |
// This function does not care if it's a min or max, just whether | |
// it is the first from the right/bottom or second from the right/bottom | |
// and so on.. | |
// | |
BOOL NEAR PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc ) | |
{ | |
UINT nSize = 0 ; | |
if (!GetCaptionRect( hWnd, lprc )) //window coords | |
return FALSE ; | |
nSize = GETCAPTIONSIZE( hWnd ) ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
{ | |
lprc->bottom -= nSize * (nPos-1) ; | |
lprc->top = lprc->bottom - nSize + 1 ; | |
} | |
else | |
{ | |
lprc->right -= nSize * (nPos-1) ; | |
lprc->left = lprc->right - nSize + 1 ; | |
} | |
return TRUE ; | |
} // GetButtonRect() | |
// DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed ) | |
// | |
// Draws either the min, max, or restore buttons. If fMin is FALSE then it | |
// will draw either the Max or Restore button. If fDepressed is TRUE it will | |
// draw the button in a down state. | |
// | |
VOID NEAR PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed) | |
{ | |
RECT rcButton ; | |
RECT rc ; | |
COLORREF rgbWindowFrame ; | |
BOOL fDC ; | |
UINT nCapSize ; | |
UINT nOffset ; | |
int n ; | |
nCapSize = GETCAPTIONSIZE( hWnd ) ; | |
// If you look at the standard Windows' min/max buttons, you will notice | |
// that they have two pixels of 'shadow' to the bottom and right. Since | |
// our buttons can be really, really small, we only want one pixel of | |
// shadow when they are small. I arbitrarily decided that if the | |
// caption size is greater than or equal to 20 we will use two | |
// pixels. That's what this THREASHOLD stuff does. | |
// | |
#define THRESHOLD 20 | |
nOffset = (nCapSize >= THRESHOLD) ? 2 : 1 ; | |
if (!hDC) | |
{ | |
fDC = TRUE ; | |
hDC = GetWindowDC( hWnd ) ; | |
} | |
else | |
fDC = FALSE ; | |
if (hDC) | |
{ | |
rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ; | |
if (fMin) | |
GetMinButtonRect( hWnd, &rcButton ) ; | |
else | |
GetMaxButtonRect( hWnd, &rcButton ) ; | |
GetWindowRect( hWnd, &rc ) ; | |
OffsetRect( &rcButton, -rc.left, -rc.top ) ; | |
rc = rcButton ; | |
if (TestWinStyle( hWnd, IBS_VERTCAPTION )) | |
{ | |
rc = rcButton ; //separator line | |
rc.bottom = --rc.top + 1 ; | |
rcButton.right-- ; | |
} | |
else | |
{ | |
rc = rcButton ; //separator line | |
rc.right = --rc.left + 1 ; | |
rcButton.bottom-- ; | |
} | |
//Draw separator line | |
SetBkColor( hDC, rgbWindowFrame ) ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
//Fill | |
SetBkColor( hDC, RGBLTGRAY ) ; | |
DRAWFASTRECT( hDC, &rcButton ) ; | |
if (!fDepressed) | |
{ | |
//The normal min/max buttons have one pixel on the top and left | |
//sides for the highlight, and two pixels on the bottom and | |
//right side for the shadow. | |
// | |
//When our caption is 'small' we only use one pixel on all | |
//sides. | |
// | |
SetBkColor( hDC, RGBWHITE ) ; | |
//Draw left side | |
rc = rcButton ; | |
rc.right = rc.left + 1 ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
//Draw Top | |
rc = rcButton ; | |
rc.bottom = rc.top + 1 ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
SetBkColor( hDC, RGBGRAY ) ; | |
//Draw right side | |
rc = rcButton ; | |
rc.left = rc.right - 1 ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
if (nCapSize > THRESHOLD) | |
{ | |
rc.left-- ; | |
rc.top++ ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
} | |
//Draw bottom | |
rc = rcButton ; | |
rc.top = rc.bottom - 1 ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
if (nCapSize > THRESHOLD) | |
{ | |
rc.top-- ; | |
rc.left++ ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
} | |
rcButton.left++ ; | |
rcButton.top++ ; | |
rcButton.right -= nOffset ; | |
rcButton.bottom -= nOffset ; | |
} | |
else | |
{ | |
//Draw depressed state | |
SetBkColor( hDC, RGBGRAY ) ; | |
//Draw left side | |
rc = rcButton ; | |
rc.right = rc.left + nOffset ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
//Draw Top | |
rc = rcButton ; | |
rc.bottom = rc.top + nOffset ; | |
DRAWFASTRECT( hDC, &rc ) ; | |
rcButton.left += 2 * nOffset ; | |
rcButton.top += 2 * nOffset ; | |
} | |
// Now draw the arrows. We do not want the | |
// arrows to grow too large when we have a bigger than | |
// normal caption, so we restrict their size. | |
// | |
// rcButton now represents where we can place our | |
// arrows. | |
// | |
// The maximum size of our arrows (i.e. the width of rcButton) | |
// has been empirically determined to be SM_CYCAPTION / 2 | |
// | |
n = ((GetSystemMetrics( SM_CYCAPTION )) / 2) - | |
(rcButton.right - rcButton.left) ; | |
if (n < 1) | |
InflateRect( &rcButton, n/2-1, n/2-1 ) ; | |
if (fMin) | |
DrawArrow( hDC, &rcButton, ARROW_DOWN ) ; | |
else | |
if (IsZoomed( hWnd )) | |
{ | |
DrawArrow( hDC, &rcButton, ARROW_RESTORE ) ; | |
} | |
else | |
DrawArrow( hDC, &rcButton, ARROW_UP ) ; | |
if (fDC) | |
ReleaseDC( hWnd, hDC ) ; | |
} | |
} // DrawButton() | |
// DrawArrow | |
// | |
// Draws either a up or down arrow. The arrow is bound by the rectangle | |
// | |
VOID NEAR PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle ) | |
{ | |
int row ; | |
int xTip ; | |
int yTip ; | |
RECT rc ; | |
int nMax = (lprc->bottom - lprc->top) >> 1 ; | |
SetBkColor( hdc, RGBBLACK ) ; | |
// We draw the arrow by drawing a series of horizontal lines | |
// | |
xTip = lprc->left + ((lprc->right - lprc->left+1) >> 1) ; | |
switch (uiStyle) | |
{ | |
case ARROW_UP: | |
yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 2) ; | |
for (row = 1 ; row <= nMax ; row++ ) | |
{ | |
rc.left = xTip - row ; | |
rc.right = xTip + row - 1 ; | |
rc.top = yTip + row ; | |
rc.bottom = rc.top + 1 ; | |
DRAWFASTRECT( hdc, &rc ) ; | |
} | |
break ; | |
case ARROW_DOWN: | |
yTip = lprc->bottom - ((lprc->bottom - lprc->top-1) >> 2) ; | |
for ( row = nMax ; row > 0 ; row-- ) | |
{ | |
rc.left = xTip - row ; | |
rc.right = xTip + row - 1 ; | |
rc.top = yTip - row ; | |
rc.bottom = rc.top + 1 ; | |
DRAWFASTRECT( hdc, &rc ) ; | |
} | |
break ; | |
case ARROW_RESTORE: | |
default: | |
yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 3) - 2; | |
for (row = 1 ; row <= nMax ; row++ ) | |
{ | |
rc.left = xTip - row ; | |
rc.right = xTip + row - 1 ; | |
rc.top = yTip + row ; | |
rc.bottom = rc.top + 1 ; | |
DRAWFASTRECT( hdc, &rc ) ; | |
} | |
yTip += (nMax+1) * 2 ; | |
for ( row = nMax ; row > 0 ; row-- ) | |
{ | |
rc.left = xTip - row ; | |
rc.right = xTip + row - 1 ; | |
rc.top = yTip - row ; | |
rc.bottom = rc.top + 1 ; | |
DRAWFASTRECT( hdc, &rc ) ; | |
} | |
break ; | |
} | |
} // DrawArrow() | |
// This function is obsolete. Some of my apps still call it | |
// though so that's why it's still here. | |
// | |
BOOL FAR PASCAL ibInit( HANDLE hInstance ) | |
{ | |
return TRUE ; | |
} | |
///////////////////////////////////////////////////////////////////////// | |
// End of File: itsybits.c | |
///////////////////////////////////////////////////////////////////////// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment