/*
	スクロールウィンドウ型の実現部
*/

#define	MODULE_SCRLWIN

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <mos.h>
#include "newmsg.h"
#include "scrlwin.h"

int 	MJ_SCRLWIN = -1;

/* WINDOW型の定数 */

	#define CLOSEWX		12
	#define CLOSEWY 	12
	#define RESIZEWX	16
	#define RESIZEWY	16

	#define TITLEHIGHT	(CLOSEWY + 2)

	#define FFONTSIZE	12
	#define HFONTSIZE	(FFONTSIZE/2)

	extern int	MC_checkMoveFrame40(int, FRAME *) ;

/* SCRLWIN型の定数 */

	#define	TitleHeight		16
	#define	SbarWidth		16
	#define	EraseboxSize	12

  /* 部品の新規生成 (id＝メタクラス部品の ID) */
	#define	CREATE(id)			MMI_SendMessage((id), MM_NEW, 0)
	#define	OBJPTR(objId)			TL_getObjectPtr(objId)
	#define	OBJHYP(objId)			(*(HYPER *)TL_getObjectPtr(objId)->data)
	#define	OBJDATA(type,objId)		(*(type *)TL_getObjectPtr(objId)->data)

/*--------------------------------------------------------*/
/*        ウィンドウ上の各部品の位置・大きさを計算        */
/*--------------------------------------------------------*/

	static void getframe_user(FRAME *back, FRAME *org)
	{
		org->lupx = 1;
		org->lupy = 1 + TitleHeight;
	  /* 大きさ */
		org->rdwx = (back->rdwx - back->lupx + 1) - (SbarWidth + 1);
		org->rdwy = (back->rdwy - back->lupy + 1) - (SbarWidth + TitleHeight);
	}

	static void GetFrame_TitleBar(FRAME *back, FRAME *titleFr)
	{
		titleFr->lupx = back->lupx + 1;
		titleFr->lupy = back->lupy + 1;
		titleFr->rdwx = back->rdwx - 1;
		titleFr->rdwy = back->lupy + 1 + TitleHeight - 1;
	}

	static void GetFrame_ScrlBarVert(FRAME *back, FRAME *scrlFr)
	{
		scrlFr->lupx = back->rdwx + 1 - SbarWidth;
		scrlFr->lupy = back->lupy + 1 + TitleHeight - 1;
		scrlFr->rdwx = back->rdwx;
		scrlFr->rdwy = back->rdwy + 1 - SbarWidth;
	}

	static void GetFrame_ScrlBarHori(FRAME *back, FRAME *scrlFr)
	{
		scrlFr->lupx = back->lupx;
		scrlFr->lupy = back->rdwy + 1 - SbarWidth;
		scrlFr->rdwx = back->rdwx + 1 - SbarWidth;
		scrlFr->rdwy = back->rdwy;
	}

	static void GetFrame_TitleMsg(FRAME *back, FRAME *msgFr)
	{
		msgFr->lupx = back->lupx + TitleHeight + 6;
		msgFr->lupy = back->lupy + 1;
		msgFr->rdwx = back->rdwx - 1;
		msgFr->rdwy = back->lupy + 1 + TitleHeight - 1;
	}

	static void getframe_resize(FRAME *back, FRAME *resizeFr)
	{
		resizeFr->lupx = back->rdwx-16+1;
		resizeFr->lupy = back->rdwy-16+1;
		resizeFr->rdwx = back->rdwx;
		resizeFr->rdwy = back->rdwy;
	}

	static void GetFrame_EraseBox(FRAME *back, FRAME *ersboxFr)
	{
		ersboxFr->lupx = back->lupx + 1 + 2;
		ersboxFr->lupy = back->lupy + 1 + 2;
		ersboxFr->rdwx = ersboxFr->lupx + EraseboxSize - 1;
		ersboxFr->rdwy = ersboxFr->lupy + EraseboxSize - 1;
	}

/*--------------------------------------------------------*/
/*        イレーズボタン、スクロールバーの実行関数        */
/*--------------------------------------------------------*/

	static int eraseboxFunc(int idObj)
	{
		int idWin;
		idWin = OBJPTR(idObj)->base;
		if (idWin >= 0)
		{
			MMI_SendMessage(idWin, MM_ERASE, 0) ;
			MMI_SendMessage(idWin, MM_DETACH, 0) ;
		}
		else
			printf("Warn(<imagewin>eraseboxFunc): 親が見つかりません\n");
		return NOERR;
	}

	static int sbarFunc(int idObj,int idMsg,int nArg,EVENT *pev,int trig)
	{
		int nWin;
		int (*ufunc)();
		nWin = OBJPTR(idObj)->base;
		if (nWin >= 0)
		{
			SCRLWIN *pWinData = &OBJDATA(SCRLWIN, nWin);
			int nMsg;
			ufunc = pWinData->ufunc;
			if (idObj == pWinData->idScrlBarHori)
				nMsg = MM_HSCROLL;
			else
				nMsg = MM_VSCROLL;
			if (ufunc != 0)
				(*ufunc)(nWin, nMsg, nArg, pev, trig);
		}
		else
			printf("Warn(<imagewin>sbarFunc): 親が見つかりません\n");
		return NOERR;
	}

