/* mswdlg - Low Level Dialog Objects for Microsoft Windows */ /* XLISP-STAT 2.1 Copyright (c) 1990, 1991, by Luke Tierney */ /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */ /* You may give out copies of this software; for conditions see the */ /* file COPYING included with this distribution. */ #include "dialogs.h" #include "wxlisp.h" #include "ledit.h" /* external variables */ extern HWND hWndFrame, hWndClient; extern HINSTANCE hInst; extern HANDLE hAccel; extern LVAL s_text_length; /* static variables */ static char szXLSDlgClass[] = "XLSDialog"; static char szXLSMDIDlgClass[] = "XLSMDIDialog"; static char szXLSMDlgClass[] = "XLSModalDialog"; static BOOL InModalDialog = FALSE; static LVAL ModalItem = NIL; #ifdef WIN32 static WNDPROC pDefBtnProc = NULL; static WNDPROC pDefEditTextProc = NULL; static WNDPROC pDefScrollProc = NULL; static WNDPROC pDefListProc = NULL; #endif /* WIN32 */ /* function prototypes */ LRESULT CALLBACK XLSDlgProc(HWND, UINT, WPARAM, LONG); LRESULT CALLBACK XLSMDIDlgProc(HWND, UINT, WPARAM, LONG); LRESULT CALLBACK XLSMDlgProc(HWND, UINT, WPARAM, LONG); static void InstallItem(HWND, LVAL); static void InstallButtonItem(HWND, LVAL); static void InstallToggleItem(HWND, LVAL); static void InstallChoiceItem(HWND, LVAL); static void InstallTextItem(HWND, LVAL); static void InstallScrollItem(HWND, LVAL); static void InstallListItem(HWND, LVAL); static void SetClusterValue(HWND, int); #ifdef WIN32 static void DialogDoDefaultButton(LVAL dialog); static LRESULT CALLBACK CustomButtonProc(HWND hWnd,UINT message,WPARAM wPrm,LPARAM lPrm); static LRESULT CALLBACK CustomEditTextProc(HWND hWnd,UINT message,WPARAM wPrm,LPARAM lPrm); static LRESULT CALLBACK CustomScrollProc(HWND hWnd,UINT message,WPARAM wPrm,LPARAM lPrm); static LRESULT CALLBACK CustomListProc(HWND hWnd,UINT message,WPARAM wPrm,LPARAM lPrm); #endif /* WIN32 */ #ifdef WIN32 # define DIALOG_FONT DEFAULT_GUI_FONT # define DIALOG_BACKGROUND COLOR_MENU # define AVE_CHAR_PAD 2 # define CHOICE_WIDTH_FUZZ 6 #else # define DIALOG_FONT SYSTEM_FIXED_FONT # define DIALOG_BACKGROUND COLOR_WINDOW # define AVE_CHAR_PAD 0 # define CHOICE_WIDTH_FUZZ 4 #endif #define LIST_USE_LEADING FALSE /**** inline this */ #define REAL_LIST_ITEM_PAD 0 /**** drop LIST_ITEM_PAD */ /**** need to rethink size calculations for non-fixed-width fonts */ /***********************************************************************/ /** **/ /** Utility Functions **/ /** **/ /***********************************************************************/ static void check_alloc(HANDLE p) { if (! p) xlfail("allocation failed"); } static void check_lock(void *p) { if (! p) xlfail("lock failed"); } static int FindItemType(LVAL item) { if (consp(item)) return(ITEM_LIST); else if (button_item_p(item)) return(BUTTON_ITEM); else if (toggle_item_p(item)) return(TOGGLE_ITEM); else if (text_item_p(item)) return(TEXT_ITEM); else if (choice_item_p(item)) return(CHOICE_ITEM); else if (scroll_item_p(item)) return(SCROLL_ITEM); else if (list_item_p(item)) return(LIST_ITEM); else xlfail("item of unknown type"); return(0); } static int count_hardware_items(LVAL items) { LVAL temp; int n; if (! consp (items)) return(0); else { for (n = 0; consp(items); items = cdr(items)) { switch(FindItemType(car(items))) { case CHOICE_ITEM: temp = slot_value(car(items), s_text); if (! consp(temp)) xlerror("not a list", temp); n += (int) llength(temp); break; case ITEM_LIST: n += count_hardware_items(car(items)); break; default: n += 1; } } } return(n); } static Point AvCharSize(BOOL leaded) { Point pt; HDC hDC; TEXTMETRIC tm; hDC = GetDC(hWndFrame); SelectObject(hDC, GetStockObject(DIALOG_FONT)); GetTextMetrics(hDC, &tm); pt.h = tm.tmAveCharWidth + AVE_CHAR_PAD; /* to correct font width problems */ pt.v = tm.tmHeight; if (leaded) pt.v += tm.tmExternalLeading; ReleaseDC(hWndFrame, hDC); return(pt); } static Point text_size(char *s) { char *bp; int w; Point sz; for (w = 0, sz.h = 0, sz.v = 0; *s != '\0'; s++) { for (bp = buf; *s != '\0' && *s != '\r' && *s != '\n'; s++, bp++) *bp = *s; *bp = '\0'; w = strlen(buf); if (sz.h < w) sz.h = w; sz.v++; if (*s == '\0') break; } return(sz); } static void truncateListEntry(char *s) { if (strlen(s) > MAX_ENTRY_LENGTH) { s = s + MAX_ENTRY_LENGTH - 3; s[0] = '.'; s[1] = '.'; s[2] = '.'; s[3] = '\0'; } } static BOOL FindItemData(HWND theDialog, int wParam, DialogItemData *di) { HANDLE hd; DialogData *dd; DialogItemData *did; int index, result; index = wParam - ITEM_INDEX_BASE; if (index < 0) return(FALSE); hd = GETDIALOGDATA(theDialog); dd = (DialogData *) GlobalLock(hd); check_lock(dd); did = GETITEMDATA(dd); if (index < dd->count) { *di = did[index]; result = TRUE; } else result = FALSE; GlobalUnlock(hd); return(result); } static BOOL FindItemObjectData(LVAL item, DialogItemData *di) { LVAL dialog; HANDLE hd; DialogData *dd; DialogItemData *did; int i, found; dialog = slot_value(item, s_dialog); if (dialog == NIL || ! check_dialog_address(dialog)) return(FALSE); hd = GETDIALOGDATA(GETDIALOGADDRESS(dialog)); dd = (DialogData *) GlobalLock(hd); check_lock(dd); did = GETITEMDATA(dd); for (i = 0, found = FALSE; i < dd->count && ! found; i++) { if (did[i].object == item) { *di = did[i]; found = TRUE; } } GlobalUnlock(hd); return(found); } /***********************************************************************/ /** **/ /** Internal Dialog Data Functions **/ /** **/ /***********************************************************************/ static HANDLE MakeDialogData(LVAL dialog) { int numItems; HANDLE hItems; DialogData *dd; numItems = count_hardware_items(slot_value(dialog, s_items)); hItems = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(DialogData) + numItems * sizeof(DialogItemData)); check_alloc(hItems); dd = (DialogData *) GlobalLock(hItems); check_lock(dd); dd->count = 0; dd->object = dialog; dd->dflt = -1; GlobalUnlock(hItems); return(hItems); } static void FreeDialogData(HANDLE hItems) { GlobalFree(hItems); } static void InstallItemList(HWND theDialog, LVAL items) { for (; consp(items); items = cdr(items)) if (consp(car(items))) InstallItemList(theDialog, car(items)); else InstallItem(theDialog, car(items)); } static void InstallItem(HWND theDialog, LVAL item) { if (! dialog_item_p(item)) xlerror("not a dialog item", item); switch (FindItemType(item)) { case BUTTON_ITEM: InstallButtonItem(theDialog, item); break; case TOGGLE_ITEM: InstallToggleItem(theDialog, item); break; case CHOICE_ITEM: InstallChoiceItem(theDialog, item); break; case TEXT_ITEM: InstallTextItem(theDialog, item); break; case SCROLL_ITEM: InstallScrollItem(theDialog, item); break; case LIST_ITEM: InstallListItem(theDialog, item); break; default: xlfail("unkown item type"); } } /***********************************************************************/ /** **/ /** Initialization and Callback Functions **/ /** **/ /***********************************************************************/ BOOL InitApplDialogs(HANDLE hInstance) { WNDCLASS wc; /* class structure for modeless dialog windows */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) XLSDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(LONG) + sizeof(LONG); wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "WXLSIcon"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (DIALOG_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szXLSDlgClass; if (! RegisterClass(&wc)) return(FALSE); /* class structure for modeless MDI dialog windows */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) XLSMDIDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(LONG) + sizeof(LONG); wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "WXLSIcon"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (DIALOG_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szXLSMDIDlgClass; if (! RegisterClass(&wc)) return(FALSE); /* class structure for modal dialog windows */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) XLSMDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(LONG) + sizeof(LONG); wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (DIALOG_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szXLSMDlgClass; if (! RegisterClass(&wc)) return(FALSE); #ifdef WIN32 // // these procs are used to pass the ENTER key on to the parent window to // mimic default button modal dialog behavior // GetClassInfo(hInstance, "button", &wc); pDefBtnProc = wc.lpfnWndProc; GetClassInfo(hInstance, "edit", &wc); pDefEditTextProc = wc.lpfnWndProc; GetClassInfo(hInstance, "scrollbar", &wc); pDefScrollProc = wc.lpfnWndProc; GetClassInfo(hInstance, "listbox", &wc); pDefListProc = wc.lpfnWndProc; #endif /* WIN32 */ return(TRUE); } int InitInstDialogs(HANDLE hInstance) { return(TRUE); } static LRESULT ProcessDialogEvent(HWND hWnd, UINT message, WPARAM wPrm, LONG lPrm, BOOL modeless, BOOL mdidialog) { LVAL dialog; DialogItemData di; int val, wid; switch(message) { #ifdef WIN32 /* Set the background color for WIN32 */ case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: case WM_CTLCOLORBTN: val = SetBkColor((HDC) wPrm, GetSysColor(DIALOG_BACKGROUND)); SelectObject((HDC) wPrm, GetStockObject(DIALOG_FONT)); return ((LRESULT) GetSysColorBrush(DIALOG_BACKGROUND)); #endif case WM_CREATE: if (mdidialog) { LPMDICREATESTRUCT mdic; mdic = (LPMDICREATESTRUCT) ((LPCREATESTRUCT) lPrm)->lpCreateParams; dialog = (LVAL) mdic->lParam; } else dialog = (LVAL) ((LPCREATESTRUCT) lPrm)->lpCreateParams; SETDIALOGOBJECT(hWnd, dialog); SETDIALOGDATA(hWnd, MakeDialogData(dialog)); InstallItemList(hWnd, slot_value(dialog, s_items)); DialogSetDefaultButton(dialog, slot_value(dialog, s_default_button)); break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wPrm, lPrm)) { case IDC_SHOWWINDOW: if (modeless) { if (mdidialog) { if (IsIconic(hWnd)) MDIRestoreWindow(hWndClient, hWnd); MDIActivateWindow(hWndClient, hWnd); } else { if (IsIconic(hWnd)) ShowWindow(hWnd,SW_RESTORE); } return(0); } break; case IDC_HIDEWINDOW: if (modeless) { if (! IsIconic(hWnd)) ShowWindow(hWnd, SW_MINIMIZE); return(0); } break; case IDC_DESTROY: if (mdidialog) MDIDestroyWindow(hWndClient, hWnd); else DestroyWindow(hWnd); return 0; default: if (FindItemData(hWnd, GET_WM_COMMAND_ID(wPrm, lPrm), &di)) { if (di.object && di.object != NIL) { switch (di.type) { case TOGGLE_ITEM: val = ! Button_GetCheck(di.itemHandle); Button_SetCheck(di.itemHandle, val); set_slot_value(di.object, s_value, (val) ? s_true : NIL); break; case CHOICE_ITEM: SetClusterValue(hWnd, di.itemNumber); set_slot_value(di.object, s_value, cvfixnum((FIXTYPE) di.itemNumber - di.clusterLeader)); break; } if (di.type == LIST_ITEM) { switch (GET_WM_COMMAND_CMD(wPrm, lPrm)) { case LBN_DBLCLK: send_callback_message_1L(di.object, sk_do_action, s_true); break; case LBN_SELCHANGE: case LBN_SELCANCEL: send_callback_message(di.object, sk_do_action); break; } } else { if (InModalDialog) ModalItem = di.object; else send_callback_message(di.object, sk_do_action); } } return(0); } } break; case WM_VSCROLL: case WM_HSCROLL: wid = GetWindowID(GET_WM_HSCROLL_HWND(wPrm, lPrm)); switch (GET_WM_HSCROLL_CODE(wPrm, lPrm)) { case SB_PAGEDOWN: case SB_LINEDOWN: case SB_PAGEUP: case SB_LINEUP: case SB_TOP: case SB_BOTTOM: if (FindItemData(hWnd, wid, &di) && di.object && di.object != NIL) { int low, high, value, page; LVAL temp, item = di.object; temp = slot_value(item, s_min_value); low = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MIN; temp = slot_value(item, s_max_value); high = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MAX; temp = slot_value(item, s_value); value = (fixp(temp)) ? (int) getfixnum(temp) : low; temp = slot_value(item, s_page_increment); page = (fixp(temp)) ? (int) getfixnum(temp) : SCROLL_PAGE; switch (GET_WM_HSCROLL_CODE(wPrm, lPrm)) { case SB_PAGEDOWN: value += page; break; case SB_LINEDOWN: value++; break; case SB_PAGEUP: value -= page; break; case SB_LINEUP: value--; break; case SB_TOP: value = low; break; case SB_BOTTOM: value = high; break; } if (value < low) value = low; if (value > high) value = high; set_slot_value(item, s_value, cvfixnum((FIXTYPE) value)); SetScrollPos(di.itemHandle, SB_CTL, value, TRUE); send_callback_message(item, sk_scroll_action); } return(0); case SB_THUMBPOSITION: val = GET_WM_HSCROLL_POS(wPrm, lPrm); if (FindItemData(hWnd, wid, &di) && di.object && di.object != NIL) { set_slot_value(di.object, s_value, cvfixnum((FIXTYPE) val)); SetScrollPos(di.itemHandle, SB_CTL, val, TRUE); send_callback_message(di.object, sk_do_action); } return(0); } break; #ifdef WIN32 case WM_CHAR: switch (wPrm) { case VK_RETURN: // do the default button thing DialogDoDefaultButton(GETDIALOGOBJECT(hWnd)); break; case VK_ESCAPE: DestroyWindow(hWnd); break; } break; #endif /* WIN32 */ case WM_QUERYENDSESSION: case WM_CLOSE: if (! InModalDialog) send_callback_message((LVAL) GETDIALOGOBJECT(hWnd), sk_close); return(0); case WM_DESTROY: FreeDialogData(GETDIALOGDATA(hWnd)); if (mdidialog) return 0; } if (mdidialog) return(DefMDIChildProc(hWnd, message, wPrm, lPrm)); else return(DefWindowProc(hWnd, message, wPrm, lPrm)); } LRESULT CALLBACK XLSDlgProc(HWND hWnd, UINT message, WPARAM wPrm, LONG lPrm) { return ProcessDialogEvent(hWnd, message, wPrm, lPrm, TRUE, FALSE); } LRESULT CALLBACK XLSMDIDlgProc(HWND hWnd, UINT message, WPARAM wPrm, LONG lPrm) { return ProcessDialogEvent(hWnd, message, wPrm, lPrm, TRUE, TRUE); } LRESULT CALLBACK XLSMDlgProc(HWND hWnd, UINT message, WPARAM wPrm, LONG lPrm) { return ProcessDialogEvent(hWnd, message, wPrm, lPrm, FALSE, FALSE); } void MSWResetDialogs(void) { ModalItem = NIL; InModalDialog = FALSE; } /***********************************************************************/ /** **/ /** Allocation and Deallocation Functions **/ /** **/ /***********************************************************************/ void DialogAllocate(LVAL dialog) { HWND theDialog; Point loc, size; char *title; BOOL goAway, modeless; DWORD flags; if (check_dialog_address(dialog)) DialogRemove(dialog); if (! stringp(slot_value(dialog, s_title))) xlerror("not a string", slot_value(dialog, s_title)); title = (char *) getstring(slot_value(dialog, s_title)); goAway = (slot_value(dialog, s_go_away) != NIL) ? TRUE : FALSE; modeless = (slot_value(dialog, s_type) != s_modal) ? TRUE : FALSE; loc = ListToPoint(slot_value(dialog, s_location)); size = ListToPoint(slot_value(dialog, s_size)); if (size.h < MIN_DLG_WIDTH) size.h = MIN_DLG_WIDTH; if (size.v < MIN_DLG_HEIGHT) size.v = MIN_DLG_HEIGHT; if (modeless) { // ### fix if manage to get proper frame /**** This is a quick hack. It would probably be better to use a slot to set the MDI/non-MDI option */ LVAL topsym = xlenter("SYSTEM::*TOP-LEVEL-DIALOGS*"); int mdidialog = (! boundp(topsym)) || null(getvalue(topsym)); size.h += 2 * GetSystemMetrics(SM_CXBORDER); size.v += GetSystemMetrics(SM_CYBORDER); size.v += GetSystemMetrics(SM_CYCAPTION); // ### kill border so dlgframe works? flags = WS_POPUP | WS_DLGFRAME | WS_VISIBLE | WS_CAPTION; if (goAway) flags |= WS_SYSMENU; if (mdidialog) { MDICREATESTRUCT mdicreate; mdicreate.szClass = szXLSMDIDlgClass; mdicreate.szTitle = title; mdicreate.hOwner = hInst; mdicreate.x = loc.h; mdicreate.y = loc.v; mdicreate.cx = size.h; mdicreate.cy = size.v; mdicreate.style = WS_MINIMIZE; mdicreate.lParam = (LONG) dialog; theDialog = MDICreateWindow(hWndClient, &mdicreate); SetWindowStyle(theDialog, GetWindowStyle(theDialog) & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX); MDIRestoreWindow(hWndClient, theDialog); } else { theDialog = CreateWindowEx(WS_EX_DLGMODALFRAME, szXLSDlgClass, title, flags, loc.h, loc.v, size.h, size.v, NULL, NULL, hInst, (LPVOID) dialog); } } else { size.h += 2 * GetSystemMetrics(SM_CXDLGFRAME); #ifdef WIN32 size.v += GetSystemMetrics(SM_CYBORDER); size.v += GetSystemMetrics(SM_CYCAPTION); flags = WS_POPUP | WS_VISIBLE |WS_CAPTION; //FC 7/20/99 theDialog = CreateWindowEx(WS_EX_DLGMODALFRAME, szXLSMDlgClass, title, flags, loc.h, loc.v, size.h, size.v, NULL, NULL, hInst, (LPVOID) dialog); #else size.v += 2 * GetSystemMetrics(SM_CYDLGFRAME); flags = WS_POPUP | WS_DLGFRAME | WS_VISIBLE; theDialog = CreateWindow(szXLSMDlgClass, title, flags, loc.h, loc.v, size.h, size.v, hWndFrame, NULL, hInst, (LPVOID) dialog); #endif } check_alloc(theDialog); set_dialog_address(theDialog, dialog); } void DialogRemove(LVAL dialog) { if (check_dialog_address(dialog)) XLSDestroyWindow(GETDIALOGADDRESS(dialog)); if (objectp(dialog)) standard_hardware_clobber(dialog); } /***********************************************************************/ /** **/ /** Dialog Item Functions **/ /** **/ /***********************************************************************/ static void InstallBtnItem(HWND theDialog, LVAL item, DWORD flags, int type, DialogItemData *di) { HANDLE hd; DialogItemData *data; DialogData *dialogData; HWND theItem; int itemIndex; char *text; Point loc, size; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); itemIndex = (dialogData->count)++; if (! stringp(slot_value(item, s_text))) xlerror("not a string", slot_value(item, s_text)); text = (char *) getstring(slot_value(item, s_text)); loc = ListToPoint(slot_value(item, s_location)); size = ListToPoint(slot_value(item, s_size)); theItem = CreateWindow("button", text, WS_CHILD | WS_VISIBLE | flags, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); check_alloc(theItem); data = GETITEMDATA(dialogData); data[itemIndex].type = type; data[itemIndex].itemNumber = itemIndex; data[itemIndex].itemHandle = theItem; data[itemIndex].object = item; if (di) *di = data[itemIndex]; #ifdef WIN32 SetWindowLong(theItem, GWL_WNDPROC, (LPARAM)CustomButtonProc); #endif /* WIN32 */ GlobalUnlock(hd); } static void InstallButtonItem(HWND theDialog, LVAL item) { InstallBtnItem(theDialog, item, BS_PUSHBUTTON, BUTTON_ITEM, NULL); } #ifdef WIN32 static LRESULT CALLBACK CustomButtonProc(HWND hWnd, UINT message, WPARAM wPrm, LPARAM lPrm) { if ((message == WM_CHAR) && (wPrm == VK_RETURN)) { SendMessage(GetParent(hWnd), message, wPrm, lPrm); return 0; } return CallWindowProc(pDefBtnProc, hWnd, message, wPrm, lPrm); } static LRESULT CALLBACK CustomScrollProc(HWND hWnd, UINT message, WPARAM wPrm, LPARAM lPrm) { if ((message == WM_CHAR) && (wPrm == VK_RETURN)) { SendMessage(GetParent(hWnd), message, wPrm, lPrm); return 0; } return CallWindowProc(pDefScrollProc, hWnd, message, wPrm, lPrm); } static LRESULT CALLBACK CustomEditTextProc(HWND hWnd, UINT message, WPARAM wPrm, LPARAM lPrm) { if ((message == WM_CHAR) && (wPrm == VK_RETURN)) { SendMessage(GetParent(hWnd), message, wPrm, lPrm); return 0; } return CallWindowProc(pDefEditTextProc, hWnd, message, wPrm, lPrm); } static LRESULT CALLBACK CustomListProc(HWND hWnd, UINT message, WPARAM wPrm, LPARAM lPrm) { if ((message == WM_CHAR) && (wPrm == VK_RETURN)) { SendMessage(GetParent(hWnd), message, wPrm, lPrm); return 0; } return CallWindowProc(pDefListProc, hWnd, message, wPrm, lPrm); } #endif /* WIN32 */ void DialogButtonGetDefaultSize(LVAL item, int *pwidth, int *pheight) { LVAL text; Point csz; int n; text = slot_value(item, s_text); if (! stringp(text)) xlerror("not a string", text); csz = AvCharSize(TRUE); n = strlen((char *) getstring(text)); if (n < MIN_BUTTON_STRLEN) n = MIN_BUTTON_STRLEN; if (pwidth != NULL) *pwidth = (n + 2) * csz.h; if (pheight != NULL) *pheight = (7 * csz.v) / 4; } static void InstallToggleItem(HWND theDialog, LVAL item) { DialogItemData di; InstallBtnItem(theDialog, item, BS_CHECKBOX, TOGGLE_ITEM, &di); Button_SetCheck(di.itemHandle, (slot_value(item, s_value) != NIL) ? TRUE : FALSE); } void DialogToggleGetDefaultSize(LVAL item, int *pwidth, int *pheight) { LVAL text; Point csz; int n; text = slot_value(item, s_text); if (! stringp(text)) xlerror("not a string", text); csz = AvCharSize(TRUE); n = strlen((char *) getstring(text)); if (pwidth != NULL) *pwidth = (n + 4) * csz.h; if (pheight != NULL) *pheight = (3 * csz.v) / 2; } LVAL DialogToggleItemValue(item, set, value) LVAL item, value; int set; { DialogItemData itemData; if (set) { set_slot_value(item, s_value, (value != NIL) ? s_true : NIL); if (FindItemObjectData(item, &itemData)) { Button_SetCheck(itemData.itemHandle, (value != NIL) ? TRUE : FALSE); } } return(slot_value(item, s_value)); } static void InstallChoiceItem(HWND theDialog, LVAL item) { LVAL titles, temp; DialogItemData *data; DialogData *dialogData; HWND theItem; int itemIndex, clusterLeader, clusterSize, initial; char *text; Point loc, size; HANDLE hd; titles = slot_value(item, s_text); if (! consp(titles)) xlerror("not a list", titles); loc = ListToPoint(slot_value(item, s_location)); size = ListToPoint(slot_value(item, s_size)); clusterSize = (int) llength(titles); size.v /= clusterSize; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); clusterLeader = dialogData->count; for (; consp(titles); titles = cdr(titles)) { if (! stringp(car(titles))) xlerror("not a string", car(titles)); text = (char *) getstring(car(titles)); itemIndex = (dialogData->count)++; theItem = CreateWindow("button", text, WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); check_alloc(theItem); loc.v += size.v; data = GETITEMDATA(dialogData); data[itemIndex].type = CHOICE_ITEM; data[itemIndex].itemNumber = itemIndex; data[itemIndex].itemHandle = theItem; data[itemIndex].object = item; data[itemIndex].clusterLeader = clusterLeader; data[itemIndex].clusterSize = clusterSize; #ifdef WIN32 SetWindowLong(theItem, GWL_WNDPROC, (LPARAM)CustomButtonProc); #endif /* WIN32 */ } temp = slot_value(item, s_value); initial = (fixp(temp)) ? (int) getfixnum(temp) : 0; if (initial < 0 || initial >= clusterSize) initial = 0; initial += clusterLeader; Button_SetCheck(data[initial].itemHandle, 1); GlobalUnlock(hd); } void DialogChoiceGetDefaultSize(LVAL item, int *pwidth, int *pheight) { Point csz; LVAL text = slot_value(item, s_text); int n, k, h; csz = AvCharSize(TRUE); for (h = 0, n = 0; consp(text); text = cdr(text)) { k = strlen((char *) getstring(car(text))); if (n < k) n = k; h += (3 * csz.v) / 2; } if (pwidth != NULL) *pwidth = (n + CHOICE_WIDTH_FUZZ) * csz.h; if (pheight != NULL) *pheight = h; } static void SetClusterValue(HWND theDialog, int index) { int i, n, leader; HANDLE hd; DialogData *dialogData; DialogItemData *data; if (index < 0) return; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); if (index < dialogData->count) { data = GETITEMDATA(dialogData); leader = data[index].clusterLeader; n = data[index].clusterSize + leader; for (i = leader; i < n; i++) Button_SetCheck(data[i].itemHandle, 0); Button_SetCheck(data[index].itemHandle, 1); } GlobalUnlock(hd); } LVAL DialogChoiceItemValue(LVAL item, int set, int value) { DialogItemData itemData; LVAL dialog, textlist; if (set) { textlist = slot_value(item, s_text); if (! consp(textlist) || value < 0 || value >= llength(textlist)) xlfail("Value out of range"); set_slot_value(item, s_value, cvfixnum((FIXTYPE) value)); if (FindItemObjectData(item, &itemData)) { if (value < 0 || value >= itemData.clusterSize) xlfail("value out of range"); dialog = slot_value(item, s_dialog); SetClusterValue(GETDIALOGADDRESS(dialog), itemData.clusterLeader + value); } } return(slot_value(item, s_value)); } static void InstallTextItem(HWND theDialog, LVAL item) { HANDLE hd; DialogItemData *data; DialogData *dialogData; HWND theItem; int editable, itemIndex; char *text; Point loc, size; if (! stringp(slot_value(item, s_text))) xlerror("not a string", slot_value(item, s_text)); text = (char *) getstring(slot_value(item, s_text)); loc = ListToPoint(slot_value(item, s_location)); size = ListToPoint(slot_value(item, s_size)); editable = (slot_value(item, s_editable) != NIL) ? TRUE : FALSE; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); itemIndex = (dialogData->count)++; strcpy(buf, text); if (editable) { theItem = CreateWindow("edit", buf, WS_CHILD | WS_VISIBLE | WS_BORDER, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); } else { theItem = CreateWindow("static", buf, WS_CHILD | WS_VISIBLE, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); } check_alloc(theItem); #ifdef WIN32 if (editable) { SetWindowLong(theItem, GWL_WNDPROC, (LPARAM)CustomEditTextProc); } #endif /* WIN32 */ data = GETITEMDATA(dialogData); data[itemIndex].type = TEXT_ITEM; data[itemIndex].itemNumber = itemIndex; data[itemIndex].itemHandle = theItem; data[itemIndex].object = item; GlobalUnlock(hd); } void DialogTextGetDefaultSize(LVAL item, int *pwidth, int *pheight) { Point csz, tsz; LVAL text = slot_value(item, s_text); LVAL text_length = slot_value(item, s_text_length); tsz.h = 0; tsz.v = 0; csz = AvCharSize(TRUE); if (stringp(text)) { tsz = text_size((char *) getstring(text)); } if (fixp(text_length)) { if (tsz.h < getfixnum(text_length)) tsz.h = (int) getfixnum(text_length); if (tsz.v < 1) tsz.v = 1; } if (slot_value(item, s_editable) != NIL) { if (pwidth != NULL) *pwidth = csz.h * tsz.h + EDIT_TEXT_PAD; if (pheight != NULL) *pheight = csz.v * tsz.v + EDIT_TEXT_PAD; } else { if (pwidth != NULL) *pwidth = csz.h * tsz.h + STATIC_TEXT_PAD; if (pheight != NULL) *pheight = csz.v * tsz.v + STATIC_TEXT_PAD; } } LVAL DialogTextItemText(LVAL item, int set, char *text) { DialogItemData di; int n; if (set) set_slot_value(item, s_text, cvstring(text)); if (FindItemObjectData(item, &di)) { if (set) { strcpy(buf, text); SetWindowText(di.itemHandle, buf); } n = GetWindowText(di.itemHandle, buf, STRMAX); buf[n] = '\0'; set_slot_value(item, s_text, cvstring(buf)); } return(slot_value(item, s_text)); } static void InstallScrollItem(HWND theDialog, LVAL item) { HANDLE hd; DialogItemData *data; DialogData *dialogData; HWND theItem; int low, high, value; int itemIndex; Point loc, size; LVAL temp; DWORD flags; loc = ListToPoint(slot_value(item, s_location)); size = ListToPoint(slot_value(item, s_size)); flags = (size.h > size.v) ? SBS_HORZ : SBS_VERT; temp = slot_value(item, s_min_value); low = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MIN; temp = slot_value(item, s_max_value); high = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MAX; temp = slot_value(item, s_value); value = (fixp(temp)) ? (int) getfixnum(temp) : low; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); itemIndex = (dialogData->count)++; theItem = CreateWindow("scrollbar", NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | flags, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); check_alloc(theItem); SetScrollRange(theItem, SB_CTL, low, high, FALSE); SetScrollPos(theItem, SB_CTL, value, TRUE); data = GETITEMDATA(dialogData); data[itemIndex].type = SCROLL_ITEM; data[itemIndex].itemNumber = itemIndex; data[itemIndex].itemHandle = theItem; data[itemIndex].object = item; GlobalUnlock(hd); #ifdef WIN32 SetWindowLong(theItem, GWL_WNDPROC, (LPARAM)CustomScrollProc); #endif /* WIN32 */ } void DialogScrollGetDefaultSize(LVAL item, int *pwidth, int *pheight) { int h, w; h = GetSystemMetrics(SM_CYHSCROLL); w = SCROLL_WIDTH; // ### 10 * h if (pwidth != NULL) *pwidth = w; if (pheight != NULL) *pheight = h; } static LVAL scroll_item_value(LVAL item, int set, int value, int which) { LVAL slot, temp; DialogItemData di; int low, high; switch (which) { case 'V': slot = s_value; break; case 'H': slot = s_max_value; break; case 'L': slot = s_min_value; break; } if (set) { if (FindItemObjectData(item, &di)) { switch (which) { case 'V': SetScrollPos(di.itemHandle, SB_CTL, value, TRUE); break; case 'H': temp = slot_value(item, s_min_value); low = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MIN; SetScrollRange(di.itemHandle, SB_CTL, low, value, TRUE); break; case 'L': temp = slot_value(item, s_max_value); high = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MAX; SetScrollRange(di.itemHandle, SB_CTL, value, high, TRUE); break; } } set_slot_value(item, slot, cvfixnum((FIXTYPE) value)); temp = slot_value(item, s_min_value); low = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MIN; temp = slot_value(item, s_max_value); high = fixp(temp) ? (int) getfixnum(temp) : SCROLL_MAX; temp = slot_value(item, s_value); value = (fixp(temp)) ? (int) getfixnum(temp) : low; if (value < low || value > high) set_slot_value(item, s_value, cvfixnum((FIXTYPE) low)); } return(slot_value(item, slot)); } LVAL DialogScrollItemValue(LVAL item, int set, int value) { return(scroll_item_value(item, set, value, 'V')); } LVAL DialogScrollItemMax(LVAL item, int set, int value) { return(scroll_item_value(item, set, value, 'H')); } LVAL DialogScrollItemMin(LVAL item, int set, int value) { return(scroll_item_value(item, set, value, 'L')); } static Point ListItemDims(LVAL item) { LVAL listData = slot_value(item, s_list_data); Point sz; if (seqp(listData)) { sz.v = (short) seqlen(listData); sz.h = 1; } else if (matrixp(listData)) { sz.v = numrows(listData); sz.h = numcols(listData); } else xlerror("this form of data is not yet supported", listData); return(sz); } static void InstallListItem(HWND theDialog, LVAL item) { HANDLE hd; DialogItemData *data; DialogData *dialogData; HWND theItem; int itemIndex, columns, n, m, i, j, k; Point loc, size, csz, lsz; LVAL listData, next, temp; BOOL vscroll, hscroll; DWORD flags; char *s; csz = AvCharSize(LIST_USE_LEADING); csz.v += REAL_LIST_ITEM_PAD; loc = ListToPoint(slot_value(item, s_location)); size = ListToPoint(slot_value(item, s_size)); xlsave1(listData); listData = slot_value(item, s_list_data); lsz = ListItemDims(item); n = lsz.v; m = lsz.h; temp = slot_value(item, s_columns); if (! fixp(temp) || getfixnum(temp) < 1) columns = 1; else columns = (int) getfixnum(temp); hscroll = (columns < m) ? TRUE : FALSE; vscroll = (n * csz.v > size.v - ((hscroll) ? GetSystemMetrics(SM_CYHSCROLL) : 0)) ? TRUE : FALSE; flags = WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT; if (hscroll) flags |= WS_HSCROLL; if (vscroll) flags |= WS_VSCROLL; if (m > 1) flags |= LBS_MULTICOLUMN; hd = GETDIALOGDATA(theDialog); dialogData = (DialogData *) GlobalLock(hd); check_lock(dialogData); itemIndex = (dialogData->count)++; theItem = CreateWindow("listbox", NULL, flags, loc.h, loc.v, size.h, size.v, (HWND) theDialog, (HMENU) (itemIndex + ITEM_INDEX_BASE), hInst, NULL); check_alloc(theItem); SendMessage(theItem,WM_SETFONT,(WPARAM) GetStockObject(DIALOG_FONT),0); ListBox_SetColumnWidth(theItem, LIST_COL_CHARS * csz.h); if (darrayp(listData)) listData = getdarraydata(listData); else if (listp(listData)) listData = coerce_to_tvec(listData, s_true); SetWindowRedraw(theItem, FALSE); for (j = 0; j < m; j++) { for (i = 0, k = j; i < n; i++, k += m) { next = gettvecelement(listData, k); s = (stringp(next)) ? (char *) getstring(next) : ""; strcpy(buf, s); truncateListEntry(buf); if (ListBox_AddString(theItem, buf) < 0) xlfail("list allocation failed"); } } SetWindowRedraw(theItem, TRUE); data = GETITEMDATA(dialogData); data[itemIndex].type = LIST_ITEM; data[itemIndex].itemNumber = itemIndex; data[itemIndex].itemHandle = theItem; data[itemIndex].object = item; GlobalUnlock(hd); xlpop(); #ifdef WIN32 SetWindowLong(theItem, GWL_WNDPROC, (LPARAM)CustomListProc); #endif /* WIN32 */ } void DialogListGetDefaultSize(LVAL item, int *pwidth, int *pheight) { LVAL columns = slot_value(item, s_columns); LVAL data = slot_value(item, s_list_data); Point csz, sz; csz = AvCharSize(LIST_USE_LEADING); sz.h = LIST_COL_CHARS * (short) getfixnum(columns); if (seqp(data)) sz.v = (short) seqlen(data); else if (matrixp(data)) sz.v = (int) numrows(data); csz.v += REAL_LIST_ITEM_PAD; sz.h *= csz.h; sz.v *= csz.v; if (sz.v > csz.v * MAX_LIST_ROWS) { sz.v = csz.v * MAX_LIST_ROWS; sz.h += GetSystemMetrics(SM_CXVSCROLL); } if (matrixp(data) && numrows(data) > getfixnum(columns)) sz.v += GetSystemMetrics(SM_CYHSCROLL); if (pwidth != NULL) *pwidth = sz.h; if (pheight != NULL) *pheight = sz.v; } LVAL DialogListItemSelection(LVAL item, int set, LVAL index) { LVAL result; DialogItemData di; Point lsz, cell; int i; BOOL twodim; lsz = ListItemDims(item); if (FindItemObjectData(item, &di)) { if (set) { if (index == NIL) i = -1; else if (fixp(index)) i = (int) getfixnum(index); else if (consp(index)) { cell = ListToPoint(index); i = cell.h + cell.v * lsz.h; } else xlbadtype(index); if (i < 0 || i >= lsz.h * lsz.v) i = -1; (void) ListBox_SetCurSel(di.itemHandle, i); } twodim = matrixp(slot_value(item, s_list_data)) ? TRUE : FALSE; i = (int) ListBox_GetCurSel(di.itemHandle); if (i == LB_ERR || lsz.h <= 0) result = NIL; else if (twodim) { cell.h = i % lsz.h; cell.v = i / lsz.h; result = integer_list_2(cell.h, cell.v); } else result = cvfixnum((FIXTYPE) i); } else result = NIL; return(result); } void DialogListItemSetText(LVAL item, LVAL index, char *text) { DialogItemData di; Point lsz, cell; int i, j; lsz = ListItemDims(item); if (FindItemObjectData(item, &di)) { if (fixp(index)) i = (int) getfixnum(index); else if (consp(index)) { cell = ListToPoint(index); i = cell.h + cell.v * lsz.h; } else xlbadtype(index); if (i >= 0 && i < lsz.h * lsz.v) { j = ListBox_GetCurSel(di.itemHandle); (void) ListBox_DeleteString(di.itemHandle, i); (void) ListBox_InsertString(di.itemHandle, i, text); (void) ListBox_SetCurSel(di.itemHandle, j); } } } LVAL DialogGetModalItem(LVAL dialog) { HWND theDialog; LVAL item, oldModalItem; BOOL oldInModalDialog; MSG msg; theDialog = GETDIALOGADDRESS(dialog); if (theDialog == NULL) xlfail("the dialog is not visible"); oldModalItem = ModalItem; oldInModalDialog = InModalDialog; ModalItem = NIL; InModalDialog = TRUE; while (ModalItem == NIL && GetMessage(&msg, /*theDialog*/NULL, 0, 0)) { if(! TranslateMDISysAccel(hWndClient, &msg) && ! TranslateAccelerator(hWndFrame, hAccel, &msg)) { TTYFlushOutput(); TranslateMessage(&msg); DispatchMessage(&msg); SetActiveWindow(theDialog); } } item = ModalItem; ModalItem = oldModalItem; InModalDialog = oldInModalDialog; if (item == NIL) item = slot_value(dialog, s_default_button); return(item); } void DialogSetDefaultButton(LVAL dialog, LVAL item) { HANDLE hd; DialogData *dd; DialogItemData di; HWND theDialog; if (item != NIL && ! button_item_p(item)) xlerror("not a button item", item); set_slot_value(dialog, s_default_button, item); theDialog = GETDIALOGADDRESS(dialog); if (theDialog != NULL) { hd = GETDIALOGDATA(theDialog); dd = (DialogData *) GlobalLock(hd); check_lock(dd); if (FindItemData(theDialog, ITEM_INDEX_BASE + dd->dflt, &di)) { dd->dflt = -1; Button_SetStyle(di.itemHandle, BS_PUSHBUTTON, TRUE); } if (item != NIL && FindItemObjectData(item, &di)) { dd->dflt = di.itemNumber; Button_SetStyle(di.itemHandle, BS_DEFPUSHBUTTON, TRUE); SetFocus(di.itemHandle); } GlobalUnlock(hd); } } #ifdef WIN32 static void DialogDoDefaultButton(LVAL dialog) { HANDLE hd; DialogData *dd; DialogItemData di; HWND theDialog; LVAL item; item = slot_value(dialog, s_default_button); if (item != NIL && ! button_item_p(item)) xlerror("not a button item", item); theDialog = GETDIALOGADDRESS(dialog); if (theDialog != NULL) { hd = GETDIALOGDATA(theDialog); dd = (DialogData *) GlobalLock(hd); check_lock(dd); if (FindItemData(theDialog, ITEM_INDEX_BASE + dd->dflt, &di)) dd->dflt = -1; if (item != NIL && FindItemObjectData(item, &di)) { HWND hwndDefault = di.itemHandle; if (IsWindow(hwndDefault)) PostMessage(hwndDefault, BM_CLICK, 0, 0); } GlobalUnlock(hd); } } #endif /* WIN32 */ #ifdef DODO Add keyboard support: subclass all items to handle tabs handle return as hitting default item #endif DODO