/*===========================================
          DolphMorph（ドルフモーフ）

      モーフィング＆変形アニメ作成ソフト

  モーフィングアルゴリズム: EAST 1994
  インターフェース作成:     松内 良介 1994
===========================================*/
#define	MODULE_IMSTORE
/*
	imstore.c
	
	静止画倉庫、動画倉庫の実現部

	static	SIMAGE	*SIMAGEnew(void)
	static	void	SIMAGEdelete(SIMAGE *si)

			int		imstore_getFrameNum(void)
			IMAGE	*imstore_getFrame(int idx)
			int 	imstore_getMarkNum(int side)
			IMAGE	*imstore_getImage(int idx)

	static	void	AdjustImageStoreWin(int side)

			int		init_imstore(void)
			void	end_imstore(void)

	static	void	calcImageListParm(STOREWIN *pw,
									  int *_xnum, int *_ylen, int *_ofsy,
									  int *_dispx, int *_dispy, int *_idx)
	static	void	setSBarImageList(STOREWIN *pw, int bRedraw);
	static	void	dispImageList(STOREWIN *pw)
	static	void	dispImageList_onlyBack(STOREWIN *pw)
	static	void	imstore_whichImage(int scrx, int scry, int *t, int *n,
									   FRAME *_fr)
			int		imstore_storeNewImage(int n, IMAGE *pi, int idx)
			void	imstore_deleteImage(int n, int idx)
	static	void	makeErrorMessage(char *buf, char *fname, int error)
	static	void	MOV_MAINHEAD_init(MOV_MAINHEAD *p)
	static	void	V00_HEAD_init(V00_HEAD *p)
	static	int		imstore_saveFrameStore_MOV(char *fname)
			void	imstore_saveFrameStoreAsMovieFile(void)
			int		imstore_checkSaveFrameStore(void);
			void	imstore_saveFrameStore(void)
			void	imstore_loadToStore(int side)
			int 	imstore_checkSaveMarkedImage(void)
			void	imstore_saveMarkedImage(void)
	static	void	imstore_WinUserMouseOn(int side, LIST *pli, EVENT *pev)

		●部品の呼び出し関数
			int		ImageStoreWinFunc(kobj, messId, argc, pev, trigger)
			int		ImageStoreSBarFunc(kobj, messId, argc, pev, trigger)
			int		ImageStoreEditDBtnFunc(kobj, messId, argc, pev, trigger)
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <file_dlg.h>
#include <dos.h>

#include <egb.h>
#include <wgb.h>
#include <ryosuke.h>
#include <usrlib.h>

#include "morph.h"
#include "guisub.h"
#include "fifo.h"
#include "image.h"
#include "wgbmac.h"
#include "desktop.h"
#include "points.h"
#include "alert.h"
#include "sub.h"

/*--------------------------------------------------------*/
/*                        部品ＩＤ                        */
/*--------------------------------------------------------*/

	int	idImageStoreWin[2] = -1 ;
	int	idImageStoreTitleDBtn[2] = -1 ;
	int	idImageStoreSBarV[2] = -1 ;
	int	idImageStoreTitleMsg[2] = -1 ;
	int	idImageStoreEditMenuDBtn[2] = -1 ;
	int	idImageStoreEditDBtn[2][3] = -1 ;
	int	idImageStoreEditMsg[2][3] = -1 ;

/*--------------------------------------------------------*/
/*                    モジュール内変数                    */
/*--------------------------------------------------------*/

  /* ウィンドウ上の各部品の配置情報 */
	static	FRAME	frAdjTitleDBtn = {1,1,-2,16};
	static	FRAME	frAdjSBarV = {-16,16,-1,-16};
		#define	EMENUHT	17
		#define	BTNW	34
		#define	BTNSKIP	(BTNW+2)
	static	FRAME	frAdjWinUser = {1,17,-17,-2-EMENUHT};
	static	FRAME	frAdjEditMenuDBtn = {1,-2-(EMENUHT-1),-17,-2};
	static	FRAME	frAdjEditDBtn[3] =
		{ { 4          , -2-(EMENUHT-2), 4+BTNW-1          , -3 },
		  { 4+BTNSKIP  , -2-(EMENUHT-2), 4+BTNW-1+BTNSKIP  , -3 },
		  { 4+BTNSKIP*2, -2-(EMENUHT-2), 4+BTNW-1+BTNSKIP*2, -3 } };

	typedef struct {
		IMAGE	*piOriginal;
		IMAGE	*piDisp;
	} SIMAGE;

	#define	IMWIDTH			64
	#define	IMHEIGHT		48
	#define	IMXMARGIN		5
	#define	IMYMARGIN		5
	#define	IMXSKIP			8
	#define	IMYSKIP			8
	#define	IMNAMEHEIGHT	14
	#define	IMXUNIT			(IMWIDTH + IMXSKIP)
	#define	IMYUNIT			(IMHEIGHT+IMNAMEHEIGHT+IMYSKIP)

	typedef struct {
		LIST	*plImage;
		int		ofsY;			/* 画像リスト中の表示位置 */
		int		nMarkedImage;
		int		idWin;
		int		idSBarV;
	} STOREWIN;

	static STOREWIN	swin[2] =
	{
		{ NULL, 0, -1 },
		{ NULL, 0, -1 }
	};

	int	SIMAGELISTsetData(LIST *pl, SIMAGE **psi)
		{ return list_setData(pl, psi); }
	int	SIMAGELISTinsertData(LIST *pl, SIMAGE **psi)
		{ return list_insertData(pl, psi); }
	int	SIMAGELISTgetData(LIST *pl, SIMAGE **psi)
		{ return list_getData(pl,psi); }

	static	void	setSBarImageList();

  /* カット／ペースト処理用変数 */
	IMAGE	*piPaste = NULL;