/*--------------------------------------------------------*/
/*         (local) ウィンドウの呼び出し関数の起動         */
/*--------------------------------------------------------*/

  /* ウィンドウの呼び出し関数の起動 */

	static int ExecCallback(int idObj, int idMsg, int nArg,
							EVENT *pEv, int trigger)
	{
		SCRLWIN *pWin ;
		int	ret = ILLIGAL_FUNCTION ;
		pWin = &OBJDATA(SCRLWIN, idObj);
		if (pWin->ufunc != 0)
		{
			/*	トリガ情報を作成する	*/
			if (nArg < 0)
			{
				trigger = 0 ;
				if (pEv != NULL)
				{
					if (pEv->what == EVMESSAGE)  trigger |= MS_EVMSGL40 ;
					if (pEv->what == EVTIMER)    trigger |= MS_EVTIMERL40 ;
					if (pEv->what == EVKEY)      trigger |= MS_EVKEYONL40 ;
					if (pEv->what == EVMOSMOVE)  trigger |= MS_EVMOVEL40 ;
					if (pEv->what == EVMOSDRAG)  trigger |= MS_EVDRAGL40 ;
				}
				nArg = 2 ;
			}
			ret = (*(pWin->ufunc))(idObj, idMsg, nArg, pEv, trigger ) ;
		}
		return ret ;
	}

  /* ユーザー領域内での、ウィンドウの呼び出し関数の起動 */

	static int WinUser_ExecCallback(int idWin, int idMsg, int nArg,
									EVENT *pEv, int flgTrigger)
	{
		int	ret = ILLIGAL_FUNCTION ;
		SCRLWIN	*pWin ;
		pWin = (SCRLWIN *)(TL_getObjectPtr(idWin)->data) ;
		if (pWin->org.rdwx && pWin->org.rdwy)
		{
			FRAME frUser ;
			WINCLIP	*pWinClip ;
			WINCTRL	*pWinCtrl ;
		  /* ユーザ領域の可視範囲と現在のクリップ領域の AND を求める */
			frUser.lupx = pWin->fr.lupx + pWin->org.lupx ;
			frUser.lupy = pWin->fr.lupy + pWin->org.lupy ;
			frUser.rdwx = frUser.lupx + pWin->org.rdwx - 1 ;
			frUser.rdwy = frUser.lupy + pWin->org.rdwy - 1 ;
			pWinClip = WIN_getClipMemory(&frUser, NULL) ;
			pWinClip = WIN_clipWindow( idWin, pWinClip, FALSE ) ;
			MMI_GetControl(&pWinCtrl) ; /* 現在のクリップとの and をとる */
			pWinClip = WIN_andClip(pWinClip, pWinCtrl->clip);
		  /* 求めたクリップ領域が空でないなら、
			 ユーザー領域内でウィンドウの呼び出し関数を起動 */
			if (pWinClip != NULL)
			{
				WINCLIP	*pWinClipStack, *pVisibleStack ;
				POINT	ptUserOrig, ptOriginStack ;
			  /* 表示枠を設定する */
				WIN_pushVisible(WIN_copyClip(pWinClip), &pVisibleStack) ;
				WIN_pushClip(pWinClip, &pWinClipStack) ;
			  /* ユーザ描画領域の左上に描画原点を設定 */
				MMI_GetOrigin(&ptUserOrig) ;
				AddPt((Point *)&ptUserOrig, (Point *)&(pWin->fr)) ;
				AddPt((Point *)&ptUserOrig, (Point *)&(pWin->org)) ;
				MG_PushOrigin(&ptUserOrig, &ptOriginStack) ;
			  /* 呼び出し関数を起動 */
				ret = ExecCallback(idWin, idMsg, nArg, pEv, flgTrigger) ;
			  /* 描画原点、クリップ領域、ビジブル領域を復帰 */
				MG_PopOrigin(&ptOriginStack) ;
				WIN_popClip(pWinClipStack) ;
				WIN_popVisible(pVisibleStack) ;
			}
		}
		return ret ;
	}

  /* イベントの起こった座標がユーザ領域内なら、呼び出し関数を起動 */

	static int WinUser_CheckExecCallback(int idWin, int idMsg, EVENT *pEv)
	{
		SCRLWIN *pWin ;
		FRAME	frUser ;
		pWin = (SCRLWIN *)(TL_getObjectPtr(idWin)->data) ;
		if (pWin->org.rdwx && pWin->org.rdwy)
		{
			frUser.lupx = pWin->fr.lupx + pWin->org.lupx ;
			frUser.lupy = pWin->fr.lupy + pWin->org.lupy ;
			frUser.rdwx = frUser.lupx + pWin->org.rdwx - 1 ;
			frUser.rdwy = frUser.lupy + pWin->org.rdwy - 1 ;
			if (PtInRect((Rect *)&frUser, (Point *)&(pEv->info)))
				return WinUser_ExecCallback(idWin, idMsg, UNUSED, pEv, 0) ;
		}
		return OUTSIDE ;
	}

