/**********************************************************************

	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomohito Nakajima <nakajima@zeta.co.jp>
	Tomoki Sekiyama <sekiyama@yahoo.co.jp>

	This program is free software; you can redistribute it
	and/or modify it under the terms of the GLOBALBASE
	Library General Public License (G-LGPL) as published by

	http://www.globalbase.org/

	This program 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.

**********************************************************************/


#include "v/v_types.h"


VTrackedInfo *VTrackedInfo::tracked = NULL;	// tracked object - corresponding to hWndTracked
VTrackedInfo *VTrackedInfo::last = NULL;	// last "enter"ed object
HWND VTrackedInfo::hWndTracked = NULL;		// tracked (last mouse down) object
HWND VTrackedInfo::hWndLastPoint = NULL;	// lastly pointed (mouse move) object

VTrackedInfo::~VTrackedInfo()
{
	if ( last == this ) {
		last = NULL;
	}
	if ( tracked == this ) {
		SetCapture(NULL);
		hWndTracked = NULL;
		tracked = NULL;
	}
}


/*	Send leave / enter messages if needed.
	In tracking mode, returns tracked object.
	Otherwise, returns current pointed object. */
VTrackedInfo *
VTrackedInfo::check_wnd(MSG *msg)
{
	VTrackedInfo *cur = dynamic_cast<VTrackedInfo*>(get_from_hwnd(msg->hwnd));

	if ( hWndTracked ) {	// tracking mode
		if ( tracked ) {		// do nothing if target is not VTrackedInfo
			RECT r;
			GetClientRect(msg->hwnd, &r);
			
			HDC hdc = GetDC(msg->hwnd);
			int cb = GetClipBox(hdc, &r);
			ReleaseDC(msg->hwnd, hdc);
			if ( cb != SIMPLEREGION )
				printf("clip rgn *** %x ***\n", cb);

			POINT cp = msg->pt;
			ScreenToClient(msg->hwnd, &cp);
			if ( cp.x >= r.left && cp.x < r.right &&
				 cp.y >= r.top  && cp.y < r.bottom ) {	// within tracked hwnd
				if ( hWndLastPoint != hWndTracked ) {
					hWndLastPoint = hWndTracked;
					if ( tracked )
						tracked->mouse_enter(msg);
					last = tracked;
				}
			}
			else {										// out of traced hwnd
				if ( hWndLastPoint == hWndTracked ) {
					hWndLastPoint = NULL;
					if ( tracked )
						tracked->mouse_leave(msg);
					last = NULL;
				}
			}
		}
	}
	else {					// normal mode
		if ( hWndLastPoint != msg->hwnd ) {
			if ( last )
				last->mouse_leave(msg);
			if ( cur )
				cur->mouse_enter(msg);
			last = cur;
			hWndLastPoint = msg->hwnd;
		}
		else if ( last != cur && cur ) {	// just turned into normal mode
			cur->mouse_enter(msg);
			last = cur;
		}
	}

	return hWndTracked ? tracked : cur;
}

void
VTrackedInfo::track_mouse(MSG *msg)
{
	switch ( msg->message ) {
	case WM_LBUTTONUP:
	case WM_RBUTTONUP:
	case WM_MBUTTONUP:
		if ( hWndTracked ) {			// tracking mode
			if ( tracked )
				tracked->mouse_up(msg);
			if ( (msg->wParam & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON)) == 0 ) {
				hWndTracked = NULL;		// end tracking
				if ( tracked )
					SetCapture(NULL);
				tracked = NULL;
			}
		}
	}

	VTrackedInfo *target = check_wnd(msg);

	if ( msg->message == WM_MOUSEMOVE && target ) {
		static HWND last_hwnd;
		static POINT last_point;
		if ( last_hwnd != msg->hwnd ||
				last_point.x != msg->pt.x ||
				last_point.y != msg->pt.y ) {
			target->mouse_move(msg);
			last_hwnd = msg->hwnd;
			last_point = msg->pt;
		}
	}

	switch ( msg->message ) {
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
	case WM_MBUTTONDOWN:
		if ( hWndTracked == NULL ) {	// normal mdoe
			hWndTracked = msg->hwnd;	// begin tracking
			tracked = target;
			if ( tracked )
				SetCapture(hWndTracked);
		}
		if ( tracked )
			tracked->mouse_down(msg);
	}
}
