/*+
 *
 *  Module:
 *		Toolbar
 *
 *  Description:
 *		General toolbar functions
 *
 *  Original author:
 *		Stephen Chung
 *
 *  Copyright (C) Stephen Chung, 1991.  All rights reserved.
-*/

#include <windows.h>
#include "toolbar.h"

#define MAXSTATES       3

static BOOL ClassRegistered = FALSE;
static BOOL Capturing = FALSE;

long FAR PASCAL ToolbarProc (HWND, WORD, WORD, LONG);
long FAR PASCAL ToolbarButtonProc (HWND, WORD, WORD, LONG);


void Create3DEffect (HDC hdc, RECT *rect, int thickness, int style)
{
	int     i;
	int     x1 = rect->left;
	int     y1 = rect->top;
	int     x2 = rect->right;
	int     y2 = rect->bottom;

	HBRUSH  hbrush, oldbrush;
	HPEN    hpen, oldpen;

	oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN));
	switch (style)
	{
		default:
		case 0:
		case 1: hbrush = GetStockObject(LTGRAY_BRUSH); break;
		case 2: hbrush = GetStockObject(WHITE_BRUSH); break;
	}

	oldbrush = SelectObject(hdc, hbrush);
	Rectangle(hdc, x1, y1, x2, y2);

	switch(style)
	{
	  default:
	  case 0:  SelectObject(hdc, GetStockObject(WHITE_PEN)); break;
	  case 1:  hpen = CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
			   SelectObject(hdc, hpen);
			   break;
	  case 2:  SelectObject(hdc, GetStockObject(BLACK_PEN)); break;
	}

	for (i = 1; i <= thickness; i++)
	{
		MoveTo(hdc, x1 + i, y1 + i);    LineTo(hdc, x1 + i, y2 - 1);
		MoveTo(hdc, x1 + i, y1 + i);    LineTo(hdc, x2 - 1, y1 + i);
	}

	switch (style)
	{
		default:
		case 0:
		case 2:
		  hpen = CreatePen(PS_SOLID, 1, RGB(128,128,128));
		  SelectObject(hdc, hpen);
		  break;
		case 1:
		  SelectObject(hdc, GetStockObject(WHITE_PEN)); break;
	}

	for (i = 1; i <= thickness; i++)
	{
		MoveTo(hdc, x1 + i, y2 - 1 - i);
		LineTo(hdc, x2 - 1, y2 - 1 - i);
		MoveTo(hdc, x2 - 1 - i, y2 - 2);
		LineTo(hdc, x2 - 1 - i, y1 + i);
	}

	SelectObject(hdc, oldbrush);
	SelectObject(hdc, oldpen);

	DeleteObject(hpen);
}

static void CursorShape(HWND hwnd, int state)
{
	HCURSOR hcursor;
	static HCURSOR arrow = NULL;

	if (state < 0)
	   hcursor = (HCURSOR) GetWindowWord(GetParent(hwnd), 3 * sizeof(WORD));
	else
	if (arrow == NULL)
	   hcursor = arrow = LoadCursor(NULL, IDC_ARROW);
	else
	   hcursor = arrow;

	SetCursor(hcursor);
}

void EnableToolbarButton (HWND hwnd, int id, BOOL enabled)
{
	int             i, n;
	TOOLBARICON     *icons;

	icons = (TOOLBARICON *) GetWindowWord(hwnd, 0);
	n = (int) GetWindowWord(hwnd, sizeof(WORD));

	for (i = 0; i < n && icons[i].id != id; i++);

	if (i >= n) return;

	if (enabled) {
		if (icons[i].state >= 0) return;
		icons[i].state = icons[i].oldstate;
	} else {
		if (icons[i].state < 0) return;
		icons[i].oldstate = icons[i].state;
		icons[i].state = -1;
	}
	InvalidateRect(icons[i].hwnd, NULL, FALSE);
    	UpdateWindow(icons[i].hwnd);
}

HWND GetToolbarButton (HWND hwnd, int id, TOOLBARICON *ip)
{
	int             i, n;
	TOOLBARICON     *icons;

	icons = (TOOLBARICON *) GetWindowWord(hwnd, 0);
	n = (int) GetWindowWord(hwnd, sizeof(WORD));

	for (i = 0; i < n && icons[i].id != id; i++);

    	if (i >= n) return (NULL);

    	if (ip != NULL) *ip = icons[i];

    	return (icons[i].hwnd);
}