/*---------------------------------------------------------*/
/*   (local) 兄弟ウィンドウのアクティブ化／非アクティブ化  */
/*---------------------------------------------------------*/

  /* ウィンドウのアクティブ／非アクティブの設定 */

	static void SetWinActiveness(int idWin, int bActive)
	{
		OBJECT	*pObj ;
		SCRLWIN	*pWin ;
		WINCLIP	*pWinClip;
		pWin = (SCRLWIN *)((pObj = TL_getObjectPtr(idWin))->data) ;
		if (bActive)
		{
			pObj->flag |= MS_ACTOBJ ;
			OBJDATA(DBUTTONL40, pWin->idTitleBar).clr.back = 0;
		}
		else
		{
			pObj->flag &= (~MS_ACTOBJ) ;
			OBJDATA(DBUTTONL40, pWin->idTitleBar).clr.back = 7;
		}
		if (pObj->flag & MS_DSP)
		{
			MG_mosDisp(2) ;
			WIN_beginUpDateObj(pWin->idTitleBar, &pWinClip);
			MMI_SendMessage(pWin->idTitleBar, MM_SHOW, 0);
			MMI_SendMessage(pWin->idTitleMsg, MM_SHOW, 0);
			MMI_SendMessage(pWin->idEraseBox, MM_SHOW, 0);
			WIN_endUpDateObj(pWinClip);
			MG_mosDisp(3) ;
		}
	}

  /* 指定されたウィンドウ以外を非アクティブにする */

	static void SetBrotherWins_NoActive(int idWin)
	{
		int		idObj1, idObj2 ;
		for (idObj1 = idWin ;
			 (idObj2 = TL_getObjectPtr(idObj1)->llevel) != idWin ;
			 idObj1 = idObj2 )
		{
			if (MTL_isMetaClass(idObj2, MJ_SCRLWIN))
				if (MTL_checkFlagObj(idObj2, (MS_ACTOBJ|MS_DSP)) ==
												(MS_ACTOBJ|MS_DSP))
				{
					SetWinActiveness(idObj2, FALSE) ;
					ExecCallback(idObj2, MM_SLEEP, UNUSED, NULL, 0) ;
				}
		}
	}

  /* 指定されたウィンドウを非アクティブにする */

	static int SetWin_NoActive(int idObj)
	  /* ウィンドウの呼び出し関数を呼ぶ前に呼び出すこと */
	  /* 返り値・次にアクティブにするべきウィンドウの ID */
	{
		int	idObj1, idObj2 ;
		OBJECT	*pObj ;
		pObj = TL_getObjectPtr(idObj) ;
		if (pObj->flag & MS_ACTOBJ)
		{
			if (TL_checkMmiModeFlag(MS_WINMOVE) == 0)
			{
				pObj->flag &= (~MS_ACTOBJ) ;
				for (idObj1 = idObj;
					 (idObj2 = TL_getObjectPtr(idObj1)->rlevel) != idObj;
					 idObj1 = idObj2)
				{
					if (MTL_isMetaClass(idObj2, MJ_SCRLWIN))
						if (MTL_checkFlagObj(idObj2, MS_DSP))
							return idObj2;
				}
			}
		}
		return -1;
	}

