home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 3
/
FREEWARE.BIN
/
towns_os
/
fildlg22
/
filedlg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1980-01-02
|
40KB
|
1,585 lines
/*
* filedlg.c
* ファイルダイアログ表示ルーチン
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include "button.h"
#include "display.h"
#include "mouse.h"
#include "msdos.h"
#include "setup.h"
#include "filedlg.h"
#define GLOBAL
#define LOCAL
#define TRUE 1
#define FALSE 0
/*--------------------------------------*/
/* 型定義 */
/*--------------------------------------*/
/* Boolean型定義 */
typedef int Bool_t;
/* ファイル情報構造体の定義 */
typedef struct fileInfo {
struct fileInfo *next; /* 次要素 */
struct fileInfo *prev; /* 前要素 */
char name[13];
char attr;
unsigned short date;
unsigned short time;
long size;
int select;
} fileInfo_t;
/*--------------------------------------*/
/* 定数定義 */
/*--------------------------------------*/
/* -------- ファイル関連 --------*/
#define PathLen 80
#define FnameLen 12
#define DriveQ 17
/* -------- イベントID --------*/
/* イベントIDはlong型であり,
* short型のmajorイベントIDと,short型のminorイベントIDからなる.
* majorイベントIDはイベントを区別し,
* minorイベントIDは各イベントの詳細を識別する.
*/
/* majorIDとminorIDを取り出すマクロ */
#define major(id) (id & 0xffff)
#define minor(id) ((id >> 16) & 0xffff)
/* majorイベントID */
#define BtnDriveLeft 0
#define BtnDriveCenter 1
#define BtnDriveRight 2
#define BtnParent 3
#define BtnScrollUp 4
#define BtnScrollDown 5
#define BtnOk 6
#define BtnCancel 7
#define MaxButtons 8
#define FileList 9
/* -------- エラーコード --------*/
#define NoAvailableMemory 1
#define IllegalDirection 2
/* -------- 画面関連定数 --------*/
/* 単位はピクセル */
int FD_CharWidth = 8; /* 1バイト文字の横方向ドット数 */
int FD_CharHeight = 16; /* 1バイト文字の縦方向ドット数 */
/* -------- デフォルトダイアログボックス --------*/
/*
* デフォルトダイアログボックスの表示位置等の定義情報
* 本ダイアログボックスは640×480ピクセルの画面を想定している.
*/
int FD_DialogPosX = 240; /* ダイアログボックス左上x座標 */
int FD_DialogPosY = 40; /* ダイアログボックス左上y座標 */
int FD_DriveBtnWidth = 32;
/* ドライブ中央ボタンのドット数 */
/* = strlen(FD_DriveName[0]) * FD_CharWidth + 8 * 2 */
int FD_ParentBtnWidth = 32;
/* 親ディレクトリボタンのドット数 */
/* = strlen(FD_ParentBtnName) * FD_CharWidth + 8 * 2 */
int FD_ScrollBtnWidth = 32;
/* スクロールボタンのドット数 */
/* = strlen(FD_ScrollBtnName[0]) * FD_CharWidth + 8 * 2 */
int FD_OkNgBtnWidth = 48;
/* 確認/取消ボタンのドット数 */
/* = strlen(FD_OkNgBtnName[0]) * FD_CharWidth + 8 * 2 */
int FD_ButtonHeight = 32;
/* ボタンの縦方向ドット数 */
/* = FD_CharHeight + 8 * 2 */
int FD_LeftMargin = 8; /* ドライブ左ボタンまでのオフセット */
int FD_TopMargin = 8; /* タイトル文字列までのオフセット */
int FD_RightMargin = 8; /* 取消ボタンからのオフセット */
int FD_BottomMargin = 8; /* 同上 */
int FD_FilesInList = 10; /* ファイルリストに表示するファイル数 */
/* -------- ダイアログボタンの表示文字 --------*/
/* これを変更すると,ボタンの文字を変更可能 */
char *FD_DriveName[] = {
" ", "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q"
};
char *FD_ParentBtnName = "親";
char *FD_ScrollBtnName[] = {"▲", "▼"};
char *FD_OkNgBtnName[] = {"実行", "取消"};
/*--------------------------------------*/
/* 変数定義 */
/*--------------------------------------*/
/*
* 大域ジャンプ(エラーリカバリ)用実行環境保存領域
*/
jmp_buf _FileDialogEnv;
/*
* ダイアログボタンのID
* インデックスはmajorイベントIDで指定する
*/
int _FD_ButtonIds[MaxButtons];
/*
* ファイルリストのリンクの先頭と最後,及び表示中ファイルの先頭
*/
fileInfo_t *_FileInfoTop;
fileInfo_t *_FileInfoTail;
fileInfo_t *_FileDispTop;
/*
* _scrollFileList()関数内で使用する矩形ピクセル移動用作業域
* FD_openDialog()の先頭で確保し,最後で解放する
*/
char *_BufPixelBlock = NULL;
/*--------------------------------------*/
/* ローカル関数宣言 */
/*--------------------------------------*/
LOCAL void
_showFileDialog(
fileDialog_t *pFd);
LOCAL int
_getCurrentDir(
char *path,
fileDialog_t *pFd);
LOCAL void
_showDirname(
char *name,
fileDialog_t *pFd);
LOCAL void
_initFileList(
fileDialog_t *pFd);
LOCAL void
_getFiles(
char *pattern,
fileDialog_t *pFd);
LOCAL fileInfo_t *
_makeFileInfo(
struct find_t *buf,
fileInfo_t *next,
fileInfo_t *prev);
LOCAL void
_freeFileInfo(
fileInfo_t *top);
LOCAL void
_sortFileList(
fileInfo_t *top,
int (*comp)(fileInfo_t *p1, fileInfo_t *p2));
LOCAL int
_compName(
fileInfo_t *pFi1,
fileInfo_t *pFi2);
LOCAL void
_showFileList(
fileInfo_t *pFi,
fileDialog_t *pFd);
LOCAL void
_scrollFileList(
int direction,
fileDialog_t *pFd);
LOCAL void
_showFilename(
char *name,
fileDialog_t *pFd);
LOCAL long
_getFdEvent(
fileDialog_t *pFd);
LOCAL int
_checkFileList(
int x, /* チェック対象座標 */
int y, /* 同上 */
fileDialog_t *pFd);
LOCAL void
_reverseFileName(
int fileNo, /* 反転対象ファイル番号(先頭は0) */
fileDialog_t *pFd);
LOCAL void
_errorFatal(
int errorCode);
/*--------------------------------------*/
/* 関数定義 */
/*--------------------------------------*/
GLOBAL int
FD_openDialog(
char *filename, /* 選択されたファイルのフルパス名 */
file_t *fileinfo, /* 選択されたファイルの各種情報 */
char *pattern, /* 選択対象とするファイル名 */
fileDialog_t *pFd) /* 使用するダイアログ構造体 */
/*
* PURPOSE
* 現在の書き込みページに対してファイルダイアログを表示し,
* 選択されたファイル名のフルパスをパラメタfilenameで通知する.
* また選択されたファイルのファイル名(ディレクトリ部以外),
* ファイル属性,更新日時,大きさをfileinfoで通知する.
* PARAMETERS
* filenameパラメタにはファイル名の通知に充分な領域への
* ポインタを指定すること.
* fileInfoにNULLを指定した場合は,ファイル情報は通知しない.
* patternには,ダイアログに表示する選択ファイルのマスクパターン
* (例. "*.*", "*.TIF")を指定する.NULLを指定した場合は,
* "*.*"が指定されたものとみなす.
* pFdがNULLであれば既定のファイルダイアログ
* (640*480 16色 CLUT無変更を前提とする)を使用する.
* NULLでなければ,指定されたダイアログを使用する.
*
* 本関数の復帰後,
* 現在の書き込みページはダイアログが表示された状態で,
* マウスカーソルは非表示状態となる.
* RETURNS
* 1 : ファイル選択取消
* 0 : 正常終了. この場合のみfilename,fileinfoの内容が有効.
* < 0 : エラー発生
*/
{
fileDialog_t fdStructure;
char bufInfo[200]; /* setup情報通知領域 */
int drive;
int driveStatus[DriveQ + 1];
/* 先頭要素[0]はダミーで,要素[1]から順に
* ドライブA, B, ・・・, Qに対応
* 0:FPD, 1:Rsv, 2:HD, 3:RamDisk, -1:未接続
*/
int status;
unsigned currentDrive;
unsigned tmpDrive;
unsigned maxDrive;
char currentPath[PathLen]; /* ルートの\を含む */
char currentFilename[FnameLen + 1]; /* '\0'を含む */
fileInfo_t *saveInfoTop, *saveInfoTail, *saveDispTop;
long event;
fileInfo_t *pFi;
int i;
int retCode = 0;
Bool_t bExit = FALSE;
/* エラー用 */
if ((retCode = setjmp(_FileDialogEnv)) != 0) {
if (_BufPixelBlock != NULL) {
free(_BufPixelBlock);
_BufPixelBlock = NULL;
}
return(-retCode);
}
/* ファイル検索パターンが指定されていなけれは,"*.*"とみなす */
if (pattern == NULL)
pattern = "*.*";
/* ダイアログ定義体が指定されていなければ,デフォルトの定義体を作成 */
if (pFd == NULL) {
pFd = &fdStructure;
FD_setDefDialog(pFd);
}
/* ダイアログを表示 */
_showFileDialog(pFd);
/* _scrollFileList()用作業域を確保 */
_BufPixelBlock = (char *)malloc(FD_CharWidth * (FnameLen+2)
* FD_CharHeight * FD_FilesInList);
if (_BufPixelBlock == NULL)
_errorFatal(NoAvailableMemory);
/* 接続ドライブ情報を取得 */
ESR_setupInfo(bufInfo);
for (drive = 1; drive < DriveQ; drive++)
driveStatus[drive] = bufInfo[0x30 + (drive - 1) * 2];
/* CD-ROMのドライブ情報は,0(FPD)としておく */
driveStatus[DriveQ] = 0;
/* カレントドライブ取得,表示 */
_dos_getdrive(¤tDrive);
tmpDrive = currentDrive;
BTN_setName(_FD_ButtonIds[BtnDriveCenter], FD_DriveName[currentDrive]);
/* 既にEnableになっているため BTN_enable()は呼ばない */
/* 必要な変数を初期化 */
_FileInfoTop = _FileInfoTail = _FileDispTop = NULL;
currentFilename[0] = '\0';
/* マウス表示 */
MOU_display(On);
/* カレントディレトクリ取得,表示 */
status = _getCurrentDir(currentPath, pFd);
/* ファイルリスト初期化 */
_initFileList(pFd);
if (status == 0)
/* ファイル一覧取得,表示 */
_getFiles(pattern, pFd);
/* イベント処理 */
do {
event = _getFdEvent(pFd);
switch (major(event)) {
case BtnDriveLeft:
/*
* カレントドライブから他に移動する場合,
* パス名,ファイルリスト,ファイル名領域を消去
*/
if (tmpDrive == currentDrive) {
_showDirname("\\", pFd);
/* ファイルリスト変数を保存 */
saveInfoTop = _FileInfoTop;
saveInfoTail = _FileInfoTail;
saveDispTop = _FileDispTop;
/* ファイル情報がフリーされないようにする */
_FileInfoTop = NULL;
/* ファイルリスト領域を消去 */
_initFileList(pFd);
/* ファイル名領域を消去 */
_showFilename("", pFd);
}
/* カレントドライブ変更 */
do {
tmpDrive--;
if (tmpDrive == 0)
tmpDrive = DriveQ;
status = driveStatus[tmpDrive];
} while (status != 0 && status != 2 && status != 3);
/* ドライブボタン表示の変更 */
MOU_display(Off);
BTN_setName(_FD_ButtonIds[BtnDriveCenter],
FD_DriveName[tmpDrive]);
MOU_display(On);
/*
* カレントドライブに移動する場合,
* 各種表示を復元
*/
if (tmpDrive == currentDrive) {
_showDirname(currentPath, pFd);
_FileInfoTop = saveInfoTop;
_FileInfoTail = saveInfoTail;
_FileDispTop = saveDispTop;
_showFileList(_FileDispTop, pFd);
/* 選択ファイルが存在する場合,それを表示 */
MOU_display(Off);
pFi = _FileDispTop;
for (i = 0; i < FD_FilesInList; i++) {
if (pFi == NULL)
break;
if (pFi -> select == TRUE)
_reverseFileName(i, pFd);
pFi = pFi -> next;
}
MOU_display(On);
_showFilename(currentFilename, pFd);
}
break;
case BtnDriveCenter:
/* Waitマウスカーソルに変更 */
MOU_setCursorType(1);
/* カレントドライブを設定 */
_dos_setdrive(tmpDrive, &maxDrive);
/* カレントドライブ取得,表示 */
_dos_getdrive(¤tDrive);
tmpDrive = currentDrive;
/* カレントディレトクリ取得,表示 */
status = _getCurrentDir(currentPath, pFd);
_initFileList(pFd);
if (status == 0)
/* ファイル一覧取得,表示 */
_getFiles(pattern, pFd);
/* ファイル名消去 */
currentFilename[0] = '\0';
_showFilename(currentFilename, pFd);
/* システムマウスカーソルに変更 */
MOU_setCursorType(0);
break;
case BtnDriveRight:
/*
* カレントドライブから他に移動する場合,
* パス名,ファイルリスト,ファイル名領域を消去
*/
if (tmpDrive == currentDrive) {
_showDirname("\\", pFd);
/* ファイルリスト変数を保存 */
saveInfoTop = _FileInfoTop;
saveInfoTail = _FileInfoTail;
saveDispTop = _FileDispTop;
/* ファイル情報がフリーされないようにする */
_FileInfoTop = NULL;
/* ファイルリスト領域を消去 */
_initFileList(pFd);
/* ファイル名領域を消去 */
_showFilename("", pFd);
}
/* カレントドライブ変更 */
do {
tmpDrive++;
if (tmpDrive == DriveQ + 1)
tmpDrive = 1; /* Drive A: */
status = driveStatus[tmpDrive];
} while (status != 0 && status != 2 && status != 3);
/* ドライブボタン表示の変更 */
MOU_display(Off);
BTN_setName(_FD_ButtonIds[BtnDriveCenter],
FD_DriveName[tmpDrive]);
MOU_display(On);
/*
* カレントドライブに移動する場合,
* 各種表示を復元
*/
if (tmpDrive == currentDrive) {
_showDirname(currentPath, pFd);
_FileInfoTop = saveInfoTop;
_FileInfoTail = saveInfoTail;
_FileDispTop = saveDispTop;
_showFileList(_FileDispTop, pFd);
/* 選択ファイルが存在する場合,それを表示 */
MOU_display(Off);
pFi = _FileDispTop;
for (i = 0; i < FD_FilesInList; i++) {
if (pFi == NULL)
break;
if (pFi -> select == TRUE)
_reverseFileName(i, pFd);
pFi = pFi -> next;
}
MOU_display(On);
_showFilename(currentFilename, pFd);
}
break;
case BtnParent:
/* カレントディレクトリ変更 */
chdir("..");
/* カレントディレクトリ取得,表示 */
status = _getCurrentDir(currentPath, pFd);
_initFileList(pFd);
if (status == 0)
/* ファイル一覧表示 */
_getFiles(pattern, pFd);
/* ファイル名消去 */
currentFilename[0] = '\0';
_showFilename(currentFilename, pFd);
break;
case BtnScrollUp:
case BtnScrollDown:
/* ファイル一覧をスクロール */
_scrollFileList(major(event), pFd);
break;
case BtnOk:
/* 選択されたファイル名をfilenameに設定 */
if (strlen(currentFilename)) {
filename[0] = currentDrive + 'A' - 1;
filename[1] = ':';
filename[2] = '\0';
strcat(filename, currentPath);
if (strcmp(currentPath, "\\"))
strcat(filename, "\\");
strcat(filename, currentFilename);
bExit = TRUE;
retCode = 0;
}
break;
case BtnCancel:
bExit = TRUE;
retCode = 1;
break;
case FileList:
pFi = _FileDispTop;
for (i = 0; i < minor(event); i++)
pFi = pFi -> next;
if (pFi -> attr & _A_SUBDIR) {
/* カレントディレクトリ変更 */
chdir(pFi -> name);
/* カレントディレクトリ取得,表示 */
status = _getCurrentDir(currentPath, pFd);
_initFileList(pFd);
if (status == 0)
/* ファイル一覧表示 */
_getFiles(pattern, pFd);
/* ファイル名消去 */
currentFilename[0] = '\0';
_showFilename(currentFilename, pFd);
}
else {
/* 選択されたファイル名をfilenameに設定 */
pFi -> select = TRUE;
strcpy(currentFilename, pFi -> name);
/* 各種のファイル情報を通知 */
if (fileinfo != NULL) {
strcpy(fileinfo -> name, pFi -> name);
fileinfo -> attr = pFi -> attr;
fileinfo -> date = pFi -> date;
fileinfo -> time = pFi -> time;
fileinfo -> size = pFi -> size;
}
/* ファイル名を表示する */
_showFilename(currentFilename, pFd);
}
break;
}
} while (bExit != TRUE);
/* 使用した資源を解放 */
_freeFileInfo(_FileInfoTop);
free(_BufPixelBlock);
_BufPixelBlock = NULL;
BTN_allDestroy();
MOU_display(Off);
return(retCode);
}
/* --- FD_openDialog() --- */
GLOBAL void
FD_setDefDialog(
fileDialog_t *pFd)
/*
* PURPOSE
* デフォルトファイルダイアログを作成する.
* 本ダイアログは640×480ドットの画面を想定している.
*/
{
/* ファイルダイアログの初期設定 */
pFd -> originX = FD_DialogPosX;
pFd -> originY = FD_DialogPosY;
pFd -> title = NULL; /* タイトルは無し */
pFd -> titleX = -1; /* センタリング指定 */
pFd -> titleY = FD_TopMargin;
pFd -> driveLX = FD_LeftMargin;
pFd -> driveLY = pFd->titleY + FD_CharHeight + 8;
pFd -> driveCX = pFd->driveLX + FD_CharWidth + 8 * 2;
pFd -> driveCY = pFd->driveLY;
pFd -> driveRX = pFd->driveCX + FD_DriveBtnWidth;
pFd -> driveRY = pFd->driveLY;
pFd -> pathX = FD_LeftMargin;
pFd -> pathY = pFd->driveLY + FD_ButtonHeight + 8;
pFd -> parentX = pFd->pathX + FD_CharWidth * FnameLen + 8;
pFd -> parentY = pFd->driveLY + FD_CharHeight + 8;
pFd -> fileListX = FD_LeftMargin;
pFd -> fileListY = pFd->pathY + FD_CharHeight + 8;
pFd -> upX = pFd->fileListX + FD_CharWidth * (FnameLen+2) + 8;
pFd -> upY = pFd->fileListY;
pFd -> downX = pFd->upX;
pFd -> downY = pFd->fileListY + FD_CharHeight * (FD_FilesInList-1);
pFd -> fileNameX = FD_LeftMargin;
pFd -> fileNameY = pFd->fileListY + FD_CharHeight * FD_FilesInList + 8;
pFd -> okX = FD_LeftMargin + 48;
pFd -> okY = pFd->fileNameY + FD_CharHeight + 8;
pFd -> cancelX = pFd->okX + FD_OkNgBtnWidth + 8;
pFd -> cancelY = pFd->okY;
pFd -> rightBottomX = pFd->cancelX + FD_OkNgBtnWidth + FD_RightMargin;
pFd -> rightBottomY = pFd->okY + FD_ButtonHeight + FD_BottomMargin;
}
/* --- FD_setDefDialog() --- */
LOCAL void
_showFileDialog(
fileDialog_t *pFd)
/*
* PURPOSE
* ファイルダイアログを表示する.
*/
{
int width, x;
button_t button;
/* 背景の設定 */
DISP_rectangle(
pFd->originX,
pFd->originY,
pFd->originX + pFd->rightBottomX - 1,
pFd->originY + pFd->rightBottomY - 1,
CI_Gray);
/* 枠の設定 */
DISP_rectBox(
pFd->originX,
pFd->originY,
pFd->originX + pFd->rightBottomX - 1,
pFd->originY + pFd->rightBottomY - 1,
CI_Black);
/* ダイアログタイトル表示 */
if (pFd -> title != NULL) {
/* 表示開始x座標を求める */
if (pFd -> titleX == -1) {
/* センタリング処理 */
width = strlen(pFd -> title) * FD_CharWidth;
if ((x = pFd->rightBottomX - width) < 0)
x = 0;
x /= 2;
}
else
x = pFd -> titleX;
DISP_stringAt(
pFd->title,
pFd->originX + x,
pFd->originY + pFd->titleY + FD_CharHeight - 1,
CI_Black);
}
/* パス表示エリア作成 */
DISP_rectangle(
pFd->originX + pFd->pathX,
pFd->originY + pFd->pathY,
pFd->originX + pFd->pathX + FD_CharWidth * FnameLen - 1,
pFd->originY + pFd->pathY + FD_CharHeight - 1,
CI_Black);
/* ファイルリストエリア作成 */
DISP_rectangle(
pFd->originX + pFd->fileListX,
pFd->originY + pFd->fileListY,
pFd->originX + pFd->fileListX + FD_CharWidth * (FnameLen+2) - 1,
pFd->originY + pFd->fileListY + FD_CharHeight * FD_FilesInList - 1,
CI_Black);
/* ファイル名エリア作成 */
DISP_rectangle(
pFd->originX + pFd->fileNameX,
pFd->originY + pFd->fileNameY,
pFd->originX + pFd->fileNameX + FD_CharWidth * FnameLen - 1,
pFd->originY + pFd->fileNameY + FD_CharHeight - 1,
CI_Black);
/* ドライブボタン作成 */
button.string = "<";
button.enable = TRUE;
button.repeat = FALSE;
button.luX = pFd->originX + pFd->driveLX;
button.luY = pFd->originY + pFd->driveLY;
_FD_ButtonIds[BtnDriveLeft] = BTN_create(&button);
button.string = FD_DriveName[0];
button.enable = TRUE;
button.repeat = FALSE;
button.luX = pFd->originX + pFd->driveCX;
button.luY = pFd->originY + pFd->driveCY;
_FD_ButtonIds[BtnDriveCenter] = BTN_create(&button);
button.string = ">";
button.enable = TRUE;
button.repeat = FALSE;
button.luX = pFd->originX + pFd->driveRX;
button.luY = pFd->originY + pFd->driveRY;
_FD_ButtonIds[BtnDriveRight] = BTN_create(&button);
/* 親ディレクトリボタン作成 */
button.string = FD_ParentBtnName;
button.enable = FALSE;
button.repeat = FALSE;
button.luX = pFd->originX + pFd->parentX;
button.luY = pFd->originY + pFd->parentY;
_FD_ButtonIds[BtnParent] = BTN_create(&button);
/* スクロールボタン作成 */
button.string = FD_ScrollBtnName[0];
button.enable = FALSE;
button.repeat = TRUE; /* repeat 有り */
button.luX = pFd->originX + pFd->upX;
button.luY = pFd->originY + pFd->upY;
_FD_ButtonIds[BtnScrollUp] = BTN_create(&button);
button.string = FD_ScrollBtnName[1];
button.enable = FALSE;
button.repeat = TRUE; /* repeat 有り */
button.luX = pFd->originX + pFd->downX;
button.luY = pFd->originY + pFd->downY;
_FD_ButtonIds[BtnScrollDown] = BTN_create(&button);
/* 確認取消ボタン作成 */
button.string = FD_OkNgBtnName[0];
button.enable = FALSE; /* 最初は disable 状態 */
button.repeat = FALSE;
button.luX = pFd->originX + pFd->okX;
button.luY = pFd->originY + pFd->okY;
_FD_ButtonIds[BtnOk] = BTN_create(&button);
button.string = FD_OkNgBtnName[1];
button.enable = TRUE;
button.repeat = FALSE;
button.luX = pFd->originX + pFd->cancelX;
button.luY = pFd->originY + pFd->cancelY;
_FD_ButtonIds[BtnCancel] = BTN_create(&button);
}
/* --- _showFileDialog() --- */
LOCAL int
_getCurrentDir(
char *path,
fileDialog_t *pFd)
/*
* PURPOSE
* カレントディレクトリを取得し,
* ルートを示す \ を含んだフルパスでpathに返す.
* また,ダイアログのパス表示エリアにも表示し,
* 親ディレクトリ移動ボタンのenable/disableを制御する.
* エラー時には,pathは"????????"を表示し通知する.
* RETURNS
* 0 : 正常終了
* -1 : エラー
*/
{
char *p;
int ret;
path[0] = '\\';
p = getcwd(&path[1], PathLen);
if (p != NULL) { /* エラー無し */
ret = 0;
}
else { /* エラー発生 */
strcpy(&path[1], "????????");
ret = -1;
}
_showDirname(path, pFd);
return(ret);
}
/* --- _getCurrentDir() --- */
LOCAL void
_showDirname(
char *path,
fileDialog_t *pFd)
/*
* PURPOSE
* パス名領域を消去後,指定されたパスの最終ディレクトリ名を
* 表示する.
* その後,親ディレクトリ移動ボタンのenable/disableを設定する.
* 渡されたパス名はルートの \ を含んでいるとみなす.
*/
{
char *p;
/* マウスを非表示にする */
MOU_display(Off);
/* パス名領域消去 */
DISP_rectangle(
pFd->originX + pFd->pathX,
pFd->originY + pFd->pathY,
pFd->originX + pFd->pathX + FD_CharWidth * FnameLen - 1,
pFd->originY + pFd->pathY + FD_CharHeight - 1,
CI_Black);
/* ディレクトリ名抽出 */
p = (char *)jstrrchr((unsigned char *)path, '\\');
/* \の次の文字からパス名領域に表示する */
p++;
DISP_stringAt(p,
pFd->originX + pFd->pathX,
pFd->originY + pFd->pathY + FD_CharHeight - 1,
CI_White);
/*
* ルートディレクトリか,読み込み失敗ディレクトリなら,
* 親ディレクトリ移動ボタンをdisable
*/
if (*p == '\0' || strcmp(p, "????????") == 0)
BTN_enable(_FD_ButtonIds[BtnParent], FALSE);
else
/*
* 通常のサブディレクトリなら,
* 親ディレクトリ移動ボタンをenable
*/
BTN_enable(_FD_ButtonIds[BtnParent], TRUE);
/* マウスを表示する */
MOU_display(On);
}
/* --- _showDirname() --- */
LOCAL void
_initFileList(
fileDialog_t *pFd)
/*
* PURPOSE
* ファイルリストの解放,ファイルリスト領域の消去と
* スクロールボタンのdisableを行う.
* GLOBAL VAR. (set)
* _FileInfoTop, _FileInfoTail, _FileDispTop
*/
{
/* ファイルリストを解放 */
_freeFileInfo(_FileInfoTop);
_FileInfoTop = _FileInfoTail = _FileDispTop = NULL;
/* マウスを非表示にする */
MOU_display(Off);
/* ファイルリスト領域を消去する */
DISP_rectangle(
pFd->originX + pFd->fileListX,
pFd->originY + pFd->fileListY,
pFd->originX + pFd->fileListX + FD_CharWidth * (FnameLen+2) - 1,
pFd->originY + pFd->fileListY + FD_CharHeight * FD_FilesInList - 1,
CI_Black);
/* スクロールボタンをdisableする */
BTN_enable(_FD_ButtonIds[BtnScrollUp], FALSE);
BTN_enable(_FD_ButtonIds[BtnScrollDown], FALSE);
/* マウスを表示する */
MOU_display(On);
}
/* --- _initFileList() --- */
LOCAL void
_getFiles(
char *pattern,
fileDialog_t *pFd)
/*
* PURPOSE
* カレントディレクトリに存在するサブディレクトリとファイルを
* 取得し,ファイルリストの生成とファイルリストダイアログの
* 表示を行う.
* 全サブディレクトリとpatternで指定されたファイル名を持つ
* 通常ファイルを検索する.
* GLOBAL VAR. (set)
* _FileInfoTop, _FileInfoTail, _FileDispTop
*/
{
fileInfo_t *pFi;
struct find_t fBuf;
_FileInfoTop = _FileInfoTail = NULL;
/* サブディレクトリ探索 */
if (_dos_findfirst("*.*", _A_SUBDIR, &fBuf) == 0) {
/* サブディレクトリの場合,. エントリは対象外 */
if (strcmp(fBuf.name, ".") == 0) {
/* 次の .. エントリも読み飛ばす */
_dos_findnext(&fBuf);
}
else {
if (fBuf.attrib & _A_SUBDIR) {
pFi = _makeFileInfo(&fBuf, NULL, _FileInfoTail);
if (pFi == NULL)
_errorFatal(NoAvailableMemory);
_FileInfoTop = pFi;
_FileInfoTail = pFi;
}
}
while (_dos_findnext(&fBuf) == 0) {
if (fBuf.attrib & _A_SUBDIR) {
pFi = _makeFileInfo(&fBuf, NULL, _FileInfoTail);
if (pFi == NULL)
_errorFatal(NoAvailableMemory);
if (_FileInfoTop == NULL) {
_FileInfoTop = pFi;
_FileInfoTail = pFi;
}
else {
_FileInfoTail -> next = pFi;
_FileInfoTail = pFi;
}
}
}
}
/* ファイル探索 */
if (_dos_findfirst(pattern, _A_NORMAL, &fBuf) == 0) {
pFi = _makeFileInfo(&fBuf, NULL, _FileInfoTail);
if (pFi == NULL)
_errorFatal(NoAvailableMemory);
if (_FileInfoTop == NULL) {
_FileInfoTop = pFi;
_FileInfoTail = pFi;
}
else {
_FileInfoTail -> next = pFi;
_FileInfoTail = pFi;
}
while (_dos_findnext(&fBuf) == 0) {
pFi = _makeFileInfo(&fBuf, NULL, _FileInfoTail);
if (pFi == NULL)
_errorFatal(NoAvailableMemory);
_FileInfoTail -> next = pFi;
_FileInfoTail = pFi;
}
}
/* ソート: ファイル名順 */
_sortFileList(_FileInfoTop, _compName);
/* ファイルリスト表示 */
_showFileList(_FileInfoTop, pFd);
_FileDispTop = _FileInfoTop;
}
/* --- _getFiles() --- */
LOCAL fileInfo_t *
_makeFileInfo(
struct find_t *buf, /* _dos_find**** の結果 */
fileInfo_t *next,
fileInfo_t *prev)
/*
* PURPOSE
* ファイル情報領域を確保し,必要な情報を設定する.
* RETURNS
* 非NULL : 確保したファイル情報へのポインタ
* NULL : メモリ不足により確保失敗
*/
{
fileInfo_t *pFi;
pFi = (fileInfo_t *)malloc(sizeof(fileInfo_t));
if (pFi == NULL)
return(NULL); /* malloc()失敗 */
pFi -> next = next;
pFi -> prev = prev;
strcpy(pFi -> name, buf -> name);
pFi -> attr = buf -> attrib;
pFi -> date = buf -> wr_date;
pFi -> time = buf -> wr_time;
pFi -> size = buf -> size;
pFi -> select = FALSE;
return(pFi);
}
/* --- _makeFileInfo() --- */
LOCAL void
_freeFileInfo(
fileInfo_t *top) /* 解放する先頭ノード */
/*
* PURPOSE
* ファイル情報リストを解放する.
*/
{
fileInfo_t *pFi;
fileInfo_t *next;
for (pFi = top; pFi != NULL; pFi = next) {
next = pFi -> next;
free(pFi);
}
}
/* --- _freeFileInfo() --- */
LOCAL void
_sortFileList(
fileInfo_t *top,
int (*comp)(fileInfo_t *p1, fileInfo_t *p2))
/*
* PURPOSE
* ファイル情報のリストをファイル名の順にソートする.
* IMPLEMENT
* 最大探索入れ換え法(?)
*/
{
fileInfo_t *p, *min;
fileInfo_t temp;
/* ソート対象がまったく存在しなければ,すぐに復帰 */
if (top == NULL)
return;
for ( ; top -> next != NULL; top = top -> next) {
min = top;
for (p = top -> next; p != NULL; p = p -> next)
if ((*comp)(p, min) < 0)
min = p;
if (min != top) {
/* 入れ換え実行 */
strcpy(&temp.name[0], min -> name);
temp.attr = min -> attr;
temp.date = min -> date;
temp.time = min -> time;
temp.size = min -> size;
strcpy(min -> name, top -> name);
min -> attr = top -> attr;
min -> date = top -> date;
min -> time = top -> time;
min -> size = top -> size;
strcpy(top -> name, &temp.name[0]);
top -> attr = temp.attr;
top -> date = temp.date;
top -> time = temp.time;
top -> size = temp.size;
}
}
}
/* --- sortFileInfo() --- */
LOCAL int
_compName(
fileInfo_t *pFi1,
fileInfo_t *pFi2)
/*
* PURPOSE
* ファイル名を比較し,比較結果を通知する.
* ディレクトリは,ファイルより小さい.
* 同種の中では,ファイル名/ディレクトリ名の順に従う.
* RETURNS
* 1 : pFi1 は pFi2 より大きい
* 0 : pFi1 と pFi2 は等しい
* -1 : pFi1 は pFi2 より小さい
*/
{
if (pFi1 -> attr & _A_SUBDIR) {
if (pFi2 -> attr & _A_SUBDIR)
return(strcmp(pFi1 -> name, pFi2 -> name));
return(-1);
}
else {
if (pFi2 -> attr & _A_SUBDIR)
return(1);
return(strcmp(pFi1 -> name, pFi2 -> name));
}
/* ここには到達しない */
}
/* --- _compName() --- */
LOCAL void
_showFileList(
fileInfo_t *pFi,
fileDialog_t *pFd)
/*
* PURPOSE
* ファイル情報のリストをファイルリスト領域に表示し,
* 必要に応じてスクロールボタンをenableにする.
*/
{
int i;
char name[15];
/* マウスを非表示にする */
MOU_display(Off);
/* スクロールボタン▲をenable */
if (pFi != NULL && pFi -> prev != NULL)
BTN_enable(_FD_ButtonIds[BtnScrollUp], TRUE);
/* ファイルリストを表示 */
for (i = 0; i < FD_FilesInList; i++) {
if (pFi == NULL)
break;
/*
* サブディレクトリなら,< >で括って表示する.
*/
if (pFi -> attr & _A_SUBDIR) {
strcpy(name, "<");
strcat(name, pFi -> name);
strcat(name, ">");
}
else
strcpy(name, pFi -> name);
DISP_stringAt(
name,
pFd->originX + pFd->fileListX,
pFd->originY + pFd->fileListY + FD_CharHeight * (i+1) - 1,
CI_White);
pFi = pFi -> next;
}
/* スクロールボタン▼をenable */
if (pFi != NULL)
BTN_enable(_FD_ButtonIds[BtnScrollDown], TRUE);
/* マウスを表示する */
MOU_display(On);
}
/* --- _showFileList() --- */
LOCAL void
_scrollFileList(
int direction,
fileDialog_t *pFd)
/*
* PURPOSE
* ファイルリストをdirectionで指定された方向にスクロールする.
* スクロール対象ファイル数に応じて,
* スクロールボタンのenableを変更する.
* GLOBAL VAR. (set)
* _FileDispTop
*/
{
int i;
fileInfo_t *pFi;
int luX, luY, rdX, rdY;
int lu2X, lu2Y, rd2X, rd2Y;
int lueX, lueY, rdeX, rdeY;
char name[15];
int revFile;
int btn1, btn2;
fileInfo_t *btn2On;
switch (direction) {
case BtnScrollDown: /* ▼ */
for (pFi = _FileDispTop, i = 0; i < FD_FilesInList; i++)
pFi = pFi -> next;
_FileDispTop = _FileDispTop -> next;
revFile = FD_FilesInList - 1;
/* スクロールボタンをenable化 */
btn1 = _FD_ButtonIds[BtnScrollUp];
btn2 = _FD_ButtonIds[BtnScrollDown];
btn2On = pFi -> next;
/* 複写元領域の設定 */
luX = pFd->originX + pFd->fileListX;
luY = pFd->originY + pFd->fileListY + FD_CharHeight;
rdX = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rdY = pFd->originY + pFd->fileListY
+ FD_CharHeight * FD_FilesInList - 1;
/* 複写先領域の設定 */
lu2X = pFd->originX + pFd->fileListX;
lu2Y = pFd->originY + pFd->fileListY;
rd2X = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rd2Y = pFd->originY + pFd->fileListY
+ FD_CharHeight * (FD_FilesInList-1) - 1;
/* 消去領域の設定 */
lueX = pFd->originX + pFd->fileListX;
lueY = pFd->originY + pFd->fileListY
+ FD_CharHeight * (FD_FilesInList-1);
rdeX = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rdeY = pFd->originY + pFd->fileListY
+ FD_CharHeight * FD_FilesInList - 1;
break;
case BtnScrollUp: /* ▲ */
pFi = _FileDispTop -> prev;
_FileDispTop = _FileDispTop -> prev;
revFile = 0;
/* スクロールボタンをenable化 */
btn1 = _FD_ButtonIds[BtnScrollDown];
btn2 = _FD_ButtonIds[BtnScrollUp];
btn2On = pFi -> prev;
/* 複写元領域の設定 */
luX = pFd->originX + pFd->fileListX;
luY = pFd->originY + pFd->fileListY;
rdX = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rdY = pFd->originY + pFd->fileListY
+ FD_CharHeight * (FD_FilesInList-1) - 1;
/* 複写先領域の設定 */
lu2X = pFd->originX + pFd->fileListX;
lu2Y = pFd->originY + pFd->fileListY + FD_CharHeight;
rd2X = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rd2Y = pFd->originY + pFd->fileListY
+ FD_CharHeight * FD_FilesInList - 1;
/* 消去領域の設定 */
lueX = pFd->originX + pFd->fileListX;
lueY = pFd->originY + pFd->fileListY;
rdeX = pFd->originX + pFd->fileListX
+ FD_CharWidth * (FnameLen+2) - 1;
rdeY = pFd->originY + pFd->fileListY + FD_CharHeight - 1;
break;
default:
_errorFatal(IllegalDirection);
break;
}
/* ファイルリスト領域の移動,消去,表示 */
MOU_display(Off);
DISP_getPixelBlock(luX, luY, rdX, rdY, _BufPixelBlock);
DISP_putPixelBlock(lu2X, lu2Y, rd2X, rd2Y, _BufPixelBlock);
DISP_rectangle(lueX, lueY, rdeX, rdeY, CI_Black);
/*
* サブディレクトリなら,< >で括って表示する.
*/
if (pFi -> attr & _A_SUBDIR) {
strcpy(name, "<");
strcat(name, pFi -> name);
strcat(name, ">");
}
else
strcpy(name, pFi -> name);
DISP_stringAt(name, lueX, rdeY, CI_White);
if (pFi -> select == TRUE)
_reverseFileName(revFile, pFd);
/* スクロールボタンをenable化 */
BTN_enable(btn1, TRUE);
BTN_enable(btn2, (btn2On != NULL) ? TRUE : FALSE);
MOU_display(On);
}
/* --- _scrollFileList() --- */
LOCAL void
_showFilename(
char *name,
fileDialog_t *pFd)
/*
* PURPOSE
* ファイル名領域を消去後,指定されたファイル名を表示する.
* ファイル名が空文字列でなければ,確認ボタンをenableし,
* 空文字列であれば,確認ボタンをdisableする.
*/
{
/* マウスを非表示にする */
MOU_display(Off);
/* ファイル名エリア消去 */
DISP_rectangle(
pFd->originX + pFd->fileNameX,
pFd->originY + pFd->fileNameY,
pFd->originX + pFd->fileNameX + FD_CharWidth * FnameLen - 1,
pFd->originY + pFd->fileNameY + FD_CharHeight - 1,
CI_Black);
/* ファイル名表示 */
DISP_stringAt(
name,
pFd->originX + pFd->fileNameX,
pFd->originY + pFd->fileNameY + FD_CharHeight - 1,
CI_White);
/* 確認ボタンの表示変更 */
BTN_enable(_FD_ButtonIds[BtnOk], (*name == '\0') ? FALSE : TRUE);
/* マウスを表示する */
MOU_display(On);
}
/* --- _showFilename() --- */
LOCAL long
_getFdEvent(
fileDialog_t *pFd)
/*
* PURPOSE
* 発生したイベントを通知する.
* マウスボタンのクリックのみが,イベントを発生させうる.
* イベントはボタンイベントとファイルリストイベントに分かれる.
* ボタンはenableであるもののみがイベントを発生させうる.
* ファイルリストにファイルが表示されている場合のみ,
* ファイルイベントが発生する.ファイルイベントでは,
* ファイルリスト内での位置をminorイベントIDで通知する.
* RETURNS
* イベントID
* GLOBAL VAR. (ref)
* _FileInfoTop, _FileDispTop
*/
{
int item;
int mosX, mosY;
int mosButton;
int btnStatus;
int pushedBtn; /* 通常モードで押されたボタンID */
int selectedFile, newFile;
int i;
static int repeatId = -1; /* repeatモードに入ったイベントID */
fileInfo_t *pFi;
while (1) {
pushedBtn = -1;
selectedFile = -1;
/* repeatモードの処理を行う */
if (repeatId != -1) {
do {
mosButton = MOU_readPosition(&mosX, &mosY);
if (mosButton & MouseLeftButton)
/*
* 同じボタンが押され続けていれば,
* 復帰する.
*/
if (BTN_posCheck(_FD_ButtonIds[repeatId],
mosX, mosY) == 1) {
return(repeatId);
}
} while (mosButton & MouseLeftButton);
/* repeatモード終了 */
MOU_display(Off);
BTN_reverse(_FD_ButtonIds[repeatId]);
MOU_display(On);
repeatId = -1;
}
/* 左ボタンが押されるのを待つ */
MOU_waitPress(MouseLeftButton, &mosX, &mosY);
/* ダイアログアイテムボタンが押されたかチェック */
for (item = 0; item < MaxButtons; item++) {
if (BTN_posCheck(_FD_ButtonIds[item], mosX, mosY) == 1) {
pushedBtn = _FD_ButtonIds[item];
break;
}
}
/* 押されていなければ,ファイルリストをチェック */
if (pushedBtn == -1)
selectedFile = _checkFileList(mosX, mosY, pFd);
/*
* 左ボタンの押下対象(アイテムボタン,ファイルリスト, その他)
* ごとに処理する
*/
/* アイテムボタンが押されていたら */
if (pushedBtn != -1) {
/* ボタンを反転表示する */
MOU_display(Off);
BTN_reverse(pushedBtn);
MOU_display(On);
btnStatus = ~FALSE;
/*
* repeat属性を持ったボタンであれば,
* repeatIDを設定し,すぐに復帰する.
*/
if (BTN_isRepeat(pushedBtn)) {
repeatId = item;
return(item);
}
/*
* 左ボタンが押されている間
* マウスの位置によりボタン表示を変更し,
* 左ボタンが離されるのを待つ
*/
do {
mosButton = MOU_readPosition(&mosX, &mosY);
if (btnStatus != FALSE &&
!BTN_posCheck(pushedBtn, mosX, mosY)) {
MOU_display(Off);
BTN_reverse(pushedBtn);
MOU_display(On);
btnStatus = FALSE;
}
else if (btnStatus == FALSE &&
BTN_posCheck(pushedBtn, mosX, mosY)) {
MOU_display(Off);
BTN_reverse(pushedBtn);
MOU_display(On);
btnStatus = ~FALSE;
}
} while (mosButton & MouseLeftButton);
/*
* 左ボタンが離された時点で,マウスカーソルが
* 最初に押されたボタン上にあれば,ボタンを戻して終了.
* さもなければ,元へ戻る.
*/
if (btnStatus != FALSE) {
MOU_display(Off);
BTN_reverse(pushedBtn);
MOU_display(On);
return(item);
}
}
/* ファイルリスト内が選択されていたら */
else if (selectedFile != -1) {
/*
* 既に存在する反転表示を元に戻した後,
* 指定された項目を反転表示する.
*/
MOU_display(Off);
for (i = 0, pFi = _FileDispTop; i < FD_FilesInList; i++) {
if (pFi == NULL)
break;
if (pFi -> select == TRUE)
_reverseFileName(i, pFd);
pFi -> select = FALSE;
pFi = pFi -> next;
}
for (pFi = _FileInfoTop; pFi != NULL; pFi = pFi -> next)
pFi -> select = FALSE;
_reverseFileName(selectedFile, pFd);
MOU_display(On);
/*
* 左ボタンが押されている間,マウスの位置により
* ファイル名の反転表示を変更し,
* 左ボタンが離されるのを待つ.
*/
do {
mosButton = MOU_readPosition(&mosX, &mosY);
newFile = _checkFileList(mosX, mosY, pFd);
if (selectedFile != -1 &&
newFile != selectedFile) {
MOU_display(Off);
_reverseFileName(selectedFile, pFd);
MOU_display(On);
}
if (newFile != -1 &&
selectedFile != newFile) {
MOU_display(Off);
_reverseFileName(newFile, pFd);
MOU_display(On);
}
selectedFile = newFile;
} while (mosButton & MouseLeftButton);
/*
* 左ボタンが離された時点で,マウスカーソルが
* ファイル名上にあれば,そのまま終了.
* さもなければ,元へ戻る.
*/
if (newFile != -1) {
return((newFile << 16) | FileList);
}
}
/* それ以外の領域で押されていた場合 */
else {
/* 左ボタンが離されるのを待ち,元へ戻る */
MOU_waitRelease(MouseLeftButton, &mosX, &mosY);
}
}
/* ここには到達しないため,return文はない */
}
/* --- _getFdEvent() --- */
LOCAL int
_checkFileList(
int x, /* チェック対象座標 */
int y, /* 同上 */
fileDialog_t *pFd)
/*
* PURPOSE
* 指定した座標が,
* ファイルリストに表示中のファイル名のうち,
* 何番目のファイル名の位置に相当するかを判定して,通知する.
* ファイルリスト中であっても,ファイル名が表示していない位置
* であれば,-1 を通知する.
* RETURNS
* -1 : 指定した座標はファイル名を指していない
* >= 0 : ファイル番号(先頭は0)
* GLOBAL VAR. (ref)
* _FileDispTop
*/
{
int i;
int checkY;
fileInfo_t *pFi;
/* ファイルリスト内か? */
if (pFd->originX + pFd->fileListX > x ||
pFd->originX + pFd->fileListX + FD_CharWidth * (FnameLen+2) - 1 < x)
return(-1);
if (pFd->originY + pFd -> fileListY > y)
return(-1);
/* 何番目か? */
checkY = pFd->originY + pFd->fileListY + FD_CharHeight - 1;
pFi = _FileDispTop;
for (i = 0; i < FD_FilesInList; i++) {
if (pFi == NULL)
return(-1); /* ファイル名なし */
if (y < checkY)
return(i); /* ファイル名あり */
checkY += FD_CharHeight;
pFi = pFi -> next;
}
return(-1); /* ファイルリスト外 */
}
/* --- _checkFileList() --- */
LOCAL void
_reverseFileName(
int fileNo, /* 反転対象ファイル番号(先頭は0) */
fileDialog_t *pFd)
{
DISP_xorRectangle(
pFd->originX + pFd->fileListX,
pFd->originY + pFd->fileListY + FD_CharHeight * fileNo,
pFd->originX + pFd->fileListX + FD_CharWidth * (FnameLen+2) - 1,
pFd->originY + pFd->fileListY + FD_CharHeight * (fileNo+1) - 1,
0xffff);
}
/* --- _reverseFileName() --- */
LOCAL void
_errorFatal(
int errorCode)
/*
* PURPOSE
* 致命的エラー処理ルーチン
*/
{
longjmp(_FileDialogEnv, errorCode);
}
/* --- _errorFatal() --- */
/***** filedlg.c *****/