|
|
//============================================================================
// Copyright (c) 1996, Microsoft Corporation
//
// File: bubble.c
//
// History:
// Abolade Gbadegesin Mar-1-1996 Created.
//
// This file contains code for the bubble-popup control.
//============================================================================
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <debug.h>
#include <nouiutil.h>
#include <uiutil.h>
#include "bpopup.h" // public declarations
#include "bubble.h" // private declarations
//----------------------------------------------------------------------------
// Function: BubblePopup_Init
//
// This function is called to initialize the control class.
// It registers the bubble-popup window class.
//----------------------------------------------------------------------------
BOOL BubblePopup_Init( IN HINSTANCE hinstance ) {
//
// if the window class is registered already, return
//
WNDCLASS wc;
if (GetClassInfo(hinstance, WC_BUBBLEPOPUP, &wc)) { return TRUE; }
//
// set up the window class for registration
//
wc.lpfnWndProc = BP_WndProc; wc.hCursor = LoadCursor(hinstance, IDC_ARROW); wc.hIcon = NULL; wc.lpszMenuName = NULL; wc.hInstance = hinstance; wc.lpszClassName = WC_BUBBLEPOPUP; wc.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbWndExtra = sizeof(BPOPUP *); wc.cbClsExtra = 0;
return RegisterClass(&wc); }
//----------------------------------------------------------------------------
// Function: BP_WndProc
//
// This is the window procedure for all windows in the BubblePopup class.
//----------------------------------------------------------------------------
LRESULT CALLBACK BP_WndProc( IN HWND hwnd, IN UINT uiMsg, IN WPARAM wParam, IN LPARAM lParam ) {
BPOPUP *pbp;
//
// attempt to retrieve the private data pointer for the window
// on WM_NCCREATE, this fails, so we allocate the data.
//
if ( NULL == hwnd) { return (LRESULT)FALSE; }
pbp = BP_GetPtr(hwnd);
if (pbp == NULL) {
if (uiMsg != WM_NCCREATE) { return DefWindowProc(hwnd, uiMsg, wParam, lParam); }
//
// allocate a block of memory
//
pbp = (BPOPUP *)Malloc(sizeof(BPOPUP)); if (pbp == NULL) { return (LRESULT)FALSE; }
//
// save the pointer in the window's private bytes
//
pbp->hwnd = hwnd;
//
//Reset Error code, because BP_SetPtr won't reset the error code when
//it succeeds
//
SetLastError( 0 ); if ((0 == BP_SetPtr(hwnd, pbp)) && (0 != GetLastError())) { Free(pbp); return (LRESULT)FALSE; }
return DefWindowProc(hwnd, uiMsg, wParam, lParam); }
//
// if the window is being destroyed, free the block allocated
// and set the private bytes pointer to NULL
//
if (uiMsg == WM_NCDESTROY) {
Free(pbp);
BP_SetPtr(hwnd, 0);
return (LRESULT)0; }
//
// handle other messages
//
switch(uiMsg) {
HANDLE_MSG(pbp, WM_CREATE, BP_OnCreate); HANDLE_MSG(pbp, WM_DESTROY, BP_OnDestroy);
case WM_PAINT: {
return BP_OnPaint(pbp); }
case WM_WINDOWPOSCHANGED: {
BP_ResizeClient(pbp);
return 0; }
case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: {
//
// hide the window if it is showing
//
BP_OnDeactivate(pbp);
return 0; }
case WM_GETFONT: {
return (LRESULT)pbp->hfont; }
case WM_SETFONT: {
BOOL bRet = BP_OnSetFont(pbp, (HFONT)wParam, (BOOL)LOWORD(lParam));
BP_ResizeClient(pbp);
if (pbp->dwFlags & BPFLAG_Activated) {
InvalidateRect(pbp->hwnd, NULL, TRUE); UpdateWindow(pbp->hwnd); }
return bRet; }
case WM_SETTEXT: {
//
// change the text we're currently using,
// and invalidate our client area
//
Free0(pbp->pszText);
pbp->pszText = StrDup((PTSTR)lParam);
BP_ResizeClient(pbp);
if (pbp->dwFlags & BPFLAG_Activated) {
InvalidateRect(pbp->hwnd, NULL, TRUE); UpdateWindow(pbp->hwnd); }
return (pbp->pszText) ? TRUE : FALSE; }
case WM_GETTEXT: {
//
// return the text we're currently using
//
PTSTR dst = (LPTSTR)lParam; PTSTR src = pbp->pszText; return lstrlen(lstrcpyn(dst, src ? src : TEXT(""), (int)wParam)); }
case WM_TIMER: {
BP_OnDeactivate(pbp);
return 0; }
case BPM_SETTIMEOUT: {
pbp->uiTimeout = (UINT)lParam;
if (pbp->dwFlags & BPFLAG_Activated) {
KillTimer(pbp->hwnd, pbp->ulpTimer);
pbp->ulpTimer = SetTimer( pbp->hwnd, BP_TimerId, pbp->uiTimeout, NULL ); }
return 0; }
case BPM_ACTIVATE: {
return BP_OnActivate(pbp); }
case BPM_DEACTIVATE: {
return BP_OnDeactivate(pbp); } }
return DefWindowProc(hwnd, uiMsg, wParam, lParam); }
//----------------------------------------------------------------------------
// Function: BP_OnCreate
//
// This function handles the creation of private data for a bubble-popup.
//----------------------------------------------------------------------------
BOOL BP_OnCreate( IN BPOPUP * pbp, IN CREATESTRUCT * pcs ) {
//
// initialize the structure members
//
pbp->iCtrlId = PtrToUlong(pcs->hMenu); pbp->pszText = (pcs->lpszName ? StrDup((PTSTR)pcs->lpszName) : NULL); pbp->dwFlags = 0; pbp->ulpTimer = 0; pbp->uiTimeout = 5000;
//
// we force the window to have the WS_POPUP style
//
SetWindowLong(pbp->hwnd, GWL_STYLE, WS_POPUP);
//
// set the WS_EX_TOOLWINDOW style to make sure
// that this window doesn't show up in the tasklist
//
SetWindowLong(pbp->hwnd, GWL_EXSTYLE, pcs->dwExStyle | WS_EX_TOOLWINDOW);
return BP_OnSetFont(pbp, NULL, FALSE); }
//----------------------------------------------------------------------------
// Function: BP_OnDestroy
//
// This function handles the deallocation of private data for a bubble-popup.
//----------------------------------------------------------------------------
VOID BP_OnDestroy( IN BPOPUP * pbp ) {
//
// if the font was created by this window, delete it
//
if (pbp->dwFlags & BPFLAG_FontCreated) { DeleteObject(pbp->hfont); }
pbp->dwFlags = 0; pbp->hfont = NULL; }
//----------------------------------------------------------------------------
// Function: BP_OnSetFont
//
// This function handles the changing of the font in use by a bubble-popup.
//----------------------------------------------------------------------------
BOOL BP_OnSetFont( IN BPOPUP * pbp, IN HFONT hfont, IN BOOL bRedraw ) {
if (pbp->dwFlags & BPFLAG_FontCreated) { DeleteObject(pbp->hfont); }
pbp->dwFlags &= ~BPFLAG_FontCreated; pbp->hfont = NULL;
if (!hfont) {
//
// (re)create the default font.
//
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
if (!SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0 )) {
TRACE1("error %d getting font info", GetLastError()); return FALSE; }
hfont = CreateFontIndirect(&ncm.lfStatusFont);
if (!hfont) {
TRACE("error creating bubble-popup font"); return FALSE; }
pbp->dwFlags |= BPFLAG_FontCreated; }
pbp->hfont = hfont;
if (bRedraw) { InvalidateRect(pbp->hwnd, NULL, TRUE); }
return TRUE; }
//----------------------------------------------------------------------------
// Function: BP_OnGetRect
//
// This function recomputes the rectangle required to display
// a bubble-popup's current text.
//----------------------------------------------------------------------------
VOID BP_OnGetRect( IN BPOPUP * pbp, IN RECT * prc ) {
if (!pbp->pszText) { SetRectEmpty(prc); } else { HFONT hfontOld; HDC hdc = GetDC(pbp->hwnd);
if (hdc) { //
// select the font into the DC and compute the new rectangle
//
hfontOld = SelectObject(hdc, pbp->hfont); DrawText(hdc, pbp->pszText, -1, prc, DT_CALCRECT | DT_EXPANDTABS); if (hfontOld) { SelectObject(hdc, hfontOld); } ReleaseDC(pbp->hwnd, hdc); //
// make space in the rectangle for the border
//
InflateRect( prc, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE) ); } }
//
// convert the rectangle to screen coordinates
//
MapWindowPoints(pbp->hwnd, NULL, (POINT *)prc, 2); }
//----------------------------------------------------------------------------
// Function: BP_ResizeClient
//
// When a change occurs (e.g. font-change, new text) this function is called
// to resize the bubble-popup's window so the text still fits.
//----------------------------------------------------------------------------
VOID BP_ResizeClient( IN BPOPUP * pbp ) {
RECT rc;
//
// find out what size the window needs to be to hold
// the text it is currently set to display
//
BP_OnGetRect(pbp, &rc);
//
// resize the window so its client area is large enough
// to hold DrawText's output
//
SetWindowPos( pbp->hwnd, HWND_TOPMOST, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE ); }
//----------------------------------------------------------------------------
// Function: BP_OnPaint
//
// This function handles the painting of a bubble-popup window.
//----------------------------------------------------------------------------
DWORD BP_OnPaint( IN BPOPUP * pbp ) {
HDC hdc; HBRUSH hbr; HFONT hfontOld; PAINTSTRUCT ps; RECT rc, rcText;
if (!pbp->hfont || !pbp->pszText) { return (DWORD)-1; }
hdc = BeginPaint(pbp->hwnd, &ps);
GetClientRect(pbp->hwnd, &rc); rcText = rc; InflateRect( &rcText, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE) );
hfontOld = SelectObject(hdc, pbp->hfont);
SetTextColor(hdc, GetSysColor(COLOR_INFOTEXT));
//
// clear the window's background
//
hbr = CreateSolidBrush(GetSysColor(COLOR_INFOBK)); if (hbr) { FillRect(hdc, &rc, hbr); DeleteObject(hbr); }
//
// draw our formatted text in the window
//
SetBkMode(hdc, TRANSPARENT); DrawText(hdc, pbp->pszText, -1, &rcText, DT_EXPANDTABS);
//
// draw a border around the window
//
DrawEdge(hdc, &rc, BDR_RAISEDOUTER, BF_RECT);
if (hfontOld) { SelectObject(hdc, hfontOld); }
EndPaint(pbp->hwnd, &ps);
return 0; }
BOOL BP_OnActivate( IN BPOPUP * pbp ) {
if (pbp->dwFlags & BPFLAG_Activated) {
KillTimer(pbp->hwnd, pbp->ulpTimer); }
ShowWindow(pbp->hwnd, SW_SHOW);
UpdateWindow(pbp->hwnd);
pbp->ulpTimer = SetTimer(pbp->hwnd, BP_TimerId, pbp->uiTimeout, NULL);
pbp->dwFlags |= BPFLAG_Activated;
return TRUE; }
BOOL BP_OnDeactivate( IN BPOPUP * pbp ) {
if (pbp->ulpTimer) { KillTimer(pbp->hwnd, pbp->ulpTimer); pbp->ulpTimer = 0; }
ShowWindow(pbp->hwnd, SW_HIDE);
pbp->dwFlags &= ~BPFLAG_Activated;
return TRUE; }
|