/*--------------------------------------------------------*/
/*                     画像リスト要素                     */
/*--------------------------------------------------------*/

	static	SIMAGE	*SIMAGEnew(void)
	{
		SIMAGE *si;
		if ((si = TL_calloc(1,sizeof(SIMAGE))) == NULL)
			return NULL;
		if ((si->piDisp = image_new(IMWIDTH/2, IMHEIGHT/2)) == NULL)
			{ TL_free(si); return NULL; }
		si->piOriginal = NULL;
		return si;
	}

	static	void	SIMAGEdelete(SIMAGE *si)
	{
		if (si->piDisp != NULL)
			image_delete(si->piDisp);
		if (si->piOriginal != NULL)
			image_delete(si->piOriginal);
		TL_free(si);
	}

/*--------------------------------------------------------*/
/*              外部のための動画倉庫アクセス              */
/*--------------------------------------------------------*/

	int	imstore_getFrameNum(void)
	{
		return list_getDataNum(swin[1].plImage);
	}

	IMAGE *imstore_getFrame(int idx)
	{
		SIMAGE *si;
		if (0<=idx && idx < list_getDataNum(swin[1].plImage))
		{
			list_moveTo(swin[1].plImage, idx);
			SIMAGELISTgetData(swin[1].plImage, &si);
			return si->piOriginal;
		}
		return NULL;
	}

	int imstore_getMarkNum(int side)
	{
		if (side == 0 || side == 1)
			return swin[side].nMarkedImage;
		else
			return -1;
	}

	IMAGE *imstore_getImage(int idx)
	{
		SIMAGE *si;
		if (0<=idx && idx < list_getDataNum(swin[0].plImage))
		{
			list_moveTo(swin[0].plImage, idx);
			SIMAGELISTgetData(swin[0].plImage, &si);
			return si->piOriginal;
		}
		return NULL;
	}

/*--------------------------------------------------------*/
/*              ウィンドウ上の各部品の再配置              */
/*--------------------------------------------------------*/

	static void AdjustImageStoreWin(int side)
	{
		RM_adjustFrame(idImageStoreTitleDBtn[side], idImageStoreWin[side],
					   &frAdjTitleDBtn);
		RM_adjustFrame(idImageStoreSBarV[side], idImageStoreWin[side],
					   &frAdjSBarV);
		RM_adjustFrame(idImageStoreEditMenuDBtn[side], idImageStoreWin[side],
					   &frAdjEditMenuDBtn);
		int i;
		for (i=0; i<3; i++)
		{
			RM_adjustFrame(idImageStoreEditDBtn[side][i],idImageStoreWin[side],
						   &frAdjEditDBtn[i]);
			RM_adjustFrame(idImageStoreEditMsg[side][i],idImageStoreWin[side],
						   &frAdjEditDBtn[i]);
		}
		RM_adjustWinUser(idImageStoreWin[side], &frAdjWinUser);
	}
	
/*--------------------------------------------------------*/
/*                モジュールの初期化／終了                */
/*--------------------------------------------------------*/

	int init_imstore(void)
	{
		int i;
		for (i=0; i<2; i++)
		{
			AdjustImageStoreWin(i);
			swin[i].plImage = list_new(sizeof(SIMAGE*));
			swin[i].idWin   = idImageStoreWin[i];
			swin[i].idSBarV = idImageStoreSBarV[i];
			setSBarImageList(&swin[i], FALSE);
		}
		return 0;
	}

	void end_imstore(void)
	{
		list_destroy(swin[0].plImage);
		list_destroy(swin[1].plImage);
	}

/*--------------------------------------------------------*/
/*            画像リストの各種パラメータの計算            */
/*--------------------------------------------------------*/

	static void calcImageListParm(STOREWIN *pw,
								  int *_xnum, int *_ylen, int *_ofsy,
								  int *_dispx, int *_dispy, int *_idx)
	{
		FRAME fr;
		RM_getWinUserFrame(pw->idWin, &fr);
	  /* 画像が横,縦にいくつ並ぶかを計算 */
		int xnum,ynum; /* 画像が横,縦に並ぶ個数 */
		xnum = (((fr.rdwx-fr.lupx+1)-IMXMARGIN*2)+IMXSKIP) / IMXUNIT;
		ynum = ((list_getDataNum(pw->plImage) + 1)+(xnum-1)) / xnum;
			// list_getDataNum + 1 としているのは、リスト末尾をマーク可能に
			// するため。
	  /* 画像リストをすべて表示した場合の縦の長さを計算 */
		int ylen;
		ylen = ynum*(IMHEIGHT+IMNAMEHEIGHT) + _max(0,ynum-1)*IMYSKIP
		       + IMYMARGIN*2;
	  /* 他のパラメータの計算 */
		int dispPosY;	 /* ユーザー領域上端がリスト内のどの位置(y)か */
		int startYCnt;	 /* リストの何段目から表示するか？ */
		int dispx,dispy; /* ユーザー領域内座標での、表示開始座標 */
		int idx;		 /* 表示を始める画像の番号 */
		dispPosY = RM_getScrollPos(pw->idSBarV) * 2;
		startYCnt = _max(0, dispPosY-IMYMARGIN) / IMYUNIT;
		dispx = fr.lupx + IMXMARGIN;
		dispy = fr.lupy + IMYMARGIN + IMYUNIT * startYCnt - dispPosY;
		idx = startYCnt * xnum;
	  /*  */
		if (_xnum != NULL)
			*_xnum = xnum;
		if (_ylen != NULL)
			*_ylen = ylen;
		if (_ofsy != NULL)
			*_ofsy = dispPosY;
		if (_dispx != NULL)
			*_dispx = dispx;
		if (_dispy != NULL)
			*_dispy = dispy;
		if (_idx != NULL)
			*_idx = idx;
	}

