Mouse-over (rollover) effect in a Windows GUI program

vegaseat 0 Tallied Votes 191 Views Share

What is so easy to do in HTML gets quite involved in C. Once you learn to look past the standard GUI overhead it becomes more obvious. This example shows the effect of the mouse cursor moving across a label by changing foreground and background colors.

// show mouse-over (rollover) action on a label
// BCX created code modified for Pelles C and Dev C++
// (invalid conversions of lpfnOldProc solved by proper casting)

#include <windows.h>  // in turn includes winuser.h

#define ID_Form1 0
#define ID_Label1 1

static HINSTANCE BCX_hInstance;
static int     BCX_ScaleX;
static int     BCX_ScaleY;
static char    BCX_ClassName[2048];
static HWND    Form1;
static HWND    Label1;
static int     Focus;

#define Show(Window)  RedrawWindow(Window,0,0,0);ShowWindow(Window,SW_SHOW);

HWND    BCX_Form(char*,int=0,int=0,int=250,int=150,int=0,int=0);
HWND    BCX_Label(char*,HWND,int=0,int=0,int=0,int=0,int=0,int=0,int=0);
LRESULT Set_Color (int,int,int,int);

void    FormLoad (void);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK LabelProc (HWND, UINT, WPARAM, LPARAM);


// standard main for windows GUI programs
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR CmdLine,int CmdShow)
{
 WNDCLASS Wc;
 MSG      Msg;
 // *****************************
 strcpy(BCX_ClassName,"MouseOverLabel1");
 // ***************************************
 // Programmer has selected to use pixels
 // adjust scaling accordingly
 // ***************************************
 BCX_ScaleX       = 1;
 BCX_ScaleY       = 1;
 BCX_hInstance    =  hInst;
 // ******************************************************
 Wc.style         =  CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
 Wc.lpfnWndProc   =  WndProc;
 Wc.cbClsExtra    =  0;
 Wc.cbWndExtra    =  0;
 Wc.hInstance     =  hInst;
 Wc.hIcon         =  LoadIcon(NULL,IDI_WINLOGO);
 Wc.hCursor       =  LoadCursor(NULL,IDC_ARROW);
 Wc.hbrBackground =  (HBRUSH)(COLOR_BTNFACE+1);
 Wc.lpszMenuName  =  NULL;
 Wc.lpszClassName =  BCX_ClassName;
 RegisterClass(&Wc);

 FormLoad();
 while(GetMessage(&Msg,NULL,0,0))
 {
   HWND hActiveWindow = GetActiveWindow();
   if (!IsWindow(hActiveWindow) || !IsDialogMessage(hActiveWindow,&Msg))
   {
     TranslateMessage(&Msg);
     DispatchMessage(&Msg);
   }
 }
 return Msg.wParam;
}


// create the windows form
HWND BCX_Form(char *Caption, int X, int Y, int W, int H, int Style, int Exstyle)
{
  HWND  A;
  // assign default style
  if (!Style)
  {
    Style= WS_MINIMIZEBOX  |
    WS_SIZEBOX      |
    WS_CAPTION      |
    WS_MAXIMIZEBOX  |
    WS_POPUP        |
    WS_SYSMENU;
  }
  A = CreateWindowEx(Exstyle,BCX_ClassName,Caption,
    Style,
    X*BCX_ScaleX,
    Y*BCX_ScaleY,
    (4+W)*BCX_ScaleX,
    (12+H)*BCX_ScaleY,
    NULL,(HMENU)NULL,BCX_hInstance,NULL);
  SendMessage(A,(UINT)WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),
    (LPARAM)MAKELPARAM(FALSE,0));
  return A;
}


// create a label
HWND BCX_Label
(char* Text,HWND hWnd,int id,int X,int Y,int W,int H,int Style,int Exstyle)
{
  HWND  A;
  // assign default style
  if (!Style)
  {
    Style=WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE;
  }
  A = CreateWindowEx(Exstyle,"static",Text,Style,X*BCX_ScaleX, Y*BCX_ScaleY, 
    W*BCX_ScaleX, H*BCX_ScaleY,hWnd,(HMENU)id,BCX_hInstance,NULL);
  SendMessage(A,(UINT)WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),
    (LPARAM)MAKELPARAM(FALSE,0));
  if (W==0)
  {
    HDC  hdc=GetDC(A);
    SIZE  size;
    GetTextExtentPoint32(hdc,Text,strlen(Text),&size);
    ReleaseDC(A,hdc);
    MoveWindow(A,X*BCX_ScaleX,Y*BCX_ScaleY,size.cx,size.cy,TRUE);
  }
  return A;
}