void ModifyToolbarButton (HWND hwnd, TOOLBARICON *icon)
{
    TOOLBARICON *old;

    old = (TOOLBARICON *) GetWindowWord(hwnd, 0);

    old->id = icon->id;
    old->x = icon->x;
    old->y = icon->y;
	old->width = icon->width;
    old->height = icon->height;
    old->state = icon->state;
	old->cycle = icon->cycle;
	old->disabled = icon->disabled;
	old->undepressed = icon->undepressed;
	old->depressed = icon->depressed;
    old->grayed = icon->grayed;
    old->pressing = icon->pressing;

	InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
}



HWND CreateToolbar (HWND parent, int x, int y, int width, int height,
                    int thickness, int id, int n, HANDLE hInstance,
                    TOOLBARICON *icons, char *xcursor)
{
	int         i;
	HWND        hwnd;
    WNDCLASS    wndclass;

	if (!ClassRegistered) {
		wndclass.style          = CS_HREDRAW | CS_VREDRAW;
		wndclass.lpfnWndProc    = ToolbarProc;
		wndclass.cbClsExtra     = 0;
        wndclass.cbWndExtra     = 4 * sizeof(WORD);
		wndclass.hInstance      = hInstance;
		wndclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
		wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground  = COLOR_BTNFACE + 1;
        wndclass.lpszMenuName   = NULL;
        wndclass.lpszClassName  = TOOLBARCLASS;

		RegisterClass(&wndclass);

		wndclass.cbWndExtra     = sizeof(WORD);
		wndclass.lpfnWndProc    = ToolbarButtonProc;
		wndclass.lpszClassName  = TOOLBARBUTTONCLASS;

		RegisterClass(&wndclass);
	}

	hwnd = CreateWindow(TOOLBARCLASS, "", WS_CHILD /* | WS_VISIBLE */ ,
						x, y, width, height, parent, id, hInstance, NULL);

	SetWindowWord(hwnd, 0, (WORD) icons);
	SetWindowWord(hwnd, sizeof(WORD), (WORD) n);
	SetWindowWord(hwnd, 2 * sizeof(WORD), (WORD) thickness);
	if (xcursor != NULL)
	{
		SetWindowWord(hwnd, 3 * sizeof(WORD), LoadCursor(hInstance, xcursor));
	}
	else
	{
		SetWindowWord(hwnd, 3 * sizeof(WORD), NULL);
	}

	//ShowWindow(hwnd, SW_SHOW);
	//UpdateWindow(hwnd);

	/* Create the children */

	for (i = 0; i < n; i++)
	{
		icons[i].hwnd = CreateWindow(TOOLBARBUTTONCLASS, "",
									 WS_CHILD | WS_VISIBLE,
									 icons[i].x, icons[i].y,
									 icons[i].width, icons[i].height,
									 hwnd, icons[i].id, hInstance, NULL);

		SetWindowWord(icons[i].hwnd, 0, (WORD) &(icons[i]));
		ShowWindow(icons[i].hwnd, SW_SHOW);
		UpdateWindow(hwnd);
	}

    return (hwnd);
}

long FAR PASCAL _export ToolbarProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
	int             i;
	HDC             hdc;
	PAINTSTRUCT     ps;
	HWND            child;
	RECT			rect;
	TOOLBARICON     *icons;


	switch (message) {

		case WM_PAINT:
            GetClientRect(hwnd, &rect);

			hdc = BeginPaint(hwnd, &ps);
			Create3DEffect(hdc, &rect, GetWindowWord(hwnd, 2 * sizeof(WORD)), 0);
			EndPaint(hwnd, &ps);
			return (0);

		case WM_COMMAND:
			SendMessage(GetParent(hwnd), WM_COMMAND,
						(wParam << 8) | GetWindowWord(hwnd, GWW_ID), lParam);
			return (0);

		case BM_SETSTATE:
		case BM_GETSTATE:
			icons = (TOOLBARICON *) GetWindowWord(hwnd, 0);
			for (i = 0; icons[i].id != LOWORD(lParam); i++);
			return (SendMessage(icons[i].hwnd, message, wParam, 0L));
	}

	return (DefWindowProc(hwnd, message, wParam, lParam));
}