/*--------------------------------------------------------*/
/*                    ウィンドウの生成                    */
/*--------------------------------------------------------*/

	int	SCRLWIN_NEW_func(int mobj, int idMsg, int nArg)
	{
			static DBUTTONL40 data_TitleBar =
				{ MS_DSPONLYL40,{0,0,0,0},{0,7,0}, MS_FRAMEL40 | MS_UFRAMEL40,
				  0,  0 };
			static MSGL40 data_TitleMsg =
				{ MS_LEFTL40| MS_DSPONLYL40, {0,0,0,0}, {0,0,15},
				  MS_NONEL40, "", 1, 12,12, MS_NONEL40, 0, 0 } ;
			static DBUTTONL40 data_EraseBox =
				{ MS_BTLEFTL40 | MS_EVMOSOFFL40 | MS_EVKEYONL40,
				  {0,0,0,0},{0,7,0}, MS_PANELL40,
				  eraseboxFunc,  0 };
			static SCRLL40 data_ScrlBarVert =
				{ MS_BTLEFTL40| MS_REPEATL40| MS_EVMOSONL40,
				  {0,0,0,0}, {0,7,7}, MS_FRAMEL40|MS_PANELL40,
				  sbarFunc,  0,0,100,10,1, IUPARROW, IDOWNARROW };
			static SCRLL40 data_ScrlBarHori =
				{ MS_BTLEFTL40| MS_REPEATL40| MS_EVMOSONL40| MS_HORIL40,
				  {0,0,0,0}, {0,7,7}, MS_FRAMEL40|MS_PANELL40,
				  sbarFunc,  0,0,100,10,1, ILEFTARROW, IRIGHTARROW };
		int			id, idScrlWin;
		SCRLWIN		*pScrlWin;
		DBUTTONL40	*pDBUTTONL40;
		SCRLL40		*pSCRLL40;
		MSGL40		*pMSGL40;
		extern int ML_NewHyper(int, int, int);
		if ((idScrlWin = ML_NewHyper(mobj, idMsg, nArg)) < 0)
			return idScrlWin;
		pScrlWin = &OBJDATA(SCRLWIN, idScrlWin);
		#define WIN (*pScrlWin)
	  /* ユーザー領域の設定 */
		getframe_user(&WIN.fr, &WIN.org);
	  /* 部品生成・アタッチのためのマクロ定義 */
		#define CREATE_AND_ATTACH(NAME, TYPE)				\
		  {	if ((id = CREATE(MJ_##TYPE)) < 0)				\
				return id;									\
			p##TYPE = & OBJDATA(TYPE, id);					\
			*p##TYPE = data_##NAME;							\
			GetFrame_##NAME(&WIN.fr, &p##TYPE->fr);			\
			MMI_SendMessage(id, MM_ATTACH, 1, idScrlWin);	\
			WIN.id##NAME = id; }
	  /* 各部品の生成・アタッチ */
		CREATE_AND_ATTACH(TitleBar, DBUTTONL40)
		CREATE_AND_ATTACH(TitleMsg, MSGL40)
		CREATE_AND_ATTACH(EraseBox, DBUTTONL40)
		CREATE_AND_ATTACH(ScrlBarVert, SCRLL40)
		CREATE_AND_ATTACH(ScrlBarHori, SCRLL40)
	  /* おわり */
		#undef WIN
		return idScrlWin;
	}

/*--------------------------------------------------------*/
/*                   ウィンドウのERASE                    */
/*--------------------------------------------------------*/

		/* 処理内容は WINDOWL40 型と同じだが、
		   呼び出し関数内で自身を DESTROY してもよいようにした */

	static int SCRLWIN_ERASE_func(int idObj, int idMsg, int nArg)
	{
		int	ret ;
		int	wakeId ;
		ret = MMI_SuperSendMessage(MJ_DIALOGL40, idObj, idMsg, nArg) ;
		if (TL_checkMmiModeFlag(MS_WINMOVE) == 0)
		  /* ウィンドウの移動／リサイズによって消去したのでなければ */
		{
			wakeId = SetWin_NoActive(idObj);
			ExecCallback(idObj, MM_ERASE, UNUSED, NULL, 0) ;
			if (wakeId >= 0)
			{
				SetWinActiveness(wakeId, TRUE);
				ExecCallback(wakeId, MM_WAKE, UNUSED, NULL, 0) ;
			}
		}
		return ret ;
	}

/*--------------------------------------------------------*/
/*               ウィンドウの WAKE / SLEEP                */
/*--------------------------------------------------------*/
	  
		static void SetWinWakeness(int idWin, int flag)
		{
			OBJECT	*pWinObj ;
			SCRLWIN	*pWin ;
			int		wakeId ;
			int		base ;
			WINCLIP	*pwclps ;
			WINCLIP	*pwclpd ;
			pWin = (SCRLWIN *)((pWinObj = TL_getObjectPtr(idWin))->data) ;
			wakeId = UNUSED ;
			if (flag)
			{
				if ((pWinObj->flag & MS_ACTOBJ) == 0)
				{
					wakeId = idWin;
					SetBrotherWins_NoActive(wakeId) ;
					SetWinActiveness(wakeId, TRUE) ;
				}
			}
			else
			{
				if (pWinObj->flag & MS_ACTOBJ)
				{
					wakeId = SetWin_NoActive(idWin) ;
					SetWinActiveness(idWin, FALSE) ;
					ExecCallback(idWin, MM_SLEEP, UNUSED, NULL, 0) ;
				}
			}
		  /* ライズ前の表示範囲を求める */
			pwclps = WIN_getClipMemory(&(pWin->fr), NULL) ;
			pwclpd = WIN_copyClip(pwclps) ;
			pwclps = WIN_clipWindow(idWin, pwclps, FALSE) ;
		  /* ウィンドウをライズ(最前面に移動)する */
			base = pWinObj->base ;
			MMI_SendMessage(idWin, MM_DETACH, 0) ;
			MMI_SendMessage(idWin, MM_ATTACH, 2, base, (flag) ? -1 : 0) ;
		  /* ライズ後の表示範囲から、再表示の必要のある領域を得る */
			pwclpd = WIN_clipWindow(idWin, pwclpd, FALSE) ;
		  /* 再描画 */
			MMI_SendMessage(idWin, MM_UPDATE, 1, (flag) ?
								(pwclpd = WIN_removeClip(pwclpd, pwclps)) :
									(pwclps = WIN_removeClip(pwclps, pwclpd)));
		  /* クリップ領域を開放 */
			WIN_freeClipMemory(pwclpd) ;
			WIN_freeClipMemory(pwclps) ;
		  /* 呼び出し関数を起動 */
			if (wakeId > 0)
				ExecCallback(wakeId, MM_WAKE, UNUSED, NULL, 0) ;
		}

	static int SCRLWIN_WAKE_func(int idObj)
	{
		SetWinWakeness(idObj, TRUE);
		return NOERR;
	}
	
	static int SCRLWIN_SLEEP_func(int idObj)
	{
		SetWinWakeness(idObj, FALSE);
		return NOERR;
	}

/*--------------------------------------------------------*/
/*           マウスがクリックされた場合 (MOSON)           */
/*--------------------------------------------------------*/

	/* リサイズ処理 */

		static int resize(int idScrlWin,  EVENT *pev)
			/* リサイズ処理が行われたなら 1 を返す */
		{
			SCRLWIN *pScrlWin;
			HYPER	hypWin;
			WINCLIP	*pWinClip ;
		  /* 各種情報を取得 */
			pScrlWin = &OBJDATA(SCRLWIN, idScrlWin);
			hypWin = *((HYPER *)pScrlWin);
			MG_SizeBoxL40( &hypWin, TRUE ) ; /* ウインドウの内枠を求める */
		  /* ウィンドウにリサイズボックスがないなら何もせず終了 */
			if ((pScrlWin->atr & MS_RESIZEL40) == 0)
				return 0;
		  /* リサイズボックスの描画のためのハイパ構造体を作成 */
			static HYPER hypResize =
				{ MS_NONEL40,{0},{0}, MS_PANELL40| MS_FRAMEL40| MS_INVERTL40 };
			hypResize.clr = pScrlWin->clr ;
		  /* リサイズボックスの表示範囲を求める */
			int nFrWid;
			nFrWid = (pScrlWin->atrm & MS_FRAMEL40) ? 1 : 0 ;
			#define WIN_FR	hypWin.fr
			hypResize.fr.lupx = WIN_FR.rdwx - RESIZEWX + 1 + nFrWid ;
			hypResize.fr.lupy = WIN_FR.rdwy - RESIZEWY + 1 + nFrWid ;
			hypResize.fr.rdwx = WIN_FR.rdwx + nFrWid ;
			hypResize.fr.rdwy = WIN_FR.rdwy + nFrWid ;
			#undef WIN_FR
		  /* リサイズボックスの中でないならなにもせず終了 */
			if (PtInRect((Rect *)&(hypResize.fr), (Point *)&(pev->info)) == 0)
				return 0;
		  /* リサイズボックスの押下状態を描画 */
			#define DRAW_RESIZEBTN(bPush)							\
			  {	MG_mosDisp(2) ;										\
				WIN_beginUpDateObj(idScrlWin, &pWinClip) ;			\
				MG_DspBoxL40((HYPER *)&hypResize, TRUE, bPush) ;	\
				WIN_endUpDateObj(pWinClip) ;						\
				MG_mosDisp(3) ; }
			DRAW_RESIZEBTN(TRUE);
		  /* ウィンドウ枠をXOR で表示しながらリサイズ入力 */
			FRAME frOrig;
			FRAME frResult;
			frResult = frOrig = pScrlWin->fr ;
			MG_ReSizeFrame(&frResult, pev, FRIGHTDOWN, &(pScrlWin->size)) ;
		  /* リサイズボックスの非押下状態を描画 */
			DRAW_RESIZEBTN(FALSE);
		  /* サイズが変わっていなかったら、なにもせず正常終了 */
			if (MC_checkMoveFrame40(idScrlWin, &frResult) == 0)
				return 1;
		  /* 再描画の準備 */
			char *pSave ;
			TL_setWinMoveFlag() ;  /* SHOW時の V.E.を無効にする */
			if ((pSave = pScrlWin->save) != NULL)
				MMI_SendMessage(idScrlWin, MM_ERASE, 0) ;
		  /* ウィンドウの大きさを再設定 */
			MMI_SendMessage(idScrlWin, MM_SETFRAME, 1, &frResult);
		  /* 再描画のためのクリップ領域を設定 */
			FRAME	saveFr ;
			saveFr = pScrlWin->fr ;
			UnionRect((Rect *)&frOrig, (Rect *)&frResult) ;
			pScrlWin->fr = frOrig ;
			WIN_beginUpDateObj(idScrlWin, &pWinClip) ;
			pScrlWin->fr = saveFr ;
		  /* 再描画 */
			ExecCallback(idScrlWin, MM_UPDATE, UNUSED, pev, 0) ;
			if (pSave == NULL)
			{
			  WINCTRL *pctrl ;
			  MMI_GetControl(&pctrl) ;
			  MMI_SendMessage(idScrlWin,MM_UPDATE,1,pctrl->clip) ;
			}
		  /* 再描画の終了 */
			WIN_endUpDateObj(pWinClip) ;
			if (pSave)
				MMI_SendMessage(idScrlWin, MM_SHOW, 0) ;
			TL_resetWinMoveFlag() ;
			return 1;
		}

	int	SCRLWIN_MOSON_func(int idScrlWin, int idMsg, int nArg, EVENT *pev)
	{
		int ret ;
		register OBJECT	*pObj ;
		register SCRLWIN *pScrlWin ;
		pScrlWin = (SCRLWIN *)((pObj = TL_getObjectPtr(idScrlWin))->data) ;
		if (((pScrlWin->atr &(MS_BTLEFTL40|MS_BTRIGHTL40)) & 
				((pev->shift) << 22)) == 0)
			return NOERR ;
		if (pObj->flag & MS_ACTOBJ)
		  /* WAKE 状態のウィンドウの場合 */
		{
			if (resize(idScrlWin, pev))
				return NOERR;	/* リサイズ処理が正常終了した */
			if (WinUser_CheckExecCallback(idScrlWin, idMsg, pev) < NOERR)
			{
			  /* ユーザ領域外なので、ダイアログクラスとして移動チェック */
				TL_setWinMoveFlag() ;	/* SHOW時の V.E.無効化 */
				POINT orgDisp ;
				orgDisp = *(POINT *)&(pScrlWin->fr) ;
				ret = MMI_SuperSendMessage(MJ_DIALOGL40, 
										   idScrlWin, idMsg, nArg, pev) ;
			  /* 移動したなら、MOVE 処理 */
				if (*(int *)&(pScrlWin->fr) != *(int *)&(orgDisp))
					ExecCallback(idScrlWin, MM_MOVE, UNUSED, NULL, 0) ;
				TL_resetWinMoveFlag() ;
				return ret ;
			}
		}
		else
		  /* SLEEP状態のウィンドウの場合 */
		{
			register int	mosTime ;
			EVENT	*pnev ;
			mosTime = MOS_getTime() ;
		  /* アクティブなウインドウを設定し画面の上に持ってくる. */
			MMI_SendMessage(idScrlWin, MM_WAKE, 0) ;
		  /* ディレイ */
			do
			{
				MMI_iosense() ;
				if (MMI_SnsEvnt(EVALL, &pnev) == 0)
				{
					if ((pnev->what != EVMOSUP)||
							(((pnev->shift & (SRIGHTBTN|SLEFTBTN)) &
								(pev->shift & (SRIGHTBTN|SLEFTBTN))) == 0))
						break ;
					return NOERR ;
				}
			} while ((MOS_getTime() - mosTime) <= REPEAT_TIME2) ;
		  /* イベントの再実行はしない */
			// MMI_ExecEvnt(pev) ;
		}
		return NOERR ;
	}

/*--------------------------------------------------------*/
/*              ウィンドウの属性の設定・取得              */
/*--------------------------------------------------------*/

	int	SCRLWIN_SETHYPER_func(int idObj, int idMsg, int nArg, HYPER *hyp)
	{
		SCRLWIN *data;
		data = &OBJDATA(SCRLWIN, idObj);
		OBJHYP(idObj) = *hyp;
		getframe_user(&hyp->fr, &data->org);
		GetFrame_TitleBar(&hyp->fr, &OBJHYP(data->idTitleBar).fr);
		GetFrame_TitleMsg(&hyp->fr, &OBJHYP(data->idTitleMsg).fr);
		GetFrame_EraseBox(&hyp->fr, &OBJHYP(data->idEraseBox).fr);
		GetFrame_ScrlBarVert(&hyp->fr, &OBJHYP(data->idScrlBarVert).fr);
		GetFrame_ScrlBarHori(&hyp->fr, &OBJHYP(data->idScrlBarHori).fr);
		return NOERR ;
	}

	static int SCRLWIN_SETUSER_func(kobj, messId, argc, org, size)
	int		kobj ;
	int		messId ;
	int		argc ;
	FRAME	*org ;
	FRAME	*size ;
	{
		register WINDOWL40	*pwin ;

		pwin = (WINDOWL40 *)(TL_getObjectPtr(kobj)->data) ;

		pwin->org = *org ;
		pwin->size = *size ;

		return NOERR ;
	}

	static int SCRLWIN_GETUSER_func(kobj, messId, argc, org, size)
	int		kobj ;
	int		messId ;
	int		argc ;
	FRAME	*org ;
	FRAME	*size ;
	{
		register WINDOWL40	*pwin ;

		pwin = (WINDOWL40 *)(TL_getObjectPtr(kobj)->data) ;

		*org = pwin->org ;
		*size = pwin->size ;

		return NOERR ;
	}

	int	SCRLWIN_SETEXEC_func(int idObj, int idMsg,int nArg, int (*f)())
	{
		OBJDATA(SCRLWIN, idObj).ufunc = f;
		return NOERR;
	}

	int	SCRLWIN_SETATR_func(int idObj, int idMsg, int nArg, int atr)
	{
		((HYPER*)(TL_getObjectPtr(idObj)->data))->atr = atr;
		return NOERR;
	}

	int	SCRLWIN_GETATR_func(int idObj, int idMsg, int nArg, int *atr)
	{
		*atr = ((HYPER*)(TL_getObjectPtr(idObj)->data))->atr;
		return NOERR;
	}

	int	SCRLWIN_SETFRAME_func(int idObj, int idMsg, int nArg, FRAME *fr)
	{
		HYPER hyp;
		MMI_SendMessage(idObj, MM_GETHYPER, 1, &hyp);
		hyp.fr = *fr;
		MMI_SendMessage(idObj, MM_SETHYPER, 1, &hyp);
		return NOERR;
	}
	
	int	SCRLWIN_GETFRAME_func(int idObj, int idMsg, int nArg, FRAME *fr)
	{
		HYPER hyp;
		MMI_SendMessage(idObj, MM_GETHYPER, 1, &hyp);
		*fr = hyp.fr;
		return NOERR;
	}

	int SCRLWIN_dummy_func()
	{
		return NOERR;
	}

	int SCRLWIN_SETMSG_func(int kobj, int messId, int argc, char *string)
	{
		int id;
		id = OBJDATA(SCRLWIN, kobj).idTitleMsg;
		MMI_SendMessage(id, messId, argc, string);
		return NOERR ;
	}

/*--------------------------------------------------------*/
/*             スクロールバーの設定・状態取得             */
/*--------------------------------------------------------*/

	int SCRLWIN_SETHSCROLL_func(int idObj, int idMsg, int nArg,
			int bRedraw,int nPos,int nMin,int nMax,int nLen,int nPageSkip)
		/*
			nArg:
				1	(bRedraw のみ)	再描画だけを行う場合
				2	(nPos まで)		位置の設定だけ
				4	(nMax まで)		範囲の設定
				6					全部設定
		*/
	{
		int	nPos2, nMin2, nMax2, nLen2, nPageSkip2;
		int idSbar;
		idSbar = OBJDATA(SCRLWIN, idObj).idScrlBarHori;
		MMI_SendMessage(idSbar, MM_GETSCROLL, 5,
						&nPos2, &nMin2, &nMax2, &nLen2, &nPageSkip2);
		if (nArg >= 2)	nPos2 = nPos;
		if (nArg >= 3)	nMin2 = nMin;
		if (nArg >= 4)	nMax2 = nMax;
		if (nArg >= 5)	nLen2 = nLen;
		if (nArg >= 6)	nPageSkip2 = nPageSkip;
		MMI_SendMessage(idSbar, MM_SETSCROLL, 5,
						nPos2, nMin2, nMax2, nLen2, nPageSkip2);
		if (bRedraw)
			MMI_SendMessage(idSbar, MM_SHOW, 0);
		return NOERR;
	}

	int SCRLWIN_SETVSCROLL_func(int idObj, int idMsg, int nArg,
			int bRedraw,int nPos,int nMin,int nMax,int nLen,int nPageSkip)
	{
		int	nPos2, nMin2, nMax2, nLen2, nPageSkip2;
		int idSbar;
		idSbar = OBJDATA(SCRLWIN, idObj).idScrlBarVert;
		MMI_SendMessage(idSbar, MM_GETSCROLL, 5,
						&nPos2, &nMin2, &nMax2, &nLen2, &nPageSkip2);
		if (nArg >= 2)	nPos2 = nPos;
		if (nArg >= 3)	nMin2 = nMin;
		if (nArg >= 4)	nMax2 = nMax;
		if (nArg >= 5)	nLen2 = nLen;
		if (nArg >= 6)	nPageSkip2 = nPageSkip;
		MMI_SendMessage(idSbar, MM_SETSCROLL, 5,
						nPos2, nMin2, nMax2, nLen2, nPageSkip2);
		if (bRedraw)
			MMI_SendMessage(idSbar, MM_SHOW, 0);
		return NOERR;
	}

	int SCRLWIN_GETHSCROLL_func(int idObj, int idMsg, int nArg,
			int *pnPos, int *pnMin, int *pnMax, int *pnLen, int *pnPageSkip)
	{
		int nPos2, nMin2, nMax2, nLen2, nPageSkip2;
		int idSbar;
		idSbar = OBJDATA(SCRLWIN, idObj).idScrlBarHori;
		MMI_SendMessage(idSbar, MM_GETSCROLL, 5,
						&nPos2,&nMin2,&nMax2,&nLen2,&nPageSkip2);
		if (nArg >= 1 && pnPos != NULL)
			*pnPos = nPos2;
		if (nArg >= 2 && pnMin != NULL)
			*pnMin = nMin2;
		if (nArg >= 3 && pnMax != NULL)
			*pnMax = nMax2;
		if (nArg >= 4 && pnLen != NULL)
			*pnLen = nLen2;
		if (nArg >= 5 && pnPageSkip != NULL)
			*pnPageSkip = nPageSkip2;
		return NOERR;
	}

	int SCRLWIN_GETVSCROLL_func(int idObj, int idMsg, int nArg,
			int *pnPos, int *pnMin, int *pnMax, int *pnLen, int *pnPageSkip)
	{
		int nPos2, nMin2, nMax2, nLen2, nPageSkip2;
		int idSbar;
		idSbar = OBJDATA(SCRLWIN, idObj).idScrlBarVert;
		MMI_SendMessage(idSbar, MM_GETSCROLL, 5,
						&nPos2,&nMin2,&nMax2,&nLen2,&nPageSkip2);
		if (nArg >= 1 && pnPos != NULL)
			*pnPos = nPos2;
		if (nArg >= 2 && pnMin != NULL)
			*pnMin = nMin2;
		if (nArg >= 3 && pnMax != NULL)
			*pnMax = nMax2;
		if (nArg >= 4 && pnLen != NULL)
			*pnLen = nLen2;
		if (nArg >= 5 && pnPageSkip != NULL)
			*pnPageSkip = nPageSkip2;
		return NOERR;
	}

	int SCRLWIN_SETHSCROLLRANGE_func(int idObj, int idMsg, int nArg,
		int dispLen, int containLen, int bRedraw)
	{
		int nPos, nMin, nMax, nLen, nPageSkip;
		MMI_SendMessage(idObj, MM_GETHSCROLL, 5,
						&nPos, &nMin, &nMax, &nLen, &nPageSkip);
		nPos -= nMin;
		nMin = dispLen-1;
		nMax = (dispLen > containLen ? dispLen-1 : containLen-1);
		nLen = dispLen;
		nPos = _min(nMin + nPos, nMax);
		MMI_SendMessage(idObj, MM_SETHSCROLL, 6, bRedraw,
						nPos, nMin, nMax, nLen, nPageSkip);
		return NOERR;
	}

	int SCRLWIN_SETVSCROLLRANGE_func(int idObj, int idMsg, int nArg,
		int dispLen, int containLen, int bRedraw)
	{
		int nPos, nMin, nMax, nLen, nPageSkip;
		MMI_SendMessage(idObj, MM_GETVSCROLL, 5,
						&nPos, &nMin, &nMax, &nLen, &nPageSkip);
		nPos -= nMin;
		nMin = dispLen-1;
		nMax = (dispLen > containLen ? dispLen-1 : containLen-1);
		nLen = dispLen;
		nPos = _min(nMin + nPos, nMax);
		MMI_SendMessage(idObj, MM_SETVSCROLL, 6, bRedraw,
						nPos, nMin, nMax, nLen, nPageSkip);
		return NOERR;
	}

/*--------------------------------------------------------*/
/*              ウィンドウ上かどうかを調べる              */
/*--------------------------------------------------------*/

	static int SCRLWIN_ONWIN_func(int idWin, int idMsg, int nArg, EVENT *pEv)
	{
		OBJECT *pWinObj ;
		HYPER  hyp ;
		pWinObj = TL_getObjectPtr(idWin) ;
	  /* 選択不能な部品は検索できない 	*/
		if ((pWinObj->flag & MS_UNSELECT)||
				(((SCRLWIN *)(pWinObj->data))->atr & MS_INACTIVEL40))
			return OBJECT_NOT_FOUND ;
	  /* アクティブになっているものはスレーブ検索をする */
		if (pWinObj->flag & MS_ACTOBJ)
			return MMI_SuperSendMessage(MJ_HYPER, idWin, idMsg, nArg, pEv) ;
	  /* オブジェクト内ならばIDを返す */
		hyp = *((HYPER *)(pWinObj->data)) ;
		MG_SizeBoxL40(&hyp, ENABLE) ;
		if (MMI_CheckInsideFrame(&(hyp.fr), (POINT *)(&(pEv->info))) < NOERR)
			return OUTSIDE ;
		return idWin ;
	}

/*--------------------------------------------------------*/
/*                  ウィンドウの UPDATE                   */
/*--------------------------------------------------------*/

	int SCRLWIN_UPDATE_func(int idObj, int idMsg, int nArg,
							 WINCLIP *pWinclip, int arg2)
	{
		if (nArg == 0)
		{
			WINCLIP *pWinclip2;
			FRAME frWin, frUser;
			frWin = OBJDATA(SCRLWIN, idObj).fr;
			getframe_user(&frWin, &frUser);
			frUser.lupx += frWin.lupx;
			frUser.lupy += frWin.lupy;
			frUser.rdwx = frUser.lupx + frUser.rdwx - 1;
			frUser.rdwy = frUser.lupy + frUser.rdwy - 1;
			pWinclip2 = WIN_getClipMemory(&frUser, NULL);
			MMI_SuperSendMessage(MJ_WINDOWL40, idObj, idMsg, 1, pWinclip2);
			WIN_freeClipMemory(pWinclip2);
		}
		else
		{
			MMI_SuperSendMessage(MJ_WINDOWL40, idObj, idMsg, nArg,
								 pWinclip, arg2);
		}
		return NOERR;
	}

/*--------------------------------------------------------*/
/*                   任意のデータの登録                   */
/*--------------------------------------------------------*/

	int	SCRLWIN_SETDATA_func(int idObj, int idMsg, int nArg, void *data)
	{
		OBJDATA(SCRLWIN, idObj).data = data;
		return NOERR;
	}
	
	int	SCRLWIN_GETDATA_func(int idObj, int idMsg, int nArg, void **data)
	{
		*data = OBJDATA(SCRLWIN, idObj).data;
		return NOERR;
	}

/*--------------------------------------------------------*/
/*                     クラスの初期化                     */
/*--------------------------------------------------------*/

	#define	METHODNUM	26

	int	(*SCRLWINmethods[METHODNUM])() = {
		SCRLWIN_NEW_func,
		SCRLWIN_SETHYPER_func,
		SCRLWIN_SETUSER_func,
		SCRLWIN_GETUSER_func,
		SCRLWIN_ERASE_func,
		SCRLWIN_WAKE_func,
		SCRLWIN_SLEEP_func,
		SCRLWIN_MOSON_func,
		SCRLWIN_SETEXEC_func,
		SCRLWIN_SETATR_func,
		SCRLWIN_GETATR_func,
		SCRLWIN_SETFRAME_func,
		SCRLWIN_GETFRAME_func,
		SCRLWIN_SETMSG_func,
		SCRLWIN_dummy_func,
		SCRLWIN_dummy_func,
		SCRLWIN_SETHSCROLL_func,
		SCRLWIN_SETVSCROLL_func,
		SCRLWIN_GETHSCROLL_func,
		SCRLWIN_GETVSCROLL_func,
		SCRLWIN_SETHSCROLLRANGE_func,
		SCRLWIN_SETVSCROLLRANGE_func,
		SCRLWIN_ONWIN_func,
		SCRLWIN_SETDATA_func,
		SCRLWIN_GETDATA_func,
		SCRLWIN_UPDATE_func
	};

	char	*SCRLWINmsgs[METHODNUM] = {
		MT_NEW,
		MT_SETHYPER,
		MT_SETUSER,
		MT_GETUSER,
		MT_ERASE,
		MT_WAKE,
		MT_SLEEP,
		MT_MOUSEON,
		MT_SETEXEC,
		MT_SETATR,
		MT_GETATR,
		MT_SETFRAME,
		MT_GETFRAME,
		MT_SETMSG,
		MT_HSCROLL,
		MT_VSCROLL,
		MT_SETHSCROLL,
		MT_SETVSCROLL,
		MT_GETHSCROLL,
		MT_GETVSCROLL,
		MT_SETHSCROLLRANGE,
		MT_SETVSCROLLRANGE,
		MT_ONPARTS,
		MT_SETDATA,
		MT_GETDATA,
		MT_UPDATE
	};

int MMI_initScrollWindow()
{
	MJ_SCRLWIN = MMI_AddType(MJ_WINDOWL40, METHODNUM, sizeof(SCRLWIN), 
							  SCRLWINmethods, SCRLWINmsgs);
	if (MJ_SCRLWIN < NOERR)
		return MJ_SCRLWIN;

	MM_SETUSER = TL_teachHash(MT_SETUSER) ;
	MM_GETUSER = TL_teachHash(MT_GETUSER) ;
	MM_SETEXEC = TL_teachHash(MT_SETEXEC) ;
	MM_SETMSG  = TL_teachHash(MT_SETMSG) ;

	MM_SETATR = TL_teachHash(MT_SETATR);
	MM_GETATR = TL_teachHash(MT_GETATR);
	MM_SETFRAME = TL_teachHash(MT_SETFRAME);
	MM_GETFRAME = TL_teachHash(MT_GETFRAME);
	MM_VSCROLL = TL_teachHash(MT_VSCROLL);
	MM_HSCROLL = TL_teachHash(MT_HSCROLL);
	MM_SETHSCROLL = TL_teachHash(MT_SETHSCROLL);
	MM_SETVSCROLL = TL_teachHash(MT_SETVSCROLL);
	MM_GETHSCROLL = TL_teachHash(MT_GETHSCROLL);
	MM_GETVSCROLL = TL_teachHash(MT_GETVSCROLL);
	MM_SETHSCROLLRANGE = TL_teachHash(MT_SETHSCROLLRANGE);
	MM_SETVSCROLLRANGE = TL_teachHash(MT_SETVSCROLLRANGE);
	MM_SETDATA = TL_teachHash(MT_SETDATA);
	MM_GETDATA = TL_teachHash(MT_GETDATA);

	SCRLWIN *skel;
	skel = (SCRLWIN *) ( TL_getObjectPtr(MJ_SCRLWIN)->data );
	skel->atr = MS_BTLEFTL40 | MS_EVMOSONL40 | MS_RESIZEL40;
	skel->fr.lupx = 0;
	skel->fr.lupy = 0;
	skel->fr.rdwx = 127;
	skel->fr.rdwy = 95;
	skel->clr.fr = 0;
	skel->clr.back = 7;
	skel->clr.ch = 0;
	skel->atrm = MS_FRAMEL40 | MS_BFRAMEL40;
	skel->save = NULL;
	skel->ve = 0;
	skel->se = 0;
	static FRAME org = { 0,0,0,0 };
	skel->org = org;
	static FRAME size = { 0,0,9999,9999 };
	skel->size = size;
	skel->ufunc = 0;
	skel->tmsg = NULL;
	return NOERR;
}

/* [end] */