LRESULT Set_Color (int TxtColr,int BkColr,int wParam,int lParam)
{
  static HBRUSH  ReUsableBrush;
  SetTextColor((HDC)wParam,TxtColr);
  if (BkColr==-1)
  {
    BkColr=GetClassLong(GetParent((HWND)lParam),GCL_HBRBACKGROUND);
    if (BkColr>31)
    { 
	    SetBkMode((HDC)wParam,TRANSPARENT); 
	    return BkColr; 
	  }
    else
      BkColr=GetSysColor(BkColr-1);
  }
  DeleteObject(ReUsableBrush);
  ReUsableBrush=CreateSolidBrush(BkColr);
  SetBkColor((HDC)wParam,BkColr);
  return (LRESULT)ReUsableBrush;
}


// details like corner coordinates, width, height ...
void FormLoad (void)
  {
    Form1=BCX_Form("Mouse-over Label ...",80,88,320,102);
    Label1=BCX_Label("Move the mouse over me!",Form1,ID_Label1,32,24,250,28);
    //  setup callback functions 
    SetProp(Label1,"oldproc",(HANDLE)GetWindowLong(Label1,GWL_WNDPROC));
    SetWindowLong(Label1,GWL_WNDPROC,(DWORD)LabelProc);
    Show(Form1);
  }


// standard windows message handler
LRESULT CALLBACK WndProc (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  while(1)
  {
  if (Msg==WM_MOUSEMOVE)
  {
    if (Focus)
    {
      Focus=FALSE;
      InvalidateRect(Label1,0,TRUE);
    }
    break;
  }
  if (Msg==WM_CTLCOLORSTATIC)
  {
    static int      cFG;
    memset(&cFG,0,sizeof(cFG));
    static int      cBG;
    memset(&cBG,0,sizeof(cBG));
    if ((HANDLE)lParam==Label1)
    {
      if (Focus)
      {
        cFG=RGB(0,0,0);       // black text
        cBG=RGB(255,255,0);   // label bg = yellow
      }
      else
      {
        cFG=RGB(255,255,255); // white text
        cBG=RGB(0,0,255);     // label bg = blue
      }
      if ((HWND)lParam==Label1 && Msg==WM_CTLCOLORSTATIC)
        return Set_Color(cFG,cBG,wParam,lParam);
    }
    break;
  }
  if (Msg==WM_CLOSE)
  {
    DestroyWindow(Form1);
    return 0;
  }
  break;
  }
  // clean up and exit program
  if (Msg==WM_DESTROY)
  {
    UnregisterClass(BCX_ClassName,BCX_hInstance);
    PostQuitMessage(0);
  }
  return DefWindowProc(hWnd,Msg,wParam,lParam);
}


// the label events
LRESULT CALLBACK LabelProc (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  static  FARPROC  lpfnOldProc;
  memset(&lpfnOldProc,0,sizeof(lpfnOldProc));
  static  LRESULT  lResult;
  memset(&lResult,0,sizeof(lResult));
  lpfnOldProc=(FARPROC)GetProp(hWnd,"oldproc");  // cast to FARPROC
  while(1)
  {
    if (Msg==WM_MOUSEMOVE)
    {
      if (!Focus)
      {
        Focus=TRUE;
        InvalidateRect(Label1,0,TRUE);
      }
      break;
    }
    // clean up
    if (Msg==WM_DESTROY)
    {
      SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)GetProp(hWnd,"oldproc"));
      RemoveProp(hWnd,"oldproc");
      // cast to WNDPROC
      return CallWindowProc((WNDPROC)lpfnOldProc,hWnd,Msg,wParam,lParam);
    }
    break;
  }
  // cast to WNDPROC
  return CallWindowProc((WNDPROC)lpfnOldProc,hWnd,Msg,wParam,lParam);
}