The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "guts.h"
#include "Window.h"
#include "Icon.h"
#include "Application.h"

#ifdef __cplusplus
extern "C" {
#endif


#define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#define var (( PWidget) self)->
#define HANDLE sys handle
#define DHANDLE(x) dsys(x) handle


Bool
cursor_update( Handle self)
{
	if ( !is_apt( aptFocused))
		return true;
	DestroyCaret();
	if ( is_apt( aptCursorVis)) {
		if ( !CreateCaret(( HWND) var handle, nil, sys cursorSize. x, sys cursorSize. y)) apiErrRet;
		if ( !SetCaretPos( sys cursorPos. x, sys lastSize. y - sys cursorPos. y - sys cursorSize. y)) apiErrRet;
		if ( !ShowCaret(( HWND) var handle)) apiErrRet;
	}
	return true;
}

Bool
apc_cursor_set_pos( Handle self, int x, int y)
{
	objCheck false;
	if ( !hwnd_check_limits( x, y, true)) apcErrRet( errInvParams);
	sys cursorPos. x = x;
	sys cursorPos. y = y;
	return cursor_update( self);
}

Bool
apc_cursor_set_size( Handle self, int x, int y)
{
	objCheck false;
	if ( !hwnd_check_limits( x, y, false)) apcErrRet( errInvParams);
	sys cursorSize. x = x;
	sys cursorSize. y = y;
	return cursor_update( self);
}

Bool
apc_cursor_set_visible( Handle self, Bool visible)
{
	objCheck false;
	apt_assign( aptCursorVis, visible);
	return cursor_update( self);
}

Point
apc_cursor_get_pos( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys cursorPos;
}

Point
apc_cursor_get_size( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys cursorSize;
}

Bool
apc_cursor_get_visible( Handle self)
{
	objCheck false;
	return is_apt( aptCursorVis);
}

Point
apc_pointer_get_hot_spot( Handle self)
{
	Point         r = {0,0};
	ICONINFO      ii;
	objCheck r;
	if ( !GetIconInfo( sys pointer, &ii))
		apiErr
	else {
		r. x = ii. xHotspot;
		r. y = guts. pointerSize. y - ii. yHotspot - 1;
		DeleteObject( ii. hbmMask);
		DeleteObject( ii. hbmColor);
	}
	return r;
}

Point
apc_pointer_get_pos( Handle self)
{
	Point p = {0,0};
	RECT r;
	objCheck p;
	if ( !GetCursorPos(( POINT*) &p)) apiErr;
	GetWindowRect( HWND_DESKTOP, &r);
	p. y = r. bottom - p. y - 1;
	return p;
}

int
apc_pointer_get_shape( Handle self)
{
	objCheck 0;
	return sys pointerId;
}

Point
apc_pointer_get_size( Handle self)
{
	return guts. pointerSize;
}

Bool
apc_pointer_get_bitmap( Handle self, Handle icon)
{
	ICONINFO  ii;
	PIcon     i = ( PIcon) icon;
	HDC dc;
	XBITMAPINFO bi = {{
		sizeof( BITMAPINFOHEADER), 0, 0, 1, 1
	}};

	bi. bmiHeader. biWidth = guts. pointerSize. x;
	bi. bmiHeader. biHeight = guts. pointerSize. y;

	if ( icon == nilHandle)
		apcErrRet( errInvParams);
	objCheck false;
	dobjCheck( icon) false;
	if ( !GetIconInfo( sys pointer, &ii))
		apiErrRet;
	i-> self-> create_empty( icon, guts. pointerSize. x, guts. pointerSize. y, 1);
	if (!( dc = dc_alloc())) return false; 
	if ( ii. hbmColor) {
		HDC ops = dsys( icon) ps;
		HBITMAP obm = dsys( icon) bm;
		dsys( icon) ps = dc;
		dsys( icon) bm = ii. hbmColor;
		image_query_bits( icon, false);
		if ( !GetDIBits( dc, ii. hbmMask, 0, i-> h, i-> mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
		dsys( icon) ps = ops;
		dsys( icon) bm = obm;
	} else {
		bi. bmiHeader. biHeight *= 2;
		if ( !GetDIBits( dc, ii. hbmMask, 0, i-> h, i-> data, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
		if ( !GetDIBits( dc, ii. hbmMask, i-> h, i-> h, i-> mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
	}
	dc_free();
	DeleteObject( ii. hbmMask);
	DeleteObject( ii. hbmColor);
	return true;
}

Bool
apc_pointer_get_visible( Handle self)
{
	objCheck false;
	return !guts. pointerInvisible;
}

Bool
apc_pointer_set_pos( Handle self, int x, int y)
{
	RECT r;
	if ( !hwnd_check_limits( x, y, true)) apcErrRet( errInvParams);
	GetWindowRect( HWND_DESKTOP, &r);
	if ( !SetCursorPos( x, r. bottom - y - 1)) apiErrRet;
	return true;
}

Handle ctx_cr2IDC[] =
{
	crArrow,     ( Handle) IDC_ARROW,
	crText,      ( Handle) IDC_IBEAM,
	crWait,      ( Handle) IDC_WAIT,
	crSize,      ( Handle) IDC_SIZEALL,
	crMove,      ( Handle) IDC_SIZEALL,
	crSizeWest,  ( Handle) IDC_SIZEWE,
	crSizeEast,  ( Handle) IDC_SIZEWE,
	crSizeWE,    ( Handle) IDC_SIZEWE,
	crSizeNorth, ( Handle) IDC_SIZENS,
	crSizeSouth, ( Handle) IDC_SIZENS,
	crSizeNS,    ( Handle) IDC_SIZENS,
	crSizeNW,    ( Handle) IDC_SIZENWSE,
	crSizeSE,    ( Handle) IDC_SIZENWSE,
	crSizeNE,    ( Handle) IDC_SIZENESW,
	crSizeSW,    ( Handle) IDC_SIZENESW,
	crInvalid,   ( Handle) IDC_NO,
	endCtx
};

static Bool
direct_pointer_change( Handle self)
{
	Point p;
	if ( var stage != csNormal || !IsWindowVisible( HANDLE)) return false;
	p = apc_pointer_get_pos( application);
	return self == apc_application_get_widget_from_point( application, p);
}

Bool
apc_pointer_set_shape( Handle self, int sysPtrId)
{
	HCURSOR user;

	objCheck false;
	user = sys pointer2;
	if ( sysPtrId < crDefault || sysPtrId > crUser) return false;
	sys pointerId = sysPtrId;
	if ( sysPtrId == crDefault)
	{
		Handle owner = var owner;
		while( owner)
		{
			sysPtrId = dsys( owner) pointerId;
			if ( sysPtrId != crDefault) break;
			owner = (( PComponent) owner)-> owner;
		}
		if ( sysPtrId == crDefault) sysPtrId = crArrow;
		if ( sysPtrId == crUser) user = dsys( owner) pointer2;
	}
	sys pointer = ( sysPtrId == crUser) ? user :
		LoadCursor( NULL, MAKEINTRESOURCE(
		ctx_remap_def( sysPtrId, ctx_cr2IDC, true, ( Handle)IDC_ARROW)));

	if ( direct_pointer_change( self)) 
		SetCursor( sys pointer);
	return true;
}

Bool
apc_pointer_set_user( Handle self, Handle icon, Point hotSpot)
{
	Bool direct;
	HCURSOR cursor;
	objCheck false;
	
	apcErrClear;
	direct = direct_pointer_change( self);
	hotSpot. y = guts. pointerSize. y - hotSpot. y - 1;
	cursor = icon ? image_make_icon_handle( icon, guts. pointerSize, &hotSpot) : nil;
	if ( apcError) return false;
	
	if ( sys pointer2) {
		if ( direct) SetCursor( NULL);
		if ( !DestroyCursor( sys pointer2)) apiErr;
	}
	sys pointer2 = cursor;
	
	if ( sys pointerId == crUser)
	{
		sys pointer = sys pointer2;
		if ( direct) SetCursor( sys pointer);
	}
	return true;
}

Bool
apc_pointer_set_visible( Handle self, Bool visible)
{
	if ( var stage == csNormal) {
		guts. pointerInvisible = !visible;
		ShowCursor( visible);
		guts. pointerLock += visible ? 1 : -1;
	}
	return true;
}

int
apc_pointer_get_state( Handle self)
{
	return
		(( GetKeyState( VK_LBUTTON) < 0) ? mbLeft     : 0) |
		(( GetKeyState( VK_RBUTTON) < 0) ? mbRight    : 0) |
		(( GetKeyState( VK_MBUTTON) < 0) ? mbMiddle   : 0);
}

#ifdef __cplusplus
}
#endif