////////////////////////////////////////////////////////////////////////////
// CMouse クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include "Mouse.h"
#include "TaEditDraw.h"
#include "CurPos.h"
#include "TaEditShell.h"

////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CMouse::CMouse( VClsPtr< CCursor > argpCursor, const CTaEditDraw *argpDraw, VClsPtr< CTextEdit > argpEditor ) :
	pCursor( argpCursor ), pDraw( argpDraw ), MouseStatus( TAMS_NORMAL ), pEditor( argpEditor ), LastEvent( TAE_BUTTON1_UP )
{

}

CMouse::~CMouse()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

// カーソルを構築
void CMouse::CreateCursor( Widget w )
{
	m_DestWgt = w;
	Display *pDisplay = XtDisplay( m_DestWgt );
	Window window = XtWindow( m_DestWgt );
	IBeamCursor = XCreateFontCursor( pDisplay, XC_xterm );
	ArrowCursor = XCreateFontCursor( pDisplay, XC_left_ptr );
	CurrentCursor = -1;
}

// Iビームポインタに変更
void CMouse::SetIBeam()
{
	// 変更する必要がなければ、処理しない
	if ( 1 == CurrentCursor ) return ;
	CurrentCursor = 1;

	Display *pDisplay = XtDisplay( m_DestWgt );
	Window window = XtWindow( m_DestWgt );
	XUndefineCursor( pDisplay, window );
	XDefineCursor( pDisplay, window, IBeamCursor );
}

// アローポインタに変更
void CMouse::SetArrow()
{
	// 変更する必要がなければ、処理しない
	if ( 0 == CurrentCursor ) return ;
	CurrentCursor = 0;

	Display *pDisplay = XtDisplay( m_DestWgt );
	Window window = XtWindow( m_DestWgt );
	XUndefineCursor( pDisplay, window );
	XDefineCursor( pDisplay, window, ArrowCursor );
}

// マウスのイベント
// x,yには負の値など、ウインドウの範囲を超える値が指定される場合がある。
void CMouse::OnMouse( TA_EVENT argEvent, int x, int y, ScrollInfoPacket *pPacket, bool OnShift, bool OnCtrl )
{
	// マウスカーソルの位置から、テキスト上での位置を算出
	T_CurPos wCurPos = pDraw->PixPosToCurPos( x, y );
	
	switch ( argEvent ) {
	case TAE_BUTTON1_DOWN:
		if ( LastEvent == TAE_BUTTON1_DOWN ) return ;
		LastEvent = TAE_BUTTON1_DOWN;

		if ( OnCtrl ) {
			// Ctrlキーが押されていた場合は、単語選択を行う
			pCursor->SelectWord( pPacket, wCurPos );
			MouseStatus = TAMS_SELECT;
			return ;
		}

		// マウスが押下されたときの文字位置を保存
		MouseDownPos = wCurPos;
		if ( pCursor->IsCharSelected( MouseDownPos ) ) {
			// 選択範囲上で、マウスが押下された場合
			MouseStatus = TAMS_TEXTMOVE;
			TextMoveSource = pCursor->GetSelRange();
		}
		else {
			// カーソルの位置を設定
			MouseStatus = TAMS_SELECT;
			pCursor->SetCurPos( wCurPos, pPacket, OnShift );
		}
		break;

	case TAE_BUTTON1_UP:
		if ( LastEvent == TAE_BUTTON1_UP ) return ;
		LastEvent = TAE_BUTTON1_UP;

		// 範囲選択だった場合は、モード変更のみを行い、処理を終了
		if ( MouseStatus == TAMS_SELECT ) {
			MouseStatus = TAMS_NORMAL;
			return ;
		}
		MouseStatus = TAMS_NORMAL;

		// テキスト移動だった場合は、テキストの移動処理を行う。

		// 選択範囲でカーソルが放されたら、特に処理は行わない。
		if ( pCursor->IsCharSelected( wCurPos ) ) {
			// ただし、マウスが押下されたときと同じ場所で放されたときは、範囲選択の解除を行う。
			if ( MouseDownPos == wCurPos )
				pCursor->SetCurPos( MouseDownPos, pPacket, T_SelRange( MouseDownPos, MouseDownPos ) );
			return ;
		}

		// テキストの移動を指示
		pEditor->MoveText( TextMoveSource, x, y );

		break;

	case TAE_MOTION:
		if ( LastEvent != TAE_MOTION && LastEvent != TAE_BUTTON1_DOWN ) return ;
		LastEvent = TAE_MOTION;

		switch ( MouseStatus ) {
		case TAMS_SELECT:
			// カーソルの位置を設定
			pCursor->SetCurPos( wCurPos, pPacket, true );
			break;
		case TAMS_TEXTMOVE:
			// 範囲選択ではなく、カーソルの位置を設定
			pCursor->SetCurPos( wCurPos, pPacket, TextMoveSource );
			break;
		}
		break;

	default:
		MouseStatus = TAMS_NORMAL;
		return ;
	}
}

// マウスポインタ移動のイベント
void CMouse::OnPointerMotion( int x, int y )
{
	// マウスカーソルの位置から、テキスト上での位置を算出
	T_CurPos wCurPos = pDraw->PixPosToCurPos( x, y );

	// ポインタの形状を設定
	if ( pCursor->IsCharSelected( wCurPos ) )
		SetArrow();
	else
		SetIBeam();
}

// 現在のマウスの状態を取得
TA_MOUSE_STATUS CMouse::GetMouseStatus() const
{
	return MouseStatus;
}