long FAR PASCAL _export ToolbarButtonProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
	int             i, j;
    BOOL            crossed;
	HDC             hdc, hdcmem;
	PAINTSTRUCT     ps;
	HPEN            hpen;
	HWND            child;
	TOOLBARICON     *icon;
	HBITMAP         hbitmap;
	HANDLE			hInstance;
    HCURSOR         hcursor;


	icon = (TOOLBARICON *) GetWindowWord(hwnd, 0);

	switch (message)
	{

	  case BM_SETSTATE:
		if (icon->state == wParam) return (0);

		icon->oldstate = icon->state = wParam;
		InvalidateRect(hwnd, NULL, FALSE);
		UpdateWindow(hwnd);
		return (0);

	case BM_GETSTATE:
		return (icon->state);

	case WM_LBUTTONDOWN:
		if (icon->state < 0) return (0);

		icon->oldstate = icon->state;
		icon->state = MAXSTATES;
		InvalidateRect(hwnd, NULL, FALSE);
		UpdateWindow(hwnd);
		SetCapture(hwnd);
		Capturing = TRUE;
		return (0);

	case WM_LBUTTONUP:
		if (!Capturing || icon->state < 0) return (0);

		ReleaseCapture();
		Capturing = FALSE;

		i = LOWORD(lParam);
		j = HIWORD(lParam);

		if (i < 0 || i >= icon->width || j < 0 || j >= icon->height) {
			return (0);
		} else if (icon->cycle <= 0) {
			icon->state = icon->oldstate;
		} else {
			icon->oldstate++;
			if (icon->oldstate >= icon->cycle) icon->oldstate = 0;
			icon->state = icon->oldstate;
		}

		InvalidateRect(hwnd, NULL, FALSE);
		UpdateWindow(hwnd);
		CursorShape(hwnd, icon->state);
		SendMessage(GetParent(hwnd), WM_COMMAND, icon->id, MAKELONG(hwnd, BN_CLICKED));
		return (0);

	case WM_MOUSEMOVE:
		CursorShape(hwnd, icon->state);
		if (!Capturing || icon->state < 0) return (0);

		i = LOWORD(lParam);
		j = HIWORD(lParam);

		if (i < 0 || i >= icon->width || j < 0 || j >= icon->height)
		{
			crossed = (icon->state == MAXSTATES);
			icon->state = icon->oldstate;
		} else
		{
			crossed = (icon->state != MAXSTATES);
			icon->state = MAXSTATES;
		}

		if (crossed)
		{
			InvalidateRect(hwnd, NULL, FALSE);
			UpdateWindow(hwnd);
		}
		return (0);

	case WM_PAINT:
		hInstance = GetWindowWord(hwnd, GWW_HINSTANCE);

		hdc = BeginPaint(hwnd, &ps);

		switch (icon->state) {
			default: if (icon->disabled != NULL)
			{
					hbitmap = LoadBitmap(hInstance, icon->disabled);
			}
			break;

			case 0:  hbitmap = LoadBitmap(hInstance, icon->undepressed); break;
			case 1:  hbitmap = LoadBitmap(hInstance, icon->depressed); break;
			case 2:  hbitmap = LoadBitmap(hInstance, icon->grayed); break;

			case MAXSTATES:
					hbitmap = LoadBitmap(hInstance, icon->pressing); break;
		}

		hdcmem = CreateCompatibleDC(hdc);
		SelectObject(hdcmem, hbitmap);

		BitBlt(hdc, 0, 0, icon->width, icon->height, hdcmem, 0, 0, SRCCOPY);

		if (!DeleteDC(hdcmem))
		   MessageBox(NULL, "TOOLBAR: Could not delete DC", "DeleteDC error",
						MB_ICONEXCLAMATION | MB_OK);
		if (!DeleteObject(hbitmap))
		   MessageBox(NULL, "TOOLBAR: Could not delete bitmapC", "DeleteObject error",
						MB_ICONEXCLAMATION | MB_OK);
		EndPaint(hwnd, &ps);
		return (0);
	}

	return (DefWindowProc(hwnd, message, wParam, lParam));
}