/*--------------------------------------------------------*/
/*                  スクロール範囲の設定                  */
/*--------------------------------------------------------*/

	static void setSBarImageList(STOREWIN *pw, int bRedraw)
	{
		FRAME fr;
		RM_getWinUserFrame(pw->idWin, &fr);
		int xnum,ylen;
		calcImageListParm(pw, &xnum, &ylen, &pw->ofsY,NULL,NULL,NULL);
		RM_setScrollRange(pw->idSBarV,(fr.rdwy-fr.lupy+1)/2,ylen/2, bRedraw);
	}

/*--------------------------------------------------------*/
/*                    画像リストの表示                    */
/*--------------------------------------------------------*/

	#define	DISP_NORMAL		0
	#define	DISP_ONLYBACK	1

	static void _dispImageList_sub(STOREWIN *pw, int mode)
	{
		MG_mosDisp(2);
		WINCLIP *pclStack;
		RM_setOriginZero();
		RM_setClipWinUser(pw->idWin, &pclStack);
		FRAME fr;
		RM_getWinUserFrame(pw->idWin, &fr);
		if (mode == DISP_NORMAL)
			WGB_BOXFILL(guiEgbPtr,fr.lupx,fr.lupy,fr.rdwx,fr.rdwy,WINBACK,0);
		int xnum;
		int dispx,dispy;	/* ユーザー領域内座標での、表示開始座標 */
		int idx;			/* 表示を始める画像の番号 */
		calcImageListParm(pw, &xnum,NULL,NULL,&dispx,&dispy,&idx);
	  /* 表示 */
		int j;
		for (;dispy<=fr.rdwy;dispy+=IMYUNIT)
			for (j=0; j < xnum; j++,idx++)
			{
				if (idx > list_getDataNum(pw->plImage))
					goto ENDDISP;
				if (idx < list_getDataNum(pw->plImage))
				{
					SIMAGE *si;
					list_moveTo(pw->plImage, idx);
					SIMAGELISTgetData(pw->plImage, &si);
					int wid,ht;
					image_getDispSize(si->piOriginal,
									  IMWIDTH,IMHEIGHT,&wid,&ht);
					int tx = dispx+IMXUNIT*j;
					image_disp(si->piDisp, tx,dispy,IMWIDTH,IMHEIGHT);
					if (mode == DISP_NORMAL)
					{
						if (idx == pw->nMarkedImage)
						{
							WGB_RBOXLINE(guiEgbPtr, tx-2,dispy-2,
										 wid+4,ht+4,BLACK,0);
							// WGB_RBOXLINE(guiEgbPtr,tx-1,dispy-1,
							//				wid+2,ht+2,BLACK,0);
						}
						char namebuf[30];
						sprintf(namebuf,"%d %dx%d",idx,
								si->piOriginal->virwid,si->piOriginal->virht);
						RM_putstring12(guiEgbPtr, dispx+IMXUNIT*j,
									   dispy+IMHEIGHT+IMNAMEHEIGHT-12, namebuf,
									   BLACK, 0);
					}
				}
				else /* idx == list_getDataNum(pw->plImage) */
				{
					int tx = dispx+IMXUNIT*j;
					if (mode == DISP_NORMAL)
					{
						if (idx == pw->nMarkedImage)
						{
							WGB_RBOXLINE(guiEgbPtr,tx-2,dispy-2,
										 IMWIDTH+4,IMHEIGHT+4, BLACK,0);
							// WGB_RBOXLINE(guiEgbPtr,tx-1,dispy-1,
							// 			 IMWIDTH+2,IMHEIGHT+2, BLACK,0);
						}
					}
				}
			}
	   ENDDISP:
		RM_resetClipWinUser(pclStack);
		RM_recoverOrigin();
		MG_mosDisp(3);
	}

	static void dispImageList(STOREWIN *pw)
	{
		_dispImageList_sub(pw, DISP_NORMAL);
	}
	
	static void dispImageList_onlyBack(STOREWIN *pw)
	{
		_dispImageList_sub(pw, DISP_ONLYBACK);
	}

/*--------------------------------------------------------*/
/*          ある座標がどの画像に対応するか調べる          */
/*--------------------------------------------------------*/

	static void imstore_whichImage(int scrx,int scry,int *t,int *n,FRAME *_fr)
	/* 返値 t:0=静止画倉庫 1=動画倉庫 -1=どのウィンドウでもない */
	/*      n:画像番号  (または 末尾番号 または -1)  */
	/*      fr:その座標の画像の表示枠 */
	{
		int nWin,nImage;
		STOREWIN *pw;
	  /* どのウィンドウ上にあるかをまず判断 */
		EVENT ev;
		ev.what = EVMOSDN;
		ev.shift = SLEFTBTN;
		((POINT*)&ev.info)->x = scrx;
		((POINT*)&ev.info)->y = scry;
		int id;
		id = MMI_SendMessage(idDesktopSelectiveHyper, MM_ONPARTS, 1, &ev);
		if (id == swin[0].idWin)
			nWin = 0;
		else if (id == swin[1].idWin)
			nWin = 1;
		else
			goto NOWHERE;
		pw = &swin[nWin];
	  /* 効率よく位置を調べるための各種パラメータを計算 */
		FRAME fr;
		RM_getWinUserFrame(pw->idWin, &fr);
		int xnum;
		int dispx,dispy; /* 表示開始座標(原点は画面左上) */
		int idx;		 /* 表示を始める画像の番号 */
		calcImageListParm(pw, &xnum,NULL,NULL,&dispx,&dispy,&idx);
	  /* 位置を調べる */
		if (scry < fr.lupy || fr.rdwy < scry)
			goto NOWHERE;
		int j;
		for (; dispy<=fr.rdwy; dispy+=IMYUNIT)
			for (j=0; j < xnum; j++,idx++)
			{
				if (idx > list_getDataNum(pw->plImage))
					goto INUSER;
				int wid,ht;
				if (idx < list_getDataNum(pw->plImage))
				{
					SIMAGE *si;
					list_moveTo(pw->plImage, idx);
					SIMAGELISTgetData(pw->plImage, &si);
					image_getDispSize(si->piOriginal,
									  IMWIDTH,IMHEIGHT, &wid,&ht);
				}
				else  /* idx == list_getDataNum */
					wid = IMWIDTH, ht = IMHEIGHT;
				int tx = dispx + IMXUNIT * j;
				if (tx <= scrx && scrx < tx+wid &&
					dispy <= scry && scry < dispy+ht)
				{
					nImage = idx;
					if (_fr != NULL)
					{
						_fr->lupx = tx;       _fr->lupy = dispy;
						_fr->rdwx = tx+wid-1; _fr->rdwy = dispy+ht-1;
					}
					goto ENDSRCH;
				}
			}
	   INUSER:;
		*t = nWin;
		*n = -1;
		return;
	   NOWHERE:;
		*t = -1;
		*n = 0;
		return;
	   ENDSRCH:;
		*t = nWin;
		*n = nImage;
		return;
	}

