/* ----------------- dialbox.c -------------- */ #include #include #include #ifdef MSC #include #else #include #endif #include #include #include "dflat.h" static char path[MAXPATH]; static char drive[MAXDRIVE] = " :"; static char dir[MAXDIR]; static char name[MAXFILE]; static char ext[MAXEXT]; #ifdef INCLUDE_DIALOG_BOXES static int inFocusCommand(DBOX *); static void SetRadioButton(WINDOW, DBOX *, CTLWINDOW *); static void InvertCheckBox(WINDOW, CTLWINDOW *); static void dbShortcutKeys(WINDOW, DBOX *, int); static int ControlProc(WINDOW, MESSAGE, PARAM, PARAM); static void ChangeFocus(WINDOW, int); #ifdef INCLUDE_SYSTEM_MENUS static int SysMenuOpen = FALSE; #endif int DialogProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2) { int rtn; DBOX *db; CTLWINDOW *ct; db = wnd->extension; switch (msg) { case SETFOCUS: if (p1) return TRUE; break; case LEFT_BUTTON: #ifdef INCLUDE_SYSTEM_MENUS if (WindowSizing || WindowMoving) return FALSE; #endif if (HitControlBox(wnd, p1-GetLeft(wnd), p2-GetTop(wnd))) { PostMessage(wnd, KEYBOARD, ' ', ALTKEY); return TRUE; } ct = db->ctl; while (ct->class) { int mx = (int) p1 - GetClientLeft(wnd); int my = (int) p2 - GetClientTop(wnd); if (ct->class == RADIOBUTTON) { if (my == ct->dwnd.y && mx == ct->dwnd.x+1) SetRadioButton(wnd, db, ct); } else if (ct->class == CHECKBOX) { if (my == ct->dwnd.y && mx == ct->dwnd.x+1) InvertCheckBox(wnd, ct); } ct++; } break; case PAINT: if (!isVisible(wnd)) break; if (!p2) BaseWndProc(DIALOG, wnd, msg, p1, p2); ct = p2 ? (CTLWINDOW *) p2 : db->ctl; while (ct->class) { if (ct->class == RADIOBUTTON) { char rb[] = "( )"; if (ct->vtext) rb[1] = 7; SetClassColors(DIALOG); writeline(wnd, rb, ct->dwnd.x+1, ct->dwnd.y+1, FALSE); } else if (ct->class == CHECKBOX) { char rb[] = "[ ]"; if (ct->vtext) rb[1] = 'X'; SetClassColors(DIALOG); writeline(wnd, rb, ct->dwnd.x+1, ct->dwnd.y+1, FALSE); } else if (ct->class == TEXT && ct->vtext != NULL) { char txt[100]; char *cp = ct->vtext; int len = min(ct->dwnd.h, MsgHeight(cp)); int i; for (i = 0; i < len; i++) { int mlen, dif; char *np = strchr(cp, '\n'); memset(txt, ' ', sizeof txt); mlen = CopyCommand(txt, cp, FALSE, WndBackground(wnd)); if (np == NULL) dif = mlen - strlen(cp); else dif = mlen - (int) (np - cp); txt[ct->dwnd.w + 1 + dif] = '\0'; SetStandardColor(wnd); writeline(wnd, txt, ct->dwnd.x+1, ct->dwnd.y+i+1, FALSE); if ((cp = strchr(cp, '\n')) != NULL) cp++; } } ct++; if (p2) break; } return TRUE; case KEYBOARD: switch ((int)p1) { case CTRL_FIVE: /* same as SHIFT-TAB */ if (p2 & (LEFTSHIFT | RIGHTSHIFT)) ChangeFocus(wnd, FALSE); break; case '\t': ChangeFocus(wnd, TRUE); break; #ifdef INCLUDE_SYSTEM_MENUS case ' ': if ((p2 & ALTKEY) && TestAttribute(wnd, CONTROLBOX)) { wnd->dFocus = inFocus; SysMenuOpen = TRUE; BuildSystemMenu(wnd); } break; #endif case ALT_F4: case ESC: #ifdef INCLUDE_SYSTEM_MENUS if (!(WindowMoving || WindowSizing)) #endif SendMessage(wnd, COMMAND, ID_CANCEL, 0); #ifdef INCLUDE_SYSTEM_MENUS case UP: case DN: case BS: case FWD: case '\r': if (WindowMoving || WindowSizing) return BaseWndProc(DIALOG, wnd, msg, p1, p2); break; #endif default: /* ------ search all the shortcut keys ----- */ dbShortcutKeys(wnd, db, (int) p1); break; } return TRUE; #ifdef INCLUDE_SYSTEM_MENUS case CLOSE_POPDOWN: SysMenuOpen = FALSE; break; #endif case BUTTON_RELEASED: #ifdef INCLUDE_SYSTEM_MENUS if (!WindowMoving && !WindowSizing) break; #endif rtn = BaseWndProc(DIALOG, wnd, msg, p1, p2); SendMessage(wnd->dFocus, SETFOCUS, TRUE, 0); return rtn; case LB_SELECTION: case LB_CHOOSE: #ifdef INCLUDE_SYSTEM_MENUS if (SysMenuOpen) return TRUE; #endif SendMessage(wnd, COMMAND, inFocusCommand(db), msg); break; case COMMAND: switch ((int) p1) { case ID_OK: case ID_CANCEL: wnd->ReturnCode = (int) p1; PostMessage(wnd, ENDDIALOG, 0, 0); return TRUE; default: break; } break; case CLOSE_WINDOW: if (!p1) SendMessage(wnd, COMMAND, ID_CANCEL, 0); else { ct = db->ctl; while (ct->class) { if (ct->vtext != NULL && ct->class == TEXT) { free(ct->vtext); ct->vtext = NULL; } ct++; } } break; default: break; } return BaseWndProc(DIALOG, wnd, msg, p1, p2); } int DialogBox(WINDOW wnd, DBOX *db, int (*wndproc)(struct window *, enum messages, PARAM, PARAM)) { int rtn; WINDOW Dwnd; CTLWINDOW *ct; WINDOW oldFocus = inFocus; Dwnd = CreateWindow(DIALOG, db->dwnd.title, db->dwnd.x, db->dwnd.y, db->dwnd.h, db->dwnd.w, db, wnd, wndproc, NOCLIP); ct = db->ctl; while (ct->class) { if (ct->class != TEXT && ct->class != RADIOBUTTON && ct->class != CHECKBOX) { WINDOW cwnd; int attrib = 0; ct->vtext = ct->itext; if (ct->class == EDITBOX && ct->dwnd.h > 1) attrib |= (MULTILINE | HASBORDER); if (ct->class == LISTBOX) attrib |= HASBORDER; cwnd = CreateWindow(ct->class, ct->dwnd.title, ct->dwnd.x+GetClientLeft(Dwnd), ct->dwnd.y+GetClientTop(Dwnd), ct->dwnd.h, ct->dwnd.w, NULL, Dwnd, ControlProc, attrib); ct->wnd = cwnd; if (Dwnd->dFocus == NULLWND) Dwnd->dFocus = cwnd; if (ct->itext) { char txt[SCREENWIDTH]; memset(txt, '\0', sizeof txt); CopyCommand(txt, ct->itext, FALSE, WndBackground(cwnd)); SendMessage(cwnd, ADDTEXT, LPARAM(txt), 0); } } else if (ct->class == TEXT && ct->itext != NULL) { int len = strlen(ct->itext)+1; ct->vtext = malloc(len); strncpy(ct->vtext, ct->itext, len); } else if (ct->class == RADIOBUTTON || ct->class == CHECKBOX) ct->vtext = ct->itext; ct++; } SendMessage(Dwnd->dFocus, SETFOCUS, TRUE, 0); SendMessage(Dwnd, SHOW_WINDOW, 0, 0); SendMessage(Dwnd, INITIATE_DIALOG, 0, 0); SendMessage(Dwnd, CAPTURE_MOUSE, 0, 0); SendMessage(Dwnd, CAPTURE_KEYBOARD, 0, 0); while (dispatch_message()) ; rtn = Dwnd->ReturnCode == ID_OK; SendMessage(Dwnd, RELEASE_MOUSE, 0, 0); SendMessage(Dwnd, RELEASE_KEYBOARD, 0, 0); SendMessage(Dwnd, CLOSE_WINDOW, TRUE, 0); SendMessage(oldFocus, SETFOCUS, TRUE, TRUE); if (rtn) { ct = db->ctl; while (ct->class) { if (ct->class == RADIOBUTTON || ct->class == CHECKBOX) ct->itext = ct->vtext; ct++; } } return rtn; } static int inFocusCommand(DBOX *db) { CTLWINDOW *ct = db->ctl; while (ct->class) { if (ct->wnd == inFocus) return ct->command; ct++; } return -1; } static CTLWINDOW *FindCommand(DBOX *db, enum commands cmd, int class) { CTLWINDOW *ct = db->ctl; while (ct->class) { if (ct->class == class) if (cmd == ct->command) return ct; ct++; } return NULL; } WINDOW ControlWindow(DBOX *db, enum commands cmd) { CTLWINDOW *ct = db->ctl; while (ct->class) { if (ct->class != TEXT && cmd == ct->command) return ct->wnd; ct++; } return NULLWND; } CTLWINDOW *ControlBox(DBOX *db, WINDOW wnd) { CTLWINDOW *ct = db->ctl; while (ct->class) { if (ct->class != TEXT && wnd == ct->wnd) return ct; ct++; } return NULL; } void PushRadioButton(DBOX *db, enum commands cmd) { CTLWINDOW *ct = FindCommand(db, cmd, RADIOBUTTON); if (ct != NULL) { SetRadioButton(NULLWND, db, ct); ct->itext = ON; } } #define MAXRADIOS 50 static struct { CTLWINDOW *rct; } rbs[MAXRADIOS]; static void SetRadioButton(WINDOW wnd, DBOX *db, CTLWINDOW *ct) { CTLWINDOW *ctt = db->ctl; int i; /* --- clear all the radio buttons in this group on the dialog box --- */ /* -------- build a table of all radio buttons at the same x vector ---------- */ for (i = 0; i < MAXRADIOS; i++) rbs[i].rct = NULL; while (ctt->class) { if (ctt->class == RADIOBUTTON) if (ct->dwnd.x == ctt->dwnd.x) rbs[ctt->dwnd.y].rct = ctt; ctt++; } /* ----- find the start of the radiobutton group ---- */ i = ct->dwnd.y; while (i >= 0 && rbs[i].rct != NULL) --i; /* ---- ignore everthing before the group ------ */ while (i >= 0) rbs[i--].rct = NULL; /* ----- find the end of the radiobutton group ---- */ i = ct->dwnd.y; while (i < MAXRADIOS && rbs[i].rct != NULL) i++; /* ---- ignore everthing past the group ------ */ while (i < MAXRADIOS) rbs[i++].rct = NULL; for (i = 0; i < MAXRADIOS; i++) { if (rbs[i].rct != NULL) { rbs[i].rct->vtext = OFF; if (wnd != NULLWND) SendMessage(wnd, PAINT, 0, LPARAM(rbs[i].rct)); } } ct->vtext = ON; if (wnd != NULLWND) SendMessage(wnd, PAINT, 0, LPARAM(ct)); } int RadioButtonSetting(DBOX *db, enum commands cmd) { CTLWINDOW *ct = FindCommand(db, cmd, RADIOBUTTON); if (ct != NULL) return (ct->vtext != NULL); return FALSE; } void SetCheckBox(DBOX *db, enum commands cmd) { CTLWINDOW *ct = FindCommand(db, cmd, CHECKBOX); if (ct != NULL) ct->itext = ON; } void ClearCheckBox(DBOX *db, enum commands cmd) { CTLWINDOW *ct = FindCommand(db, cmd, CHECKBOX); if (ct != NULL) ct->itext = ON; } int CheckBoxSetting(DBOX *db, enum commands cmd) { CTLWINDOW *ct = FindCommand(db, cmd, CHECKBOX); if (ct != NULL) return (ct->itext != NULL); return FALSE; } static void InvertCheckBox(WINDOW wnd, CTLWINDOW *ct) { if (ct->vtext == ON) ct->vtext = OFF; else ct->vtext = ON; SendMessage(wnd, PAINT, 0, LPARAM(ct)); } void PutItemText(WINDOW wnd, enum commands cmd, char *text) { CTLWINDOW *ct = FindCommand(wnd->extension, cmd, EDITBOX); if (ct == NULL) ct = FindCommand(wnd->extension, cmd, TEXT); if (ct != NULL) { switch (ct->class) { case EDITBOX: SendMessage(ct->wnd, EB_PUTTEXT, LPARAM(text), 0); SendMessage(ct->wnd, PAINT, 0, 0); break; case TEXT: { ct->vtext = realloc(ct->vtext, strlen(text)+1); strcpy(ct->vtext, text); SendMessage(wnd, PAINT, 0, LPARAM(ct)); break; } default: break; } } } void GetItemText(WINDOW wnd, enum commands cmd, char *text, int len) { CTLWINDOW *ct = FindCommand(wnd->extension, cmd, EDITBOX); if (ct == NULL) ct = FindCommand(wnd->extension, cmd, TEXT); if (ct != NULL) { switch (ct->class) { case EDITBOX: SendMessage(ct->wnd, EB_GETTEXT, LPARAM(text), len); break; case TEXT: strncpy(text, ct->vtext, len); break; default: break; } } } void GetDlgListText(WINDOW wnd, char *text, enum commands cmd) { CTLWINDOW *ct = FindCommand(wnd->extension, cmd, LISTBOX); int sel = SendMessage(ct->wnd, LB_CURRENTSELECTION, 0, 0); SendMessage(ct->wnd, LB_GETTEXT, LPARAM(text), sel); } int DlgDirList(WINDOW wnd, char *fspec, enum commands nameid, enum commands pathid, unsigned attrib) { int ax, criterr = 1; struct ffblk ff; CTLWINDOW *ct = FindCommand(wnd->extension, nameid, LISTBOX); WINDOW lwnd; CreatePath(path, fspec, TRUE, TRUE); if (ct != NULL) { lwnd = ct->wnd; SendMessage(ct->wnd, CLEARTEXT, 0, 0); if (attrib & 0x8000) { union REGS regs; char drname[15]; int cd, dr; #ifdef MSC _dos_getdrive(&cd); cd -= 1; #else cd = getdisk(); #endif for (dr = 0; dr < 26; dr++) { unsigned ndr; setdisk(dr); #ifdef MSC _dos_getdrive(&ndr); ndr -= 1; #else ndr = getdisk(); #endif if (ndr == dr) { /* ------- test for remapped B drive ------- */ if (dr == 1) { regs.x.ax = 0x440e; /* IOCTL function 14 */ regs.h.bl = dr+1; int86(DOS, ®s, ®s); if (regs.h.al != 0) continue; } sprintf(drname, "[%c:]", dr+'A'); /* ------ test for network or RAM disk ---- */ regs.x.ax = 0x4409; /* IOCTL function 9 */ regs.h.bl = dr+1; int86(DOS, ®s, ®s); if (!regs.x.cflag) { if (regs.x.dx & 0x1000) strcat(drname, " (Network)"); else if (regs.x.dx == 0x0800) strcat(drname, " (RAMdisk)"); } SendMessage(ct->wnd, ADDTEXT, LPARAM(drname), 0); } } setdisk(cd); } while (criterr == 1) { ax = findfirst(path, &ff, attrib & 0x3f); criterr = TestCriticalError(); } if (criterr) return FALSE; while (ax == 0) { if (!((attrib & 0x4000) && (ff.ff_attrib & (attrib & 0x3f)) == 0) && strcmp(ff.ff_name, ".")) { char fname[15]; sprintf(fname, (ff.ff_attrib & 0x10) ? "[%s]" : "%s" , ff.ff_name); SendMessage(ct->wnd, ADDTEXT, LPARAM(fname), 0); } ax = findnext(&ff); } #ifdef INCLUDE_SCROLLBARS if (lwnd->wlines > ClientHeight(lwnd)) AddAttribute(lwnd, VSCROLLBAR); else ClearAttribute(lwnd, VSCROLLBAR); #endif PostMessage(lwnd, SHOW_WINDOW, 0, 0); } if (pathid) { fnmerge(path, drive, dir, NULL, NULL); PutItemText(wnd, pathid, path); } return TRUE; } static void dbShortcutKeys(WINDOW wnd, DBOX *db, int ky) { int i; CTLWINDOW *ct; for (i = 0; i < 36; i++) if ((char) ky == altconvert[i]) break; if (i < 36) { ct = db->ctl; while (ct->class) { char *cp = ct->vtext; while (*cp) { if (*cp == SHORTCUTCHAR) { int ch; if (i < 26) ch = 'a' + i; else ch = '0' + i - 26; if (tolower(*(cp+1)) == ch) { if (ct->class == TEXT) { enum commands Tcmd = ct->command; /* --- find the associated control --- */ ct = db->ctl; while (ct->class) { if (ct->class != TEXT) if (ct->command == Tcmd) break; ct++; } } if (ct->class == RADIOBUTTON) SetRadioButton(wnd, db, ct); else if (ct->class == CHECKBOX) InvertCheckBox(wnd, ct); else if (ct->class) SendMessage(ct->wnd, SETFOCUS, TRUE, 0); return; } } cp++; } ct++; } } } /* generic window processor used by all dialog box control windows */ static int ControlProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2) { DBOX *db = GetParent(wnd)->extension; switch (msg) { case KEYBOARD: if (GetClass(wnd) == EDITBOX && !isMultiLine(wnd)) { if ((int) p1 == '\r') { SendMessage(GetParent(wnd), COMMAND, ID_OK, 0); return TRUE; } } break; case SETFOCUS: if (GetClass(wnd) != BUTTON) { if (p1) { DefaultWndProc(wnd, msg, p1, p2); SendMessage(GetParent(wnd), COMMAND, inFocusCommand(db), ENTERFOCUS); return TRUE; } else SendMessage(GetParent(wnd), COMMAND, inFocusCommand(db), LEAVEFOCUS); } break; default: break; } return DefaultWndProc(wnd, msg, p1, p2); } #endif /* ----- Create unambiguous path from file spec, filling in the drive and directory if incomplete. Optionally change to the new drive and subdirectory ------ */ void CreatePath(char *path, char *fspec, int InclName, int Change) { int cm = 0; *drive = *dir = *name = *ext = '\0'; #ifndef MSC cm = #endif fnsplit(fspec, drive, dir, name, ext); if (!InclName) *name = *ext = '\0'; *drive = toupper(*drive); #ifdef MSC if (*ext) cm |= EXTENSION; if (InclName && *name) cm |= FILENAME; if (*dir) cm |= DIRECTORY; if (*drive) cm |= DRIVE; #endif if (Change) { if (cm & DRIVE) setdisk(*drive - 'A'); if (cm & DIRECTORY) { char *cp = dir+strlen(dir)-1; if (*cp == '\\') *cp = '\0'; chdir(dir); } } if (!(cm & DRIVE)) { #ifdef MSC _dos_getdrive((unsigned *)drive); *drive -= 1; #else *drive = getdisk(); #endif *drive += 'A'; } if (!(cm & DIRECTORY)) { getcwd(dir, sizeof dir); memmove(dir, dir+2, strlen(dir+1)); } if (InclName) { if (!(cm & FILENAME)) strcpy(name, "*"); if (!(cm & EXTENSION)) strcpy(ext, ".*"); } else *name = *ext = '\0'; if (dir[strlen(dir)-1] != '\\') strcat(dir, "\\"); memset(path, 0, sizeof path); fnmerge(path, drive, dir, name, ext); } static void ChangeFocus(WINDOW wnd, int direc) { DBOX *db = wnd->extension; CTLWINDOW *ct = db->ctl; CTLWINDOW *ctt; while (ct->class) { if (ct->wnd == inFocus) break; ct++; } if (ct->class) { ctt = ct; do { if (direc) { ct++; if (ct->class == 0) ct = db->ctl; } else { if (ct == db->ctl) while (ct->class) ct++; --ct; } if (ct->wnd != NULLWND) { SendMessage(ct->wnd, SETFOCUS, TRUE, 0); break; } } while (ct != ctt); } }