/* * SETUP.C * * Copyright (C) 1990 Microsoft Corporation. * * Edit setups dialog box and support functions. */ /* Revision history: March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr) */ #include "preclude.h" #include #include #include #include #include "hack.h" #include "midimap.h" #include "midi.h" #include #include "extern.h" #include "stdio.h" #include "stdarg.h" #if defined(WIN32) #define _based(x) #endif //WIN32 BOOL FAR PASCAL _loadds FSetupEnumPortsFunc(LPSTR, LPSTR, UINT, HWND, LPSTR); #define PAL_SHOW 0 // show active line #define PAL_HIDE 1 // hide active line #define PSF_REDRAW 0x0001 // redraw where line used to be #define PSF_SHOWIFHIDDEN 0x0002 // show line if hidden #define BTN3S_UNCHECK 0 // uncheck a 3-state button #define BTN3S_CHECK 1 // check a 3-state button #define BTN3S_GRAY 2 // gray a 3-state button #define DEF_SETUP_ROWS 16 // number of default setup rows static HGLOBAL hSetup; // Setup handle static HWND hPortList, // invalid port list box ctrl handle hPortCombo, // port combo-box ctrl handle hPatchCombo; // patch combo-box ctrl handle static UINT nPorts; // number of ports available static int nPatches, // number of user-defined patchmaps iOldPos, // old position of active edit line xArrowOffset; // arrow control positional offset static SZCODE aszNull[] = ""; static SZCODE aszSetupNumFormat[] = "%3d"; #if DBG void FAR cdecl dprintf(LPSTR szFormat, ...) { char ach[128]; va_list va; int s,d; va_start(va, szFormat); s = vsprintf (ach, szFormat, va); va_end(va); #if 0 lstrcat(ach,"\n"); s++; #endif for (d=sizeof(ach)-1; s>=0; s--) { if ((ach[d--] = ach[s]) == '\n') ach[d--] = '\r'; } OutputDebugString("MIDI: "); OutputDebugString(ach+d+1); } #else #define dprintf if (0) ((int (*)(char *, ...)) 0) #endif //DBG static BOOL NEAR PASCAL FHasInvalidPort( void) { SETUP FAR* lpSetup; WORD wNumDevs; int i; wNumDevs = (WORD)midiOutGetNumDevs(); // dprintf("numDevs = %d\n", wNumDevs); lpSetup = (SETUP FAR*)GlobalLock(hSetup); for (i = 0; i < 16; i++) { // dprintf("device id[%d]=%d\n",i,lpSetup->channels[i].wDeviceID); if ((lpSetup->channels[i].wDeviceID != LOWORD(MIDI_MAPPER)) && (lpSetup->channels[i].wDeviceID >= wNumDevs)) break; } GlobalUnlock(hSetup); return (i < 16); } /* FHasInvalidPort */ static int PASCAL ISetupSave( HWND hdlg, BOOL bQuery) { SETUP FAR* lpSetup; MMAPERR mmaperr; int iRet = 0; // choose a value not IDCANCEL or IDYES if (bQuery) if ((iRet = QuerySave()) != IDYES) return iRet; if (FHasInvalidPort()) if (!InvalidPortMsgBox(hdlg)) return IDCANCEL; lpSetup = (SETUP FAR*)GlobalLock(hSetup); mmaperr = mapWrite(MMAP_SETUP, lpSetup); GlobalUnlock(hSetup); if (mmaperr != MMAPERR_SUCCESS) { VShowError(hdlg, mmaperr); return IDCANCEL; } Modify(FALSE); if (fNew) fNew = FALSE; return iRet; } /* ISetupSave */ /* * VSetupEditMsg * * This function deals with EN_UPDATE and EN_ACTIVATE messages sent * to the channel number edit control through the WM_COMMAND message. */ static void PASCAL VSetupEditMsg( HWND hdlg, WORD NotifCode) { SETUP FAR* lpSetup; int i; LPWORD lpwChan; WORD wChan; BOOL bTranslate; switch (NotifCode) { case EN_UPDATE: lpSetup = (SETUP FAR*)GlobalLock(hSetup); lpwChan = &lpSetup->channels[iVertPos + iCurPos].wChannel; i = GetDlgItemInt(hdlg, ID_SETUPEDIT, &bTranslate, FALSE); if (i > 0 && i <= 16) { if (*lpwChan != (BYTE)(i - 1)) { *lpwChan = (BYTE)(i - 1); Modify(TRUE); } } else { char aszMessage[256]; char aszTitle[32]; // may want to experiment with EM_UNDO here. LoadString(hLibInst, IDS_INVALIDDESTINATION, aszMessage, sizeof(aszMessage)); LoadString(hLibInst, IDS_USERERROR, aszTitle, sizeof(aszTitle)); MessageBox(hdlg, aszMessage, aszTitle, MB_ICONEXCLAMATION | MB_OK); SetDlgItemInt(hdlg, ID_SETUPEDIT, *lpwChan + 1, FALSE); } GlobalUnlock(hSetup); break; case EN_ACTIVATE: lpSetup = (SETUP FAR*)GlobalLock(hSetup); wChan = lpSetup->channels[iVertPos + iCurPos].wChannel; GlobalUnlock(hSetup); SetDlgItemInt(hdlg, ID_SETUPEDIT, wChan + 1, FALSE); break; } } /* VSetupEditMsg */ /* * VSetupActiveChan * * This function controls the checked/unchecked/grayed state of the 'Active' * button for a specific channel. If the function is being grayed, it will * be disabled as well. */ static void NEAR PASCAL VSetupActiveChan( int iPos, LPDWORD lpdwFlags, UINT uCheck) { HWND hCheck; BOOL fEnable; if (lpdwFlags) if (uCheck == BTN3S_CHECK) *lpdwFlags |= MMAP_ACTIVE; else *lpdwFlags &= ~MMAP_ACTIVE; hCheck = GetDlgItem(hWnd, ID_SETUPCHECK + iPos); if ((UINT)SendMessage(hCheck, BM_GETCHECK, (WPARAM)0, (LPARAM)0) != uCheck) SendMessage(hCheck, BM_SETCHECK, (WPARAM)uCheck, (LPARAM)0); fEnable = (uCheck != BTN3S_GRAY); if (fEnable != IsWindowEnabled(hCheck)) EnableWindow(hCheck, fEnable); } /* VSetupActiveChan */ /* * VSetupComboMsg * * This function deals with the CBN_ACTIVATE and CBN_SELCHANGE messages sent * to the port or patch combo boxes through the WM_COMMAND message. */ static void NEAR PASCAL VSetupComboMsg( HWND hdlg, UINT id, WORD NotifCode) { HWND hCombo = GetDlgItem(hdlg, id); SETUP FAR* lpSetup; CHANNEL FAR* lpChannel; UINT uIdx; char szBuf[MAXPNAMELEN]; if (NotifCode != CBN_ACTIVATE && NotifCode != CBN_SELCHANGE) return; lpSetup = (SETUP FAR*)GlobalLock(hSetup); lpChannel = &lpSetup->channels[iVertPos + iCurPos]; switch (NotifCode) { case CBN_ACTIVATE: uIdx = MMAP_ID_NOPORT; // if its a port combo box message if (id == ID_SETUPPORTCOMBO) if (lpChannel->wDeviceID != MMAP_ID_NOPORT) uIdx = lpChannel->wDeviceID; else uIdx = nPorts; // otherwise its a patch combo box message else if (lpChannel->dFlags & MMAP_PATCHMAP) uIdx = ComboLookup(hCombo, lpChannel->aszPatchName); else uIdx = nPatches; SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0); break; case CBN_SELCHANGE: GetWindowText(hCombo, szBuf, MAXPNAMELEN); // if we're dealing with a port combo message if (id == ID_SETUPPORTCOMBO) { // get the index of the newly selected port uIdx = (UINT)SendMessage(hCombo, CB_GETCURSEL, (WPARAM)NULL, (LPARAM)0); // if it's the same as old index, we don't care if (uIdx == lpChannel->wDeviceID) break; // if it's the last port index, it's the[none] entry if (uIdx == (UINT)nPorts) { // set id to bogus port value lpChannel->wDeviceID = MMAP_ID_NOPORT; // deactivate the channel VSetupActiveChan(iCurPos, &lpChannel->dFlags, BTN3S_GRAY); } else { // ok so it's not the[none] entry // if it used to be[none], activate channel if (lpChannel->wDeviceID == MMAP_ID_NOPORT) VSetupActiveChan(iCurPos, &lpChannel->dFlags, BTN3S_CHECK); // set the id to the new index lpChannel->wDeviceID = (WORD)uIdx; } Modify(TRUE); } else { if (!lstrcmpi(szBuf, lpChannel->aszPatchName)) break; lstrcpy(lpChannel->aszPatchName, szBuf); if (!lstrcmpi(szBuf, szNone)) lpChannel->dFlags &= ~MMAP_PATCHMAP; else lpChannel->dFlags |= MMAP_PATCHMAP; Modify(TRUE); } break; } GlobalUnlock(hSetup); } /* VSetupComboMsg */ static void NEAR PASCAL VSetupActiveLine( UINT uCase, UINT uFlags) { static const UINT uDefFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER; switch (uCase) { case PAL_SHOW: if (!fHidden) return; uFlags |= SWP_SHOWWINDOW; fHidden = FALSE; break; case PAL_HIDE: if (fHidden) return; uFlags |= SWP_HIDEWINDOW; fHidden = TRUE; break; } uFlags |= uDefFlags; SetWindowPos(hEdit, NULL, 0L, 0L, 0L, 0L, uFlags); SetWindowPos(hArrow, NULL, 0L, 0L, 0L, 0L, uFlags); SetWindowPos(hPortCombo, NULL, 0L, 0L, 0L, 0L, uFlags); SetWindowPos(hPatchCombo, NULL, 0L, 0L, 0L, 0L, uFlags); if (uCase == PAL_SHOW) SetFocus(hEdit); } /* VSetupActiveLine */ static void NEAR PASCAL VSetupSetFocus( HWND hdlg, UINT uFlags, int xPos) { HWND hOldCheck; HWND hNewCheck; RECT rc; DWORD dwFlags; int yPos = rcBox.top + iCurPos * yChar; // change tabstop flag on new checkbox hNewCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iCurPos); dwFlags = (DWORD)GetWindowLong(hNewCheck, GWL_STYLE); dwFlags |= WS_TABSTOP; SetWindowLong(hNewCheck, GWL_STYLE, dwFlags); // set mnemonic on new window SetWindowText(hNewCheck, aszSourceMnumonic); // take the tabstop away from the old checkbox if it exists if (iOldPos > -1) { hOldCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos); dwFlags = (DWORD)GetWindowLong(hOldCheck, GWL_STYLE); dwFlags &= ~(DWORD)WS_TABSTOP; SetWindowLong(hOldCheck, GWL_STYLE, dwFlags); // take away mnemonic from old window SetWindowText(hOldCheck, aszNull); } iOldPos = iCurPos; GetWindowRect(hEdit, &rc); SetWindowPos(hEdit, NULL, rgxPos[1], yPos, 0L, 0L, SWP_NOZORDER | SWP_NOSIZE); VSetupEditMsg(hdlg, EN_ACTIVATE); // UpdateWindow(hEdit); SetWindowPos(hArrow, NULL, rgxPos[1] + xArrowOffset, yPos, 0L, 0L, SWP_NOZORDER | SWP_NOSIZE); SetWindowPos(hPortCombo, NULL, rgxPos[2], yPos, 0L, 0L, SWP_NOZORDER | SWP_NOSIZE); VSetupComboMsg(hdlg, ID_SETUPPORTCOMBO, CBN_ACTIVATE); SetWindowPos(hPatchCombo, NULL, rgxPos[3], yPos, 0L, 0L, SWP_NOZORDER | SWP_NOSIZE); VSetupComboMsg(hdlg, ID_SETUPPATCHCOMBO, CBN_ACTIVATE); if ((fHidden) && (uFlags & PSF_SHOWIFHIDDEN)) { VSetupActiveLine(PAL_SHOW, 0L); UpdateWindow(hArrow); UpdateWindow(hPortCombo); UpdateWindow(hPatchCombo); } // ValidateRect(hdlg, NULL); if (uFlags & PSF_REDRAW && rc.right) { ScreenToClient(hdlg, (LPPOINT)&rc); ScreenToClient(hdlg, (LPPOINT)&rc + 1); rc.right = rcBox.right + 1; InvalidateRect(hdlg, &rc, FALSE); UpdateWindow(hdlg); } if (!xPos) return; if (xPos < rgxPos[2]) { SetFocus(hEdit); #if defined(WIN16) SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767)); #else SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); #endif //WIN16 } else if (xPos < rgxPos[3]) SetFocus(hPortCombo); else if (xPos < rgxPos[4]) SetFocus(hPatchCombo); } /* VSetupSetFocus */ /* * VSetupSize */ static void PASCAL VSetupSize( HWND hdlg, BOOL fMaximize) { RECT rcOK; RECT rc3S; RECT rcWnd; LONG lDBU; UINT xBU; UINT yBU; int xButton; int xCenter; int yTopMar; int yBotMar; int yLeftOver; int yMiniBotMar; int i; lDBU = GetDialogBaseUnits(); xBU = LOWORD(lDBU); yBU = HIWORD(lDBU); // get the rectangle of the OK button GetClientRect(GetDlgItem(hdlg, IDOK), &rcOK); // get x-extent of button xButton = rcOK.right - rcOK.left; // top margin is 2 characters yTopMar = (16 * yBU) / 8 - 6; // cookie land // bottom margin is 2 * minimum bottom margin dialog units + // height of button in pixels yBotMar = (VERTMARGIN * 2 *yBU) / 8 + rcOK.bottom - rcOK.top; if (fMaximize) { // get the rectangle of a 3-state button GetClientRect(GetDlgItem(hdlg, ID_SETUPCHECK), &rc3S); SetWindowPos(hdlg, NULL, 0L, 0L, rcBox.right - rcBox.left + (rc3S.right - rc3S.left) + (HORZMARGIN * 3 * xBU) / 4 + (GetSystemMetrics(SM_CXDLGFRAME) + 1) * 2, (DEF_SETUP_ROWS * 10 * yBU) / 8 + yTopMar + yBotMar + GetSystemMetrics(SM_CYCAPTION) + (GetSystemMetrics(SM_CYDLGFRAME) + 1) * 2, SWP_NOZORDER | SWP_NOMOVE); } // get the x and y extents of the client rectangle GetClientRect(hdlg, &rcWnd); xClient = rcWnd.right - rcWnd.left; yClient = rcWnd.bottom - rcWnd.top; // yChar is the height of one row in pixels - 1 yChar = (10 * yBU) / 8 - 1; // xChar is the average width of a character xChar = xBU; // yBox is the room we actually have to display setup rows yBox = yClient - yTopMar - yBotMar; // nLines is the number of setup rows we can display nLines = min(16, yBox / yChar); // yLeftOver is how many pixels are left over yLeftOver = yBox - nLines * yChar; // add half the leftovers to the top margin yTopMar += yLeftOver / 2; // calculate scroll bar maximum and position iVertMax = max(0, 16 - nLines); iVertPos = min(iVertMax, iVertPos); // rcBox is the box of rows and columns inside the client area SetRect(&rcBox, rcBox.left, yTopMar, rcBox.right, yTopMar + nLines * yChar); // xCenter is used to center the OK and CANCEL buttons horizontally xCenter = (rcBox.right - rcBox.left - xButton * 3) / 4; // yMiniBotMar is the spacing above and below the button yMiniBotMar = (VERTMARGIN * yBU) / 8 + yLeftOver / 4; SetWindowPos(GetDlgItem(hdlg, IDOK), NULL, rcBox.left + xCenter, rcBox.bottom + yMiniBotMar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(GetDlgItem(hdlg, IDCANCEL), NULL, rcBox.left + xButton + xCenter * 2, rcBox.bottom + yMiniBotMar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(GetDlgItem(hdlg, IDH_DLG_MIDI_SETUPEDIT), NULL, rcBox.left + xButton * 2 + xCenter * 3, rcBox.bottom + yMiniBotMar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); // this loop could be optimized // then again, so could the u.s. judicial system for (i = 0; i < 16; i++, yTopMar += yChar) { HWND hCheck; hCheck = GetDlgItem(hdlg, ID_SETUPCHECK + i); if (i < nLines) { SetWindowPos(hCheck, NULL, rcBox.right + (HORZMARGIN * xBU) / 4, yTopMar + 3, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); ShowWindow(hCheck, SW_SHOWNORMAL); } else ShowWindow(hCheck, SW_HIDE); } if (iCurPos >= 0 && iCurPos < nLines) VSetupSetFocus(hdlg, PSF_SHOWIFHIDDEN, 1); else VSetupActiveLine(PAL_HIDE, SWP_NOREDRAW); } /* VSetupSize */ static MMAPERR PASCAL MmaperrInitNew(void) { SETUP FAR* lpSetup; WORD wChan; if ((hSetup = GlobalAlloc(GHND, (DWORD)sizeof(SETUP))) == NULL) return MMAPERR_MEMORY; lpSetup = (SETUP FAR*)GlobalLock(hSetup); lstrcpy(lpSetup->aszSetupName, szCurrent); lstrcpy(lpSetup->aszSetupDescription, szCurDesc); for (wChan = 0; wChan < 16; wChan++) { lpSetup->channels[wChan].wChannel = wChan; lpSetup->channels[wChan].wDeviceID = MMAP_ID_NOPORT; lstrcpy(lpSetup->channels[wChan].aszPatchName, szNone); } GlobalUnlock(hSetup); return MMAPERR_SUCCESS; } /* MmaperrInitNew */ /* * VSetupEnumPorts * * Enumerate available port names and throw them in a combo box. */ static void PASCAL VSetupEnumPorts( void) { MIDIOUTCAPS moCaps; UINT i; nPorts = midiOutGetNumDevs(); for (i = 0; i < nPorts; i++) { midiOutGetDevCaps(i, &moCaps, sizeof(MIDIOUTCAPS)); SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)moCaps.szPname); } } /* VSetupEnumPorts */ /* * MmaperrEnumPatches * * This function calls mapEnumerate to enumerate all the user-defined * patchmaps into a combo box. */ static MMAPERR NEAR PASCAL MmaperrEnumPatches(void) { MMAPERR mmaperr; mmaperr = mapEnumerate(MMAP_PATCH, EnumFunc, MMENUM_BASIC, hPatchCombo, NULL); if (mmaperr != MMAPERR_SUCCESS) return mmaperr; nPatches = (int)(LONG)SendMessage(hPatchCombo, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0); SendMessage(hPatchCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone); return MMAPERR_SUCCESS; } /* MmaperrEnumPatches */ static BOOL NEAR PASCAL FInitSetup( HWND hdlg) { SETUP FAR* lpSetup; LONG lDBU; UINT xBU; UINT yBU; UINT xWidth; // width of current column UINT xEdit; // width of edit controls UINT yEdit; // height of edit/arrow controls UINT xCombo; // width of combo boxes UINT yCombo; // height of combo boxes UINT wCheck; char szCaption[80]; char szCaptionFormat[80]; MMAPERR mmaperr; int i; if (!fNew) { if ((hSetup = GlobalAlloc(GHND, sizeof(SETUP))) == NULL) { mmaperr = MMAPERR_MEMORY; exit00: VShowError(hdlg, mmaperr); return FALSE; } } else if ((mmaperr = MmaperrInitNew()) != MMAPERR_SUCCESS) goto exit00; fHidden = FALSE; iVertPos = 0; iCurPos = 0; nLines = 0; // necessary? nPatches = 0; nPorts = 0; hPortList = GetDlgItem(hdlg, ID_SETUPPORTLIST); hEdit = GetDlgItem(hdlg, ID_SETUPEDIT); hArrow = GetDlgItem(hdlg, ID_SETUPARROW); hPortCombo = GetDlgItem(hdlg, ID_SETUPPORTCOMBO); hPatchCombo = GetDlgItem(hdlg, ID_SETUPPATCHCOMBO); if (fReadOnly) { EnableWindow(GetDlgItem(hdlg,IDOK),FALSE); SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0); } lDBU = GetDialogBaseUnits(); xBU = LOWORD(lDBU); yBU = HIWORD(lDBU); xEdit = (40 * xBU) / 4; // 10 chars wide yEdit = (10 * yBU) / 8; // 10 is a magic cookie xCombo = (64 * xBU) / 4; // 16 characters long yCombo = (46 * yBU) / 8; // 46 is a magic cookie rcBox.left = (HORZMARGIN * xBU) / 4; rcBox.right = rcBox.left; rgxPos[0] = rcBox.right; rcBox.right += xEdit; rgxPos[1] = rcBox.right; xWidth = xEdit; SetWindowPos(hEdit, NULL, 0L, 0L, xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE); // set global arrow control offset to proper position rcBox.right += xArrowOffset = xWidth - 1; // width of dst channel arrow control xWidth = (10 * xBU) / 4; SetWindowPos(hArrow, NULL, 0L, 0L, xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE); rcBox.right += xWidth - 1; rgxPos[2] = rcBox.right; xWidth = (80 * xBU) / 4; // 20 characters long SetWindowPos(hPortCombo, NULL, 0L, 0L, xWidth, yCombo, SWP_NOZORDER | SWP_NOMOVE); rcBox.right += xWidth - 1; rgxPos[3] = rcBox.right; xWidth = xCombo; SetWindowPos(hPatchCombo, NULL, 0L, 0L, xWidth, yCombo, SWP_NOZORDER | SWP_NOMOVE); rcBox.right += xWidth - 1; rgxPos[4] = rcBox.right; if (!nPorts) VSetupEnumPorts(); lpSetup = (SETUP FAR*)GlobalLock(hSetup); if (!nPatches) if ((mmaperr = MmaperrEnumPatches()) != MMAPERR_SUCCESS) { exit01: GlobalUnlock(hSetup); GlobalFree(hSetup); goto exit00; } if (!fNew) { mmaperr = mapReadSetup(szCurrent, lpSetup); if (mmaperr == MMAPERR_INVALIDPORT) { if (!InvalidPortMsgBox(hdlg)) { GlobalUnlock(hSetup); GlobalFree(hSetup); return FALSE; } mmaperr = mapEnumerate( MMAP_PORTS , FSetupEnumPortsFunc , MMENUM_BASIC , NULL , (LPSTR)szCurrent ); } if (mmaperr != MMAPERR_SUCCESS){ goto exit01; } if (lstrcmp(lpSetup->aszSetupDescription, szCurDesc)) { lstrcpy(lpSetup->aszSetupDescription, szCurDesc); fNew = TRUE; } } SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone); for (i = 0; i < 16; i++) { // check a 3-state button if the channel is active, or gray // it if the channel is not mapped to a port if (lpSetup->channels[i].wDeviceID == MMAP_ID_NOPORT) wCheck = BTN3S_GRAY; else if (lpSetup->channels[i].dFlags & MMAP_ACTIVE) wCheck = BTN3S_CHECK; else continue; VSetupActiveChan(i, 0L, wCheck); } GlobalUnlock(hSetup); LoadString(hLibInst, IDS_SETUPS ,szCaptionFormat, sizeof(szCaptionFormat)); wsprintf(szCaption, szCaptionFormat, (LPSTR)szCurrent); SetWindowText(hWnd, szCaption); SendMessage(GetDlgItem(hdlg, ID_SETUPDESTMNEM), WM_SETFONT, (WPARAM)hFont, (LPARAM)0); SendMessage(GetDlgItem(hdlg, ID_SETUPPORTMNEM), WM_SETFONT, (WPARAM)hFont, (LPARAM)0); SendMessage(GetDlgItem(hdlg, ID_SETUPPATCHMNEM), WM_SETFONT, (WPARAM)hFont, (LPARAM)0); VSetupSize(hdlg, TRUE); SetWindowPos(GetDlgItem(hdlg, ID_SETUPDESTMNEM), NULL, rgxPos[1], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(GetDlgItem(hdlg, ID_SETUPPORTMNEM), NULL, rgxPos[2], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(GetDlgItem(hdlg, ID_SETUPPATCHMNEM), NULL, rgxPos[3], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER); Modify(fNew); return TRUE; } /* FInitSetup */ static void PASCAL VSetupButtonDown( HWND hdlg, LONG lParam) { int x = LOWORD(lParam); int y = HIWORD(lParam); int iPos; UINT uFlags; if (x < rcBox.left || x > rcBox.right) return; if (y < rcBox.top || y > rcBox.bottom) return; if ((iPos = min(nLines - 1, (y - rcBox.top) / yChar)) == iCurPos) return; if (iCurPos >= 0 && iCurPos < nLines) { uFlags = PSF_REDRAW; SendMessage(hPortCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0); SendMessage(hPatchCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0); UpdateWindow(hdlg); } else uFlags = PSF_SHOWIFHIDDEN; iCurPos = iPos; VSetupSetFocus(hdlg, uFlags, x); } /* VSetupButtonDown */ static void PASCAL VSetupPaint( HWND hdlg) { HPEN hPen; // previous pen to restore SETUP FAR* lpSetup; CHANNEL FAR* lpChannel; PAINTSTRUCT ps; // from BeginPaint RECT rcText; UINT uDev; int i; // loop counter int iVert; int nBegin; // first row to repaint int nEnd; // last row to repaint int iLeft; // left of invalid area int iTop; // top of invalid area int iBottom; // bottom of invalid area char szBuf[MAXPNAMELEN]; // uses GLOBAL hFont - Lord knows why. // uses GLOBAL rcBox = clipping rectangle??? BeginPaint(hdlg, &ps); if (!ps.rcPaint.bottom) { // bottom==0 => area must be empty exit00: EndPaint(hdlg, &ps); return; } hPen = SelectObject(ps.hdc, GetStockObject(BLACK_PEN)); hFont = SelectObject(ps.hdc, hFont); SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkMode(ps.hdc, TRANSPARENT); if (ps.rcPaint.top < rcBox.top) { // need to paint top headings? iVert = yChar; TextOut(ps.hdc, 11, iVert, aszSourceChannel, lstrlen(aszSourceChannel)); SetRect(&rcText, rcBox.right + 2, yChar, 0, 0); DrawText(ps.hdc, aszActive, -1, &rcText, DT_LEFT | DT_NOCLIP); } // calculate top and bottom y coordinates of invalid area iTop = max(ps.rcPaint.top, rcBox.top); // if top is below the box, forget about painting if (iTop > rcBox.bottom) { exit01: hFont = SelectObject(ps.hdc, hFont); // restore hPen = SelectObject(ps.hdc, hPen); // restore goto exit00; } iBottom = min(ps.rcPaint.bottom, rcBox.bottom); // calculate left x coordinate of invalid area iLeft = max(ps.rcPaint.left, rcBox.left); // calculate beginning and ending data row to be repainted nBegin = max(0, (iTop - rcBox.top) / yChar); nEnd = min(nLines, (iBottom - rcBox.top) / yChar); // draw vertical lines of the box for (i = 0; i < 5; i++) { MMoveTo(ps.hdc, rgxPos[i], iTop); LineTo(ps.hdc, rgxPos[i], iBottom + 1); } // vertical position of first line we have to draw iVert = rcBox.top + nBegin * yChar; // lock the map lpSetup = (SETUP FAR*)GlobalLock(hSetup); // set up an optimization pointer lpChannel = &lpSetup->channels[iVertPos + nBegin]; for (i = nBegin; i <= nEnd; i++, iVert += yChar, lpChannel++) { MMoveTo(ps.hdc, iLeft, iVert); LineTo(ps.hdc, rcBox.right, iVert); if (i == nLines) break; if (iLeft < rgxPos[1]) { wsprintf(szBuf, aszSetupNumFormat, iVertPos + i + 1); TextOut(ps.hdc, rgxPos[0] + xChar, iVert + 2, szBuf, 3); } if (iLeft < rgxPos[2]) { wsprintf(szBuf, aszSetupNumFormat, lpChannel->wChannel + 1); TextOut(ps.hdc, rgxPos[1] + 2 * xChar, iVert + 2, szBuf, 3); } if (i == iCurPos) continue; if (iLeft < rgxPos[3]) { *szBuf = 0; uDev = lpChannel->wDeviceID; if (uDev == MMAP_ID_NOPORT) uDev = nPorts; if (uDev <= nPorts) { RECT sTextRect; TEXTMETRIC sTM; SendMessage(hPortCombo, CB_GETLBTEXT, uDev, (LPARAM)(LPSTR)szBuf); GetTextMetrics(ps.hdc,(LPTEXTMETRIC)&sTM); SetRect((LPRECT)&sTextRect,rgxPos[2]+2,iVert+2,rgxPos[3]-2,iVert+2+sTM.tmHeight); DrawText(ps.hdc, szBuf, -1,(LPRECT)&sTextRect ,DT_NOPREFIX|DT_LEFT|DT_SINGLELINE); } } if (iLeft < rgxPos[4]) { RECT rc; SetRect(&rc, rgxPos[3]+2, iVert, rgxPos[4]-2, iVert+yChar); DrawText(ps.hdc, lpChannel->aszPatchName, lstrlen(lpChannel->aszPatchName), &rc, DT_LEFT|DT_SINGLELINE|DT_VCENTER ); // was: // TextOut(ps.hdc, rgxPos[3] + 2, iVert + 2, lpChannel->aszPatchName, // lstrlen(lpChannel->aszPatchName)); } } GlobalUnlock(hSetup); goto exit01; } /* VSetupPaint */ static void PASCAL VSetupArrowScroll( HWND hdlg, WORD ScrollCode) { SETUP FAR* lpSetup; WORD wChan; lpSetup = (SETUP FAR*)GlobalLock(hSetup); wChan = lpSetup->channels[iVertPos + iCurPos].wChannel; GlobalUnlock(hSetup); switch (ScrollCode) { case SB_LINEDOWN: if (!wChan--) wChan = 15; break; case SB_LINEUP: if (++wChan > 15) wChan = 0; break; } SetDlgItemInt(hWnd, ID_SETUPEDIT, wChan + 1, FALSE); } /* VSetupArrowScroll */ /* * VSetupCheckMsg */ static void PASCAL VSetupCheckMsg( WORD id, WORD NotifCode) { SETUP FAR* lpSetup; CHANNEL FAR* lpChannel; if (NotifCode != BN_CLICKED) return; lpSetup = (SETUP FAR*)GlobalLock(hSetup); lpChannel = &lpSetup->channels[iVertPos + id - ID_SETUPCHECK]; if (lpChannel->wDeviceID != MMAP_ID_NOPORT) { VSetupActiveChan( id - ID_SETUPCHECK , &lpChannel->dFlags , (lpChannel->dFlags & MMAP_ACTIVE) ? BTN3S_UNCHECK : BTN3S_CHECK ); Modify(TRUE); } GlobalUnlock(hSetup); } /* VSetupCheckMsg */ BOOL FAR PASCAL _loadds SetupBox( HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { int iRet; HWND hwndCheckBox; switch (uMessage) { case WM_INITDIALOG: hWnd = hdlg; iOldPos = -1; SetFocus(GetDlgItem(hdlg, ID_SETUPEDIT)); if (!FInitSetup(hdlg)) EndDialog(hdlg, FALSE); SetFocus(hEdit); PlaceWindow(hWnd); return FALSE; case WM_COMMAND: { WORD id = LOWORD(wParam); #if defined(WIN16) WORD NotifCode = HIWORD(lParam); HWND hwnd = LOWORD(lParam); #else WORD NotifCode = HIWORD(wParam); HWND hwnd = (HWND)lParam; #endif //WIN16 switch (id) { case IDH_DLG_MIDI_SETUPEDIT: goto DoHelp; case IDOK: case IDCANCEL: if (NotifCode != BN_CLICKED) break; if (!fReadOnly && ((id == IDOK) && fModified)) { iRet = ISetupSave(hdlg, TRUE); if (iRet == IDCANCEL) break; iRet = (iRet == IDYES); } else iRet = FALSE; GlobalFree(hSetup); EndDialog(hdlg, iRet); break; case ID_SETUPGHOSTEDITFIRST: /* assume the user back-tabbed before the first * control on the current row, so jump to the * previous row (if iCurPos > 0) or the last row * (if iCurPos == 0) */ if (NotifCode != EN_SETFOCUS) break; if (iCurPos < 0) /* do nothing */ ; else if (iCurPos > 0) iCurPos--; else iCurPos = nLines - 1; VSetupSetFocus(hdlg, PSF_REDRAW, 0); hwndCheckBox = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos); if (IsWindowEnabled(hwndCheckBox)) SetFocus(hwndCheckBox); else SetFocus(hPatchCombo); break; case ID_SETUPGHOSTEDITLAST: /* assume the user forward-tabbed beyond the last * control on the current row, so jump to the * next row (if iCurPos < nLines - 1) or the first row * (if iCurPos == nLines - 1) */ if (NotifCode != EN_SETFOCUS) break; if (iCurPos < 0) /* do nothing */ ; else if (iCurPos < nLines - 1) iCurPos++; else iCurPos = 0; VSetupSetFocus(hdlg, PSF_REDRAW, 0); SetFocus(hEdit); #if defined(WIN16) SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767)); #else SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); #endif //WIN16 break; case ID_SETUPEDIT: VSetupEditMsg(hdlg, NotifCode); break; case ID_SETUPPORTCOMBO: case ID_SETUPPATCHCOMBO: VSetupComboMsg(hdlg, id, NotifCode); break; default: if ((id >= ID_SETUPCHECK) && (id < ID_SETUPCHECK + 16)) VSetupCheckMsg(id, NotifCode); else return FALSE; } break; } /* end of WM_COMMAND */ case WM_PAINT: VSetupPaint(hdlg); break; case WM_LBUTTONDOWN: VSetupButtonDown(hdlg, (LONG)lParam); break; case WM_VSCROLL: // if (HIWORD(lParam)) // in DOS this is the window ID - I don't see why we need the test // and in NT we don't have that ID anyway VSetupArrowScroll(hdlg, LOWORD(wParam)); // LOWORD(wParam) is scroll code. See cpArrow: // actually the whole of wParam is. break; case WM_CHAR: if ((LONG)lParam == 14) if (iCurPos == 15) iCurPos = 0; else iCurPos++; else if ((LONG)lParam == 16) if (!iCurPos) iCurPos = 15; else iCurPos--; else return FALSE; VSetupSetFocus(hdlg, 0L, 0L); break; case WM_CLOSE: PostMessage(hdlg, WM_COMMAND, (WPARAM)IDOK, (LPARAM)0); break; default: if (uMessage == uHelpMessage) { DoHelp: WinHelp(hWnd, szMidiHlp, HELP_CONTEXT, IDH_DLG_MIDI_SETUPEDIT); return TRUE; } else return FALSE; break; } return TRUE; } /* SetupBox */ /* * FSetupEnumPortsFunc * * This function receives port information for each channel in a setup, * determines if the port is not available in the current environment, and * if so adds it to a listbox of invalid port names. * * The types and parameters are weird because it is being forced into the straightjacket * of an enumfunc. */ BOOL FAR PASCAL _loadds FSetupEnumPortsFunc( LPSTR lpChannel, LPSTR lpPort, UINT uCase, // unused HWND hCombo, //unused LPSTR DeviceID) { SETUP FAR* lpSetup; INT Idx; if (DeviceID == (LPSTR)MMAP_ID_NOPORT) { Idx = ComboLookup(hPortCombo, lpPort); if (Idx == CB_ERR) { SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)lpPort); Idx = nPorts++; } lpSetup = (SETUP FAR*)GlobalLock(hSetup); lpSetup->channels[(WORD)(DWORD_PTR)lpChannel - 1].wDeviceID = (WORD)Idx; GlobalUnlock(hSetup); } return TRUE; } /* FSetupEnumPortsFunc */