/*--------------------------------------------------------*/
/*                 倉庫へ新たな画像を登録                 */
/*--------------------------------------------------------*/

	int imstore_storeNewImage(int side, IMAGE *pi, int idx)
	// side:0=静止画倉庫  1=動画倉庫
	// idx: -1: マーク位置または終端に挿入、
	//      >=0: その位置に挿入
	{
		static char alertTitle[] = "倉庫へ画像を登録";
		STOREWIN *pw;
		pw = &swin[side];
		SIMAGE *si;
		if ((si = SIMAGEnew()) == NULL)
			return -1;	// ★警告表示は上位処理で行う
		si->piOriginal = pi;
		image_zoomdown(si->piDisp, si->piOriginal);
	  /* 適切な位置にリストポインタを移動 */
		int datnum,inspos;
		datnum = list_getDataNum(pw->plImage);
		inspos = (idx < 0 ?
					(pw->nMarkedImage < 0 ? 
					   datnum : _min(pw->nMarkedImage, datnum)) :
				    _min(idx, datnum));
		list_moveTo(pw->plImage, inspos);
	  /* 挿入 */
		if (SIMAGELISTinsertData(pw->plImage, &si) != 0)
			return -1;	// 警告表示は上位処理で行う
		if (pw->nMarkedImage >= inspos)
			pw->nMarkedImage++;
	  /* スクロールバー、ウィンドウの更新 */
		setSBarImageList(pw, TRUE);
		dispImageList(pw);
		return 0;
	}

/*--------------------------------------------------------*/
/*                   倉庫から画像を削除                   */
/*--------------------------------------------------------*/

	void imstore_deleteImage(int side, int idx)
	{
		STOREWIN *pw;
		pw = &swin[side];
		if (idx < 0 || list_getDataNum(pw->plImage) <= idx)
			return;
		SIMAGE *si;
		list_moveTo(pw->plImage, idx);
		SIMAGELISTgetData(pw->plImage, &si);
		list_deleteData(pw->plImage);
		SIMAGEdelete(si);
		/*
			if (pw->nMarkedImage == idx)
				pw->nMarkedImage = -1;
			↑こうするのとしないのと、どっちがいいのかなあ？
		*/
		setSBarImageList(pw, TRUE);
		dispImageList(pw);
	}

/*--------------------------------------------------------*/
/*          ファイル関係のエラーメッセージの作成          */
/*--------------------------------------------------------*/

	static void makeErrorMessage(char *buf, char *fname, int error)
	{
		if (error == ERROR_CANNOTOPEN)
			sprintf(buf, "ファイル %s がオープンできません", fname);
		else if (error == ERROR_NOMEMORY)
			sprintf(buf, "メモリの残り容量が不足しています");
		else if (error == ERROR_DISKFULL)
			sprintf(buf, "ディスクの残り容量が不足しています");
		else if (error == ERROR_INVALIDFORMAT)
			sprintf(buf, "画像ファイル形式が違います");
		else if (error == ERROR_INVALIDPIXELSIZE)
			sprintf(buf, "画像の色数が３万色ではありません");
		else if (error != 0)
			sprintf(buf, "処理を中断しました");
		else
			buf[0] = 0;
	}

/*--------------------------------------------------------*/
/*                    倉庫の画像の保存                    */
/*--------------------------------------------------------*/

	typedef struct {
		char	id[4];			// +  0 "MOV2"
		int		pixelsize;		// +  4 bit/pixel ここでは16が入る
		int		dataSize;		// +  8 total data size (本ヘッダは含まない)
		int		frameNum;		// + 12 total frame
		int		scrWidth;		// + 16 画面  横の長さ（320ドッド）
		int		scrHeight;		// + 20 画面  縦の長さ（240ドット）
		int		raster;			// + 24 raster 640が入る
		int		wait;			// + 28 メインウエイト
		short	dispx0;			// + 32 表示領域 x0
		short	dispy0;			// + 34 表示領域 y0
		short	dispx1;			// + 36 表示領域 x1
		short	dispy1;			// + 38 表示領域 y1
		char	fmb_file[8];	// + 40 FMBファイルネーム
		char	fmb_ch[8];		// + 48 FMB ch割り当て(0〜5ch) ＋２Byteの空き
		char	pmb_file[8];	// + 56 PMB  ファイルネーム
		char	pmb_ch[8];		// + 64 PMB  ch割り当て(64〜71ch)
		char	snd_name[8][8];	// + 72 SND  ch0〜ch7  ファイルネーム
		char	panpot[14];		// +136 ch0〜5,ch64〜71のパンポット(1Byte/ch)
								// ( -64:左 〜 00:中央 〜 63:右 )
		char	timingMode;		/* +150	タイミングモード ( ビット０がモード
										識別になっており 0:ウエイトして表示
										1:表示してウエイト) */
		char	pudding[256-151];
	} MOV_MAINHEAD;

	typedef struct {
		int		page;		// + 0  ページ
		int		dataSize;	// + 4  frame data size (本ヘッダは含まない)
		char	pudding[4];	// + 8  リザーブ
		short	wait;		// +12  wait
		short	loop;		// +14  loop 情報 0:none 1〜:start&回数 0xffff:end
		char	sound[4][4];  // FMB & PMB データ0〜2, データ3 / SNDデータ
	} MOV_FRAMEHEAD;

	typedef struct {
		char	id[4];		// +  0  "VD00"
		int		dataSize;	// +  4  total data size (本ヘッダは含まない)
		int		frameNum;	// +  8  total frame
		unsigned int format; // + 12  データ形式番号（0x80008000が入る）
		int		width;		// + 16  画面  横の長さ
		int		height;		// + 20  画面  縦の長さ
		int		wait;		// + 24  ウエイト(4〜8)
		char	pudding[256-28];
	} V00_HEAD;

	static void MOV_MAINHEAD_init(MOV_MAINHEAD *p)
	{
		memset(p, 0, sizeof(MOV_MAINHEAD));
		memcpy(p->id, "MOV2", 4);
		p->pixelsize = 16;
		p->scrWidth = 320;
		p->scrHeight = 240;
		p->raster = 640;
	}
	
	static void V00_HEAD_init(V00_HEAD *p)
	{
		memset(p, 0, sizeof(V00_HEAD));
		memcpy(p->id, "VD00", 4);
		p->format = 0x80008000UL;
		p->wait = 4;
	}

	static int imstore_saveFrameStore_MOV(char *fname)
	{
#if 0
		static char alertTitle[] = "MOV ファイルの作成";
		FILE *fp;
		int i;
	  /* フレーム数を求める */
		int framenum;
		framenum = list_getDataNum(swin[1].plImage);
		if (framenum <= 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に画像が１つもないので、"
							"動画ファイルが作成できません");
			return -1;
		}
	  /* 画像の縦・横の大きさ、画像一枚のバイト数を求める */
		list_top(swin[1].plImage);
		SIMAGE *psi;
		SIMAGELISTgetData(swin[1].plImage, &psi);
		int width,height,frameSize;
		width  = psi->piOriginal->width;
		height = psi->piOriginal->height;
		frameSize = width * height * 2;
		if (frameSize == 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に登録されている画像が"
							 "小さすぎるので、動画ファイルが作成できません");
			return -1;
		}
	  /* ファイルのオープン、メインヘッダの書き出し */
		if ((fp = fopen(fname, "wb")) == NULL)
			return -1;
		MOV_MAINHEAD head;
		MOV_MAINHEAD_init(&head);
		head.dataSize = (sizeof(MOV_FRAMEHEAD) + frameSize) * framenum;
		head.frameNum = framenum;
		head.dispx0 = 0;
		head.dispy0 = 0;
		head.dispx1 = width;
		head.dispy1 = height;
		head.wait = 5;
		fwrite(&head, sizeof(head), 1, fp);
		// printf("MAINHEAD = %d\n", sizeof(head));
	  /* 各フレームの書き出し */
		for (i=0; i<framenum; i++)
		{
			list_moveTo(swin[1].plImage, i);
			SIMAGELISTgetData(swin[1].plImage, &psi);
			IMAGE *pi;
			pi = psi->piOriginal;
			if (width != pi->width || height != pi->height)
			{
				dispAlertMessage(alertTitle,
					"動画倉庫に、サイズが異なる画像が入っているので、"
					"MOVファイルが作成できません");
				break;
			}
			MOV_FRAMEHEAD frhead;
			memset(&frhead, 0, sizeof(MOV_FRAMEHEAD));
			frhead.page = i;
			frhead.dataSize = frameSize; 
			fwrite(&frhead,sizeof(frhead),1,fp);
			fwrite(pi->image,1,frameSize,fp);
			// printf("FRAMEHEAD = %d\n", sizeof(frhead));
		}
		fclose(fp);
		return 0;
#else
		static char alertTitle[] = "V00 ファイルの作成";
		FILE *fp;
		int i;
	  /* フレーム数を求める */
		int framenum;
		framenum = list_getDataNum(swin[1].plImage);
		if (framenum <= 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に画像が１つもないので、"
							"動画ファイルが作成できません");
			return -1;
		}
	  /* 画像の縦・横の大きさ、画像一枚のバイト数を求める */
		list_top(swin[1].plImage);
		SIMAGE *psi;
		SIMAGELISTgetData(swin[1].plImage, &psi);
		int width,height,frameSize;
		width  = psi->piOriginal->width;
		height = psi->piOriginal->height;
		frameSize = width * height * 2;
		if (frameSize == 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に登録されている画像が"
							 "小さすぎるので、動画ファイルが作成できません");
			return -1;
		}
	  /* ファイルのオープン、メインヘッダの書き出し */
		if ((fp = fopen(fname, "wb")) == NULL)
			return -1;
		V00_HEAD head;
		V00_HEAD_init(&head);
		head.dataSize = frameSize * framenum;
		head.frameNum = framenum;
		head.width = width;
		head.height = height;
		head.wait = 7;
		fwrite(&head, sizeof(head), 1, fp);
		// printf("MAINHEAD = %d\n", sizeof(head));
	  /* 各フレームの書き出し */
		for (i=0; i<framenum; i++)
		{
			list_moveTo(swin[1].plImage, i);
			SIMAGELISTgetData(swin[1].plImage, &psi);
			IMAGE *pi;
			pi = psi->piOriginal;
			if (width != pi->width || height != pi->height)
			{
				dispAlertMessage(alertTitle,
					"動画倉庫に、サイズが異なる画像が入っているので、"
					"MOVファイルが作成できません");
				break;
			}
			fwrite(pi->image,1,frameSize,fp);
		}
		fclose(fp);
		return 0;
#endif
	}


	void imstore_saveFrameStoreAsMovieFile(void)
	{
		static char alertTitle[] = "動画ファイル保存（動画倉庫）";
		int ret;
		int fileNum,i;
		char pathbuf[100]; int fileAtr;
		if (list_getDataNum(swin[1].plImage) <= 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に画像が１つもないので、"
							"動画ファイルが作成できません");
			return;
		}
		ret = RM_callSimpleFDG(idDesktopAlertHyper, idDesktopSelectiveHyper,
							   "V00 保存", "保存", "取消", "*.V00",
							   FDG_FILEONLY|FDG_TEXT, pathbuf);
		if (ret != 0)
			return;	// 「取消」
		char pathbuf2[100];
		strcpy(pathbuf2,pathbuf);
		trans_fname_ext(pathbuf, pathbuf2, "V00");
		if (fexist(pathbuf))
		{
			char strbuf[200];
			sprintf(strbuf, "ファイル %s がすでに存在しています。"
					"上書きしますか？", pathbuf);
			if (dispCheckMessage(alertTitle, strbuf, "上書き") != 0)
				return;
		}
		int moscsr;
		MG_PushPtr(MOSICON_WAIT, &moscsr);
		imstore_saveFrameStore_MOV(pathbuf);
		MG_PopPtr(moscsr);
	}

	int imstore_checkSaveFrameStore(void)
	{
		if (list_getDataNum(swin[1].plImage) <= 0)
			return -1;
		else
			return 0;
	}

	void imstore_saveFrameStore(void)
	{
		static char alertTitle[] = "動画倉庫を番号付けでTIFF化";
		int ret;
		int fileNum,i;
		char pathbuf[100]; int fileAtr;
		if (list_getDataNum(swin[1].plImage) <= 0)
		{
			dispAlertMessage(alertTitle, "動画倉庫に画像が１つもないので、"
							 "TIFF化することができません");
			return;
		}
		ret = RM_callSimpleFDG(idDesktopAlertHyper, idDesktopSelectiveHyper,
							   "動画倉庫TIFF化", "保存", "取消", "*.TIF",
							   FDG_FILEONLY|FDG_TEXT, pathbuf);
		if (ret != 0)
			return;	// 「取消」
		char	drive[_MAX_DRIVE+2],dir[_MAX_DIR+2],basename[_MAX_FNAME+2],
				ext[_MAX_EXT+2];
		_splitpath(pathbuf, drive, dir, basename, ext);
		SIMAGE *si;
		int framenum = list_getDataNum(swin[1].plImage);
		for (i=0; i<framenum; i++)
		{
			list_moveTo(swin[1].plImage, i);
			SIMAGELISTgetData(swin[1].plImage, &si);
			if (si->piOriginal == NULL)
				continue;
			char buf1[_MAX_FNAME+2],buf2[20];
			strncpy(buf1, basename, 5);
			sprintf(buf2, "%s%03d", buf1, i);
			_makepath(pathbuf, drive, dir, buf2, "TIF");
			if (fexist(pathbuf))
			{
				char strbuf[200];
				sprintf(strbuf, "ファイル %s がすでに存在しています。"
						"上書きしますか？", pathbuf);
				if (dispCheckMessage(alertTitle, strbuf, "上書き") != 0)
					continue;
			}
			int ret;
			int moscsr;
			MG_PushPtr(MOSICON_WAIT, &moscsr);
			ret = image_saveTIFF(si->piOriginal, pathbuf);
			MG_PopPtr(moscsr);
			if (ret != 0)
			{
				char strbuf[200];
				makeErrorMessage(strbuf, pathbuf, ret);
				dispAlertMessage(alertTitle, strbuf);
				break;
			}
		}
	}

/*--------------------------------------------------------*/
/*                  倉庫への画像のロード                  */
/*--------------------------------------------------------*/

	void imstore_loadToStore(int side)
	{
		static char alertTitle[] = "倉庫へ画像を読込";
		int ret;
		int fileNum,i;
		char pathbuf[100]; int fileAtr;
		ret = RM_callSimpleFDG(idDesktopAlertHyper, idDesktopSelectiveHyper,
							   (side==0 ? "静止画倉庫読込" : "動画倉庫読込"),
							   "読込", "取消", "*.TIF",
							   FDG_FILEONLY|FDG_MSLCT, pathbuf);
		if (ret != 0)
			return;	// 「取消」
		fileNum = *(int*)pathbuf;
		for (i=0; i<fileNum; i++)
		{
			int ret;
			IMAGE *pi;
			FDG_GetPathName(pathbuf, &fileAtr, i);
			int moscsr;
			MG_PushPtr(MOSICON_WAIT, &moscsr);
			ret = image_createloadTIFF(&pi, pathbuf);
			MG_PopPtr(moscsr);
			if (ret != 0)
			{
				static char str[200];
				sprintf(str, "ファイル %s ", pathbuf);
				if (ret == ERROR_CANNOTOPEN)
				{
					strcat(str,"が見つかりません");
					dispAlertMessage(alertTitle,str);
				}
				else if (ret == ERROR_INVALIDFORMAT)
				{
					strcat(str,	"は TOWNS 標準 TIFF 形式でないので"
								"読み込めません");
					dispAlertMessage(alertTitle,str);
				}
				else if (ret == ERROR_INVALIDPIXELSIZE)
				{
					strcat(str,	"は３万色画像ではないので"
								"読み込めません");
					dispAlertMessage(alertTitle,str);
				}
				else
				{
					alert_noMemory(alertTitle);
					break;
				}
				continue;
			}
			if (imstore_storeNewImage(side, pi, -1) != 0)
			{
				alert_noMemory(alertTitle);
				break;
			}
		}
	}

