/******************************************************************************
 *   A Skinned Button Win32 Implementation
 *  Copyright (C) 2007 Paolo Medici (www.pmx.it)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *******************************************************************************/

/** @file skin_button.cpp
  * A Skinned Button Win32 Implementation
  *  
  * Bitmap should composed by two pieces [top: release, bottom: pressed]
  *
  * @author Paolo Medici (C)2007
  *
	* @license LGPL
  **/

#include <windowsx.h>
#include "skin_button.h"

/// Two state
#define BMS_RELEASED	0
#define BMS_PRESSED		1

/// The classname
const char szSkinButtonClassName[]="pmclass32_skinbutton";

/// callback WM_PAINT
static void Widget_OnPaint(HWND hwnd)
{
	  HBITMAP hbmp = (HBITMAP) GetWindowLong(hwnd,0);
	  LONG State = (LONG) GetWindowLong(hwnd,4);
  	BITMAP bm;
    PAINTSTRUCT ps;

    HDC hdc = BeginPaint(hwnd, &ps);

    HDC hdcMem = CreateCompatibleDC(hdc);
    HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, hbmp);
    int h;

    GetObject(hbmp, sizeof(bm), &bm);
	  h = bm.bmHeight/2;
    BitBlt(hdc, 0, 0, bm.bmWidth, h, hdcMem, 0, State * h, SRCCOPY);

    SelectObject(hdcMem, hbmOld);
    DeleteDC(hdcMem);

    EndPaint(hwnd, &ps);
			
}

/// callback WM_DESTROY
static void Widget_OnDestroy(HWND hwnd) { }

/// callback WM_CREATE
static BOOL Widget_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
	SetWindowLong(hwnd, GWL_ID, (LONG) lpCreateStruct->hMenu);
	SetWindowLong(hwnd,0, (LONG) lpCreateStruct->lpCreateParams);
	SetWindowLong(hwnd,4, BMS_RELEASED);
	return TRUE;
}

/// callback WM_LBUTTONDWON 
static void Widget_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x,
                               int y, UINT keyFlags)
   {
			SetCapture(hwnd);
			SetWindowLong(hwnd,4,BMS_PRESSED);
			InvalidateRect(hwnd, NULL, TRUE);
   }

/// callback WM_LBUTTONUP
static void Widget_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
   {
		  HBITMAP hbmp = (HBITMAP) GetWindowLong(hwnd,0);
		  BITMAP bm;

			ReleaseCapture();

		  GetObject(hbmp, sizeof(bm), &bm);

			SetWindowLong(hwnd,4,BMS_RELEASED);
			int h = bm.bmHeight/2;
		  
		  if((x>=0)&&(x<bm.bmWidth)&&(y>=0)&&(y<h))
				SendMessage(GetParent(hwnd), WM_COMMAND, (WPARAM) GetWindowLong(hwnd, GWL_ID), (LPARAM) hwnd);

			InvalidateRect(hwnd, NULL, TRUE);

   }

/// Callback proc
LRESULT CALLBACK SkinButtonProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{

   switch (Message)                  /* handle the messages */
    {
        HANDLE_MSG(hwnd, WM_CREATE,         Widget_OnCreate       );
      	HANDLE_MSG(hwnd, WM_DESTROY,        Widget_OnDestroy      );
      	HANDLE_MSG(hwnd, WM_PAINT,          Widget_OnPaint        );
				HANDLE_MSG(hwnd, WM_LBUTTONDOWN, 		Widget_OnLButtonDown);
        HANDLE_MSG(hwnd, WM_LBUTTONUP, 			Widget_OnLButtonUp);						
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, Message, wParam, lParam);
    }

    return 0;

}

/// Register This class
int Register_Skin_Button(HINSTANCE hThisInstance )
{
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szSkinButtonClassName;
    wincl.lpfnWndProc = SkinButtonProc;      /* This function is called by windows */
    wincl.style = 0;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = NULL;
    wincl.hIconSm = NULL;
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 2*sizeof(DWORD);                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = NULL;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;	
    return 1;
}

/// helper function to add to window the Skin Button class
HWND AddSkinButton(HWND hwnd, int x, int y, UINT idc, HINSTANCE hInst, HBITMAP hbmp)
{
	BITMAP bm;
  GetObject(hbmp, sizeof(bm), &bm);
		
	return CreateWindow(
           szSkinButtonClassName,         /* Classname */
           "",       /* Title Text */
           WS_CHILD | WS_VISIBLE, /* default window */
           x,       /* Windows decides the position */
           y,       /* where the window ends up on the screen */
           bm.bmWidth,
           bm.bmHeight/2,
           hwnd,        
           (HMENU) idc,             
           hInst,       /* Program Instance handler */
           hbmp                
           );
}