/*
 *  Routines for the TOOLBAR library
 *  Copyright (C) Stephen Chung, 1991.
 *  All rights reserved.
 *
 *  Portions (C) Tim Liddelow 1992
 */

#include <windows.h>
#include "toolbar.h"

#define MAXSTATES       3

BOOL ToolBar::ClassRegistered = FALSE;
BOOL ToolBar::Capturing = FALSE;

void ToolBar::Resize (int x, int y, int width, int height, BOOL bRepaint)
{
	MoveWindow (hwnd, x, y, width, height, bRepaint);
}

void ToolBar::EnableToolbarButton (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 ToolBar::GetToolbarButton (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 ToolBar::ModifyToolbarButton (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);
}

void ToolBar::ToolBar (HWND parent, int x, int y, int width, int height,
					int thickness, int id, int n, HANDLE hInstance,
					TOOLBARICON *icons, char *xcursor)
{
	int         i;
	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);
	}
}

long FAR PASCAL ToolBar::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 ToolBar::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);

	if (icon->state < 0)
	{
	   hcursor = (HCURSOR) GetWindowWord(GetParent(hwnd), 3 * sizeof(WORD));
	   if (hcursor != NULL)
		  SetCursor(hcursor);
	}

	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);
		ToolBar::Capturing = TRUE;
		return (0);

	  case WM_LBUTTONUP:
		if (!ToolBar::Capturing || icon->state < 0) return (0);

		ReleaseCapture();
		ToolBar::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);
		SendMessage(GetParent(hwnd), WM_COMMAND, icon->id, MAKELONG(hwnd, BN_CLICKED));
		return (0);

	  case WM_MOUSEMOVE:
		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);

		DeleteDC(hdcmem);
		DeleteObject(hbitmap);
		EndPaint(hwnd, &ps);
		return (0);

	}
	return (DefWindowProc(hwnd, message, wParam, lParam));
}

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 2:
	  case 0:	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	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);
}