/*--------------------------------------------------------*/
/*                 １枚のマーク画像を保存                 */
/*--------------------------------------------------------*/

	int	imstore_checkSaveMarkedImage(void)
	{
		int flag[2];
		flag[0] = flag[1] = FALSE;
		if (0 <= swin[0].nMarkedImage &&
		    swin[0].nMarkedImage < list_getDataNum(swin[0].plImage))
			flag[0] = TRUE;
		if (0 <= swin[1].nMarkedImage &&
			swin[1].nMarkedImage < list_getDataNum(swin[1].plImage))
			flag[1] = TRUE;
		if (flag[0]==TRUE && flag[1]==TRUE)
			return -1;
		if (flag[0] == FALSE && flag[1] == FALSE)
			return -1;
		return 0;
	}

	void imstore_saveMarkedImage(void)
	{
		static char alertTitle[] = "マーク画像を保存";
		int ret;
		int fileNum,i;
		char pathbuf[100]; int fileAtr;
		int flag[2];
		SIMAGE *psi;
	  /* どの画像を保存するのかを決める */
		flag[0] = flag[1] = FALSE;
		if (0 <= swin[0].nMarkedImage && swin[0].nMarkedImage < list_getDataNum(swin[0].plImage))
			flag[0] = TRUE;
		if (0 <= swin[1].nMarkedImage && swin[1].nMarkedImage < list_getDataNum(swin[1].plImage))
			flag[1] = TRUE;
		if (flag[0]==TRUE && flag[1]==TRUE)
		{
			dispAlertMessage(alertTitle, "静止画倉庫、動画倉庫の両方で"
								"画像がマークされているので保存できません"
								"（どちらか一方のマークを解除してください）");
			return;
		}
		if (flag[0] == FALSE && flag[1] == FALSE)
		{
			dispAlertMessage(alertTitle, "静止画倉庫、動画倉庫どちらでも"
								"画像がマークされていないので、"
								"画像が保存できません");
			return;
		}
		LIST *pli;
		int idx;
		if (flag[0])
			pli = swin[0].plImage, idx = swin[0].nMarkedImage;
		else
			pli = swin[1].plImage, idx = swin[1].nMarkedImage;
		list_moveTo(pli,idx);
		SIMAGELISTgetData(pli, &psi);
		IMAGE *pi;
		pi = psi->piOriginal;
	  /* ファイルダイアログを呼び出してファイル名を取得 */
		ret = RM_callSimpleFDG(idDesktopAlertHyper, idDesktopSelectiveHyper,
							   "マーク画像保存", "保存", "取消", "*.TIF",
							   FDG_FILEONLY|FDG_TEXT, pathbuf);
		if (ret != 0)
			return;	// 「取消」
	  /* 保存 */
		char pathbuf2[100];
		strcpy(pathbuf2,pathbuf);
		trans_fname_ext(pathbuf, pathbuf2, "TIF");
		if (fexist(pathbuf))
		{
			char strbuf[200];
			sprintf(strbuf, "ファイル %s がすでに存在しています。"
					"上書きしますか？", pathbuf);
			if (dispCheckMessage(alertTitle, strbuf, "上書き") != 0)
				return;
		}
		int moscsr;
		MG_PushPtr(MOSICON_WAIT, &moscsr);
		ret = image_saveTIFF(pi, pathbuf);
		MG_PopPtr(moscsr);
		if (ret != 0)
		{
			char strbuf[200];
			makeErrorMessage(strbuf, pathbuf, ret);
			dispAlertMessage(alertTitle, strbuf);
		}
	}

/*--------------------------------------------------------*/
/*                   部品の呼び出し関数                   */
/*--------------------------------------------------------*/

	#define SET_MOSCSR(type)		\
		MG_mosDisp(2);				\
		MG_PushPtr(type, &moscsr);	\
		MG_mosDisp(3);
	#define RECOVER_MOSCSR			\
		MG_mosDisp(2);				\
		MG_PopPtr(moscsr);			\
		MG_mosDisp(3);

	static void imstore_WinUserMouseOn(int side, LIST *pli, EVENT *pev)
	/* 静止画倉庫,動画倉庫のユーザー領域でマウスクリックされたときの処理 */
	{
		static char alertTitle[] = "倉庫の画像の移動・複製";
		int msx,msy,t,n;
		FRAME fr;
		msx = ((POINT*)&pev->info)->x;
		msy = ((POINT*)&pev->info)->y;
		imstore_whichImage(msx,msy, &t,&n, &fr);
		if (t == side && n >= 0)
		{
			int moscsr;
			EVENT *pev;
			SET_MOSCSR(MOSICON_FINGER)
		  /* その場でボタンが放されるか、あるいはドラッグされるかの判断*/
			do {
			  do {
				MMI_iosense() ;
			  } while ((MMI_GetEvnt(EVMOSDRAG|EVMOSUP, &pev)) < NOERR);
			} while ((pev->shift & SLEFTBTN)==0);
			RECOVER_MOSCSR
		  /* ドラッグされた場合、画像そのものを移動 */
			if (pev->what == EVMOSDRAG && n < list_getDataNum(pli))
			{
				SET_MOSCSR(MOSICON_DRAG)
				RM_setClipVisibleAllScr();
				RM_setOriginZero();
				MG_DragFrame(&fr, pev);
				RECOVER_MOSCSR
				int win,picn;
				imstore_whichImage((fr.lupx+fr.rdwx)/2,(fr.lupy+fr.rdwy)/2,
								   &win, &picn, NULL);
				if (win >= 0)
				{
					int counterSide = (side == 0 ? 1 : 0);
					if (win == counterSide)
					{
						SIMAGE *si;
						IMAGE *piNew;
						list_moveTo(pli, n);
						SIMAGELISTgetData(pli, &si);
						if ((piNew = image_copy(si->piOriginal)) == NULL)
							alert_noMemory(alertTitle);
						else
						{
							if (imstore_storeNewImage
								  (counterSide, piNew, (picn >= 0 ? picn : -1))
								!= 0)
								alert_noMemory(alertTitle);
						}
					}
				}
				else
				{
					int side,f;
					points_whereis((fr.lupx+fr.rdwx)/2, (fr.lupy+fr.rdwy)/2,
								   &side, &f);
					//printf("imstore_WinUserMouseOn: (side,f,n,listNum)="
					//		"%d,%d,%d,%d\n",
					//		side,f,n, list_getDataNum(pli));
					if (side >= 0)
					{
						SIMAGE *si;
						IMAGE *piNew;
						list_moveTo(pli, n);
						SIMAGELISTgetData(pli, &si);
						if ((piNew = image_copy(si->piOriginal)) == NULL)
							alert_noMemory(alertTitle);
						else
							points_storeImage(side, piNew);
					}
				}
				RM_recoverOrigin();
				RM_recoverClipVisible();
			}
		  /* その場でボタンが放された場合、マーク指定 */
			else if (pev->what == EVMOSUP)
			{
				if (swin[side].nMarkedImage != n)
					swin[side].nMarkedImage = n;
				else
					swin[side].nMarkedImage = -1;
			}
		}
		desktop_checkActivity();
	}

	/*	initDataZIMSTORE:idImageStoreWin[0]:MJ_WINDOWL40の呼び出し関数	*/
	/*	initDataZIMSTORE:idImageStoreWin[1]:MJ_WINDOWL40の呼び出し関数	*/
	int	ImageStoreWinFunc(kobj, messId, argc, pev, trigger)
	int		kobj ;
	int		messId ;
	int		argc ;
	EVENT	*pev ;
	int		trigger ;
	{
		int side;
		if (kobj == idImageStoreWin[0])
			side = 0;
		else
			side = 1;
		if (messId == MM_SHOW)
			dispImageList(&swin[side]);
		else if (messId == MM_UPDATE)
		{
			AdjustImageStoreWin(side);
			setSBarImageList(&swin[side], TRUE);
		}
		else if (messId == MM_MOVE)
		{
			RM_roundFramePosition(swin[side].idWin, 2,2);
			dispImageList(&swin[side]);
		}
		else if (messId == MM_MOUSEON)
		{
			imstore_WinUserMouseOn(side, swin[side].plImage, pev);
			dispImageList(&swin[side]);
			// printf("ImageStoreWinFunc: %d %d\n",t,n);
		}
		return NOERR ;
	}

	/*	initDataZIMSTORE:idImageStoreSBarV[0]:MJ_SCRLL40の呼び出し関数	*/
	/*	initDataZIMSTORE:idImageStoreSBarV[1]:MJ_SCRLL40の呼び出し関数	*/
	int	ImageStoreSBarFunc(kobj, messId, argc, pev, trigger)
	int		kobj ;
	int		messId ;
	int		argc ;
	EVENT	*pev ;
	int		trigger ;
	{
		int side;
		if (kobj == idImageStoreSBarV[0])
			side = 0;
		else
			side = 1;
	#if 0
		MG_mosDisp(2);
		int pos;
		pos = RM_getScrollPos(kobj) * 2;
		FRAME fr;
		RM_getWinUserFrame(swin[side].idWin, &fr);
		WIN_scrollWindow(swin[side].idWin, &fr, 0, swin[side].ofsY-pos);
		swin[side].ofsY = pos;
		dispImageList_onlyBack(&swin[side]);
		MG_mosDisp(3);
	#else
		dispImageList(&swin[side]);
	#endif
		return NOERR ;
	}

	/*	initDataZIMSTORE:idImageStoreEditDBtn[0][0]:MJ_DBUTTONL40	*/
	/*	initDataZIMSTORE:idImageStoreEditDBtn[0][1]:MJ_DBUTTONL40	*/
	/*	initDataZIMSTORE:idImageStoreEditDBtn[0][2]:MJ_DBUTTONL40	*/
	/*	initDataZIMSTORE:idImageStoreEditDBtn[1][0]:MJ_DBUTTONL40	*/
	/*	initDataZIMSTORE:idImageStoreEditDBtn[1][1]:MJ_DBUTTONL40	*/
	/*	initDataZIMSTORE:idImageStoreEditDBtn[1][2]:MJ_DBUTTONL40	*/
	int	ImageStoreEditDBtnFunc(kobj, messId, argc, pev, trigger)
	int		kobj ;
	int		messId ;
	int		argc ;
	EVENT	*pev ;
	int		trigger ;
	{
		int side,i;
		side = 0;
		for (i=0; i<3; i++)
			if (kobj == idImageStoreEditDBtn[1][i])
				side = 1;
		int datnum = list_getDataNum(swin[side].plImage);
		int mark = swin[side].nMarkedImage;
		if (kobj == idImageStoreEditDBtn[side][0] ||
			kobj == idImageStoreEditDBtn[side][1])
		{
			static char *alertTitle;
			if (side == 0)
				alertTitle = "静止画倉庫の画像を cut / copy";
			else
				alertTitle = "動画倉庫の画像を cut / copy";
			if (0 <= mark && mark < datnum)
			{
				SIMAGE *psi;
				IMAGE *pi;
				list_moveTo(swin[side].plImage, mark);
				SIMAGELISTgetData(swin[side].plImage, &psi);
				if ((pi = image_copy(psi->piOriginal)) != NULL)
				{
					if (kobj == idImageStoreEditDBtn[side][0])
						imstore_deleteImage(side, mark);
					if (piPaste != NULL)
						image_delete(piPaste);
					piPaste = pi;
				}
				else
					alert_noMemory(alertTitle);
			}
		}
		else if (kobj == idImageStoreEditDBtn[side][2])
		{
			static char *alertTitle;
			if (side == 0)
				alertTitle = "静止画倉庫へ画像を paste";
			else
				alertTitle = "動画倉庫へ画像を paste";
			if (piPaste != NULL)
			{
				IMAGE *pi;
				if ((pi = image_copy(piPaste)) != NULL)
				{
					if (imstore_storeNewImage(side,pi,(mark>=0? mark:-1)) != 0)
						alert_noMemory(alertTitle);
				}
				else
					alert_noMemory(alertTitle);
			}
		}
		desktop_checkActivity();
		return NOERR ;
	}

