Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1079 lines
40 KiB

  1. /*
  2. * SETUP.C
  3. *
  4. * Copyright (C) 1990 Microsoft Corporation.
  5. *
  6. * Edit setups dialog box and support functions.
  7. */
  8. /* Revision history:
  9. March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr)
  10. */
  11. #include "preclude.h"
  12. #include <windows.h>
  13. #include <string.h>
  14. #include <mmsystem.h>
  15. #include <port1632.h>
  16. #include "hack.h"
  17. #include "midimap.h"
  18. #include "midi.h"
  19. #include <cphelp.h>
  20. #include "extern.h"
  21. #include "stdio.h"
  22. #include "stdarg.h"
  23. #if defined(WIN32)
  24. #define _based(x)
  25. #endif //WIN32
  26. BOOL FAR PASCAL _loadds FSetupEnumPortsFunc(LPSTR, LPSTR, UINT, HWND, LPSTR);
  27. #define PAL_SHOW 0 // show active line
  28. #define PAL_HIDE 1 // hide active line
  29. #define PSF_REDRAW 0x0001 // redraw where line used to be
  30. #define PSF_SHOWIFHIDDEN 0x0002 // show line if hidden
  31. #define BTN3S_UNCHECK 0 // uncheck a 3-state button
  32. #define BTN3S_CHECK 1 // check a 3-state button
  33. #define BTN3S_GRAY 2 // gray a 3-state button
  34. #define DEF_SETUP_ROWS 16 // number of default setup rows
  35. static HGLOBAL hSetup; // Setup handle
  36. static HWND hPortList, // invalid port list box ctrl handle
  37. hPortCombo, // port combo-box ctrl handle
  38. hPatchCombo; // patch combo-box ctrl handle
  39. static UINT nPorts; // number of ports available
  40. static int nPatches, // number of user-defined patchmaps
  41. iOldPos, // old position of active edit line
  42. xArrowOffset; // arrow control positional offset
  43. static SZCODE aszNull[] = "";
  44. static SZCODE aszSetupNumFormat[] = "%3d";
  45. #if DBG
  46. void FAR cdecl dprintf(LPSTR szFormat, ...)
  47. {
  48. char ach[128];
  49. va_list va;
  50. int s,d;
  51. va_start(va, szFormat);
  52. s = vsprintf (ach, szFormat, va);
  53. va_end(va);
  54. #if 0
  55. lstrcat(ach,"\n");
  56. s++;
  57. #endif
  58. for (d=sizeof(ach)-1; s>=0; s--)
  59. {
  60. if ((ach[d--] = ach[s]) == '\n')
  61. ach[d--] = '\r';
  62. }
  63. OutputDebugString("MIDI: ");
  64. OutputDebugString(ach+d+1);
  65. }
  66. #else
  67. #define dprintf if (0) ((int (*)(char *, ...)) 0)
  68. #endif //DBG
  69. static BOOL NEAR PASCAL FHasInvalidPort(
  70. void)
  71. {
  72. SETUP FAR* lpSetup;
  73. WORD wNumDevs;
  74. int i;
  75. wNumDevs = (WORD)midiOutGetNumDevs();
  76. // dprintf("numDevs = %d\n", wNumDevs);
  77. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  78. for (i = 0; i < 16; i++)
  79. { // dprintf("device id[%d]=%d\n",i,lpSetup->channels[i].wDeviceID);
  80. if ((lpSetup->channels[i].wDeviceID != LOWORD(MIDI_MAPPER)) &&
  81. (lpSetup->channels[i].wDeviceID >= wNumDevs))
  82. break;
  83. }
  84. GlobalUnlock(hSetup);
  85. return (i < 16);
  86. } /* FHasInvalidPort */
  87. static int PASCAL ISetupSave(
  88. HWND hdlg,
  89. BOOL bQuery)
  90. {
  91. SETUP FAR* lpSetup;
  92. MMAPERR mmaperr;
  93. int iRet = 0; // choose a value not IDCANCEL or IDYES
  94. if (bQuery)
  95. if ((iRet = QuerySave()) != IDYES)
  96. return iRet;
  97. if (FHasInvalidPort())
  98. if (!InvalidPortMsgBox(hdlg))
  99. return IDCANCEL;
  100. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  101. mmaperr = mapWrite(MMAP_SETUP, lpSetup);
  102. GlobalUnlock(hSetup);
  103. if (mmaperr != MMAPERR_SUCCESS) {
  104. VShowError(hdlg, mmaperr);
  105. return IDCANCEL;
  106. }
  107. Modify(FALSE);
  108. if (fNew)
  109. fNew = FALSE;
  110. return iRet;
  111. } /* ISetupSave */
  112. /*
  113. * VSetupEditMsg
  114. *
  115. * This function deals with EN_UPDATE and EN_ACTIVATE messages sent
  116. * to the channel number edit control through the WM_COMMAND message.
  117. */
  118. static void PASCAL VSetupEditMsg(
  119. HWND hdlg,
  120. WORD NotifCode)
  121. {
  122. SETUP FAR* lpSetup;
  123. int i;
  124. LPWORD lpwChan;
  125. WORD wChan;
  126. BOOL bTranslate;
  127. switch (NotifCode) {
  128. case EN_UPDATE:
  129. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  130. lpwChan = &lpSetup->channels[iVertPos + iCurPos].wChannel;
  131. i = GetDlgItemInt(hdlg, ID_SETUPEDIT, &bTranslate, FALSE);
  132. if (i > 0 && i <= 16) {
  133. if (*lpwChan != (BYTE)(i - 1)) {
  134. *lpwChan = (BYTE)(i - 1);
  135. Modify(TRUE);
  136. }
  137. } else {
  138. char aszMessage[256];
  139. char aszTitle[32];
  140. // may want to experiment with EM_UNDO here.
  141. LoadString(hLibInst, IDS_INVALIDDESTINATION, aszMessage, sizeof(aszMessage));
  142. LoadString(hLibInst, IDS_USERERROR, aszTitle, sizeof(aszTitle));
  143. MessageBox(hdlg, aszMessage, aszTitle, MB_ICONEXCLAMATION | MB_OK);
  144. SetDlgItemInt(hdlg, ID_SETUPEDIT,
  145. *lpwChan + 1, FALSE);
  146. }
  147. GlobalUnlock(hSetup);
  148. break;
  149. case EN_ACTIVATE:
  150. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  151. wChan = lpSetup->channels[iVertPos + iCurPos].wChannel;
  152. GlobalUnlock(hSetup);
  153. SetDlgItemInt(hdlg, ID_SETUPEDIT, wChan + 1, FALSE);
  154. break;
  155. }
  156. } /* VSetupEditMsg */
  157. /*
  158. * VSetupActiveChan
  159. *
  160. * This function controls the checked/unchecked/grayed state of the 'Active'
  161. * button for a specific channel. If the function is being grayed, it will
  162. * be disabled as well.
  163. */
  164. static void NEAR PASCAL VSetupActiveChan(
  165. int iPos,
  166. LPDWORD lpdwFlags,
  167. UINT uCheck)
  168. {
  169. HWND hCheck;
  170. BOOL fEnable;
  171. if (lpdwFlags)
  172. if (uCheck == BTN3S_CHECK)
  173. *lpdwFlags |= MMAP_ACTIVE;
  174. else
  175. *lpdwFlags &= ~MMAP_ACTIVE;
  176. hCheck = GetDlgItem(hWnd, ID_SETUPCHECK + iPos);
  177. if ((UINT)SendMessage(hCheck, BM_GETCHECK, (WPARAM)0, (LPARAM)0) != uCheck)
  178. SendMessage(hCheck, BM_SETCHECK, (WPARAM)uCheck, (LPARAM)0);
  179. fEnable = (uCheck != BTN3S_GRAY);
  180. if (fEnable != IsWindowEnabled(hCheck))
  181. EnableWindow(hCheck, fEnable);
  182. } /* VSetupActiveChan */
  183. /*
  184. * VSetupComboMsg
  185. *
  186. * This function deals with the CBN_ACTIVATE and CBN_SELCHANGE messages sent
  187. * to the port or patch combo boxes through the WM_COMMAND message.
  188. */
  189. static void NEAR PASCAL VSetupComboMsg(
  190. HWND hdlg,
  191. UINT id,
  192. WORD NotifCode)
  193. {
  194. HWND hCombo = GetDlgItem(hdlg, id);
  195. SETUP FAR* lpSetup;
  196. CHANNEL FAR* lpChannel;
  197. UINT uIdx;
  198. char szBuf[MAXPNAMELEN];
  199. if (NotifCode != CBN_ACTIVATE && NotifCode != CBN_SELCHANGE)
  200. return;
  201. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  202. lpChannel = &lpSetup->channels[iVertPos + iCurPos];
  203. switch (NotifCode) {
  204. case CBN_ACTIVATE:
  205. uIdx = MMAP_ID_NOPORT;
  206. // if its a port combo box message
  207. if (id == ID_SETUPPORTCOMBO)
  208. if (lpChannel->wDeviceID != MMAP_ID_NOPORT)
  209. uIdx = lpChannel->wDeviceID;
  210. else
  211. uIdx = nPorts;
  212. // otherwise its a patch combo box message
  213. else if (lpChannel->dFlags & MMAP_PATCHMAP)
  214. uIdx = ComboLookup(hCombo, lpChannel->aszPatchName);
  215. else
  216. uIdx = nPatches;
  217. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
  218. break;
  219. case CBN_SELCHANGE:
  220. GetWindowText(hCombo, szBuf, MAXPNAMELEN);
  221. // if we're dealing with a port combo message
  222. if (id == ID_SETUPPORTCOMBO) {
  223. // get the index of the newly selected port
  224. uIdx = (UINT)SendMessage(hCombo,
  225. CB_GETCURSEL, (WPARAM)NULL, (LPARAM)0);
  226. // if it's the same as old index, we don't care
  227. if (uIdx == lpChannel->wDeviceID)
  228. break;
  229. // if it's the last port index, it's the[none] entry
  230. if (uIdx == (UINT)nPorts) {
  231. // set id to bogus port value
  232. lpChannel->wDeviceID = MMAP_ID_NOPORT;
  233. // deactivate the channel
  234. VSetupActiveChan(iCurPos, &lpChannel->dFlags,
  235. BTN3S_GRAY);
  236. } else {
  237. // ok so it's not the[none] entry
  238. // if it used to be[none], activate channel
  239. if (lpChannel->wDeviceID == MMAP_ID_NOPORT)
  240. VSetupActiveChan(iCurPos,
  241. &lpChannel->dFlags,
  242. BTN3S_CHECK);
  243. // set the id to the new index
  244. lpChannel->wDeviceID = (WORD)uIdx;
  245. }
  246. Modify(TRUE);
  247. } else {
  248. if (!lstrcmpi(szBuf, lpChannel->aszPatchName))
  249. break;
  250. lstrcpy(lpChannel->aszPatchName, szBuf);
  251. if (!lstrcmpi(szBuf, szNone))
  252. lpChannel->dFlags &= ~MMAP_PATCHMAP;
  253. else
  254. lpChannel->dFlags |= MMAP_PATCHMAP;
  255. Modify(TRUE);
  256. }
  257. break;
  258. }
  259. GlobalUnlock(hSetup);
  260. } /* VSetupComboMsg */
  261. static void NEAR PASCAL VSetupActiveLine(
  262. UINT uCase,
  263. UINT uFlags)
  264. {
  265. static const UINT uDefFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
  266. switch (uCase) {
  267. case PAL_SHOW:
  268. if (!fHidden)
  269. return;
  270. uFlags |= SWP_SHOWWINDOW;
  271. fHidden = FALSE;
  272. break;
  273. case PAL_HIDE:
  274. if (fHidden)
  275. return;
  276. uFlags |= SWP_HIDEWINDOW;
  277. fHidden = TRUE;
  278. break;
  279. }
  280. uFlags |= uDefFlags;
  281. SetWindowPos(hEdit, NULL, 0L, 0L, 0L, 0L, uFlags);
  282. SetWindowPos(hArrow, NULL, 0L, 0L, 0L, 0L, uFlags);
  283. SetWindowPos(hPortCombo, NULL, 0L, 0L, 0L, 0L, uFlags);
  284. SetWindowPos(hPatchCombo, NULL, 0L, 0L, 0L, 0L, uFlags);
  285. if (uCase == PAL_SHOW)
  286. SetFocus(hEdit);
  287. } /* VSetupActiveLine */
  288. static void NEAR PASCAL VSetupSetFocus(
  289. HWND hdlg,
  290. UINT uFlags,
  291. int xPos)
  292. {
  293. HWND hOldCheck;
  294. HWND hNewCheck;
  295. RECT rc;
  296. DWORD dwFlags;
  297. int yPos = rcBox.top + iCurPos * yChar;
  298. // change tabstop flag on new checkbox
  299. hNewCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iCurPos);
  300. dwFlags = (DWORD)GetWindowLong(hNewCheck, GWL_STYLE);
  301. dwFlags |= WS_TABSTOP;
  302. SetWindowLong(hNewCheck, GWL_STYLE, dwFlags);
  303. // set mnemonic on new window
  304. SetWindowText(hNewCheck, aszSourceMnumonic);
  305. // take the tabstop away from the old checkbox if it exists
  306. if (iOldPos > -1) {
  307. hOldCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos);
  308. dwFlags = (DWORD)GetWindowLong(hOldCheck, GWL_STYLE);
  309. dwFlags &= ~(DWORD)WS_TABSTOP;
  310. SetWindowLong(hOldCheck, GWL_STYLE, dwFlags);
  311. // take away mnemonic from old window
  312. SetWindowText(hOldCheck, aszNull);
  313. }
  314. iOldPos = iCurPos;
  315. GetWindowRect(hEdit, &rc);
  316. SetWindowPos(hEdit, NULL, rgxPos[1], yPos, 0L, 0L,
  317. SWP_NOZORDER | SWP_NOSIZE);
  318. VSetupEditMsg(hdlg, EN_ACTIVATE);
  319. // UpdateWindow(hEdit);
  320. SetWindowPos(hArrow, NULL, rgxPos[1] + xArrowOffset, yPos, 0L,
  321. 0L, SWP_NOZORDER | SWP_NOSIZE);
  322. SetWindowPos(hPortCombo, NULL, rgxPos[2], yPos, 0L, 0L,
  323. SWP_NOZORDER | SWP_NOSIZE);
  324. VSetupComboMsg(hdlg, ID_SETUPPORTCOMBO, CBN_ACTIVATE);
  325. SetWindowPos(hPatchCombo, NULL, rgxPos[3], yPos, 0L, 0L,
  326. SWP_NOZORDER | SWP_NOSIZE);
  327. VSetupComboMsg(hdlg, ID_SETUPPATCHCOMBO, CBN_ACTIVATE);
  328. if ((fHidden) && (uFlags & PSF_SHOWIFHIDDEN)) {
  329. VSetupActiveLine(PAL_SHOW, 0L);
  330. UpdateWindow(hArrow);
  331. UpdateWindow(hPortCombo);
  332. UpdateWindow(hPatchCombo);
  333. }
  334. // ValidateRect(hdlg, NULL);
  335. if (uFlags & PSF_REDRAW && rc.right) {
  336. ScreenToClient(hdlg, (LPPOINT)&rc);
  337. ScreenToClient(hdlg, (LPPOINT)&rc + 1);
  338. rc.right = rcBox.right + 1;
  339. InvalidateRect(hdlg, &rc, FALSE);
  340. UpdateWindow(hdlg);
  341. }
  342. if (!xPos)
  343. return;
  344. if (xPos < rgxPos[2]) {
  345. SetFocus(hEdit);
  346. #if defined(WIN16)
  347. SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
  348. #else
  349. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  350. #endif //WIN16
  351. } else if (xPos < rgxPos[3])
  352. SetFocus(hPortCombo);
  353. else if (xPos < rgxPos[4])
  354. SetFocus(hPatchCombo);
  355. } /* VSetupSetFocus */
  356. /*
  357. * VSetupSize
  358. */
  359. static
  360. void PASCAL VSetupSize(
  361. HWND hdlg,
  362. BOOL fMaximize)
  363. {
  364. RECT rcOK;
  365. RECT rc3S;
  366. RECT rcWnd;
  367. LONG lDBU;
  368. UINT xBU;
  369. UINT yBU;
  370. int xButton;
  371. int xCenter;
  372. int yTopMar;
  373. int yBotMar;
  374. int yLeftOver;
  375. int yMiniBotMar;
  376. int i;
  377. lDBU = GetDialogBaseUnits();
  378. xBU = LOWORD(lDBU);
  379. yBU = HIWORD(lDBU);
  380. // get the rectangle of the OK button
  381. GetClientRect(GetDlgItem(hdlg, IDOK), &rcOK);
  382. // get x-extent of button
  383. xButton = rcOK.right - rcOK.left;
  384. // top margin is 2 characters
  385. yTopMar = (16 * yBU) / 8 - 6; // cookie land
  386. // bottom margin is 2 * minimum bottom margin dialog units +
  387. // height of button in pixels
  388. yBotMar = (VERTMARGIN * 2 *yBU) / 8 + rcOK.bottom - rcOK.top;
  389. if (fMaximize) {
  390. // get the rectangle of a 3-state button
  391. GetClientRect(GetDlgItem(hdlg, ID_SETUPCHECK), &rc3S);
  392. SetWindowPos(hdlg, NULL, 0L, 0L,
  393. rcBox.right - rcBox.left +
  394. (rc3S.right - rc3S.left) +
  395. (HORZMARGIN * 3 * xBU) / 4 +
  396. (GetSystemMetrics(SM_CXDLGFRAME) + 1) * 2,
  397. (DEF_SETUP_ROWS * 10 * yBU) / 8 +
  398. yTopMar + yBotMar +
  399. GetSystemMetrics(SM_CYCAPTION) +
  400. (GetSystemMetrics(SM_CYDLGFRAME) + 1) * 2,
  401. SWP_NOZORDER | SWP_NOMOVE);
  402. }
  403. // get the x and y extents of the client rectangle
  404. GetClientRect(hdlg, &rcWnd);
  405. xClient = rcWnd.right - rcWnd.left;
  406. yClient = rcWnd.bottom - rcWnd.top;
  407. // yChar is the height of one row in pixels - 1
  408. yChar = (10 * yBU) / 8 - 1;
  409. // xChar is the average width of a character
  410. xChar = xBU;
  411. // yBox is the room we actually have to display setup rows
  412. yBox = yClient - yTopMar - yBotMar;
  413. // nLines is the number of setup rows we can display
  414. nLines = min(16, yBox / yChar);
  415. // yLeftOver is how many pixels are left over
  416. yLeftOver = yBox - nLines * yChar;
  417. // add half the leftovers to the top margin
  418. yTopMar += yLeftOver / 2;
  419. // calculate scroll bar maximum and position
  420. iVertMax = max(0, 16 - nLines);
  421. iVertPos = min(iVertMax, iVertPos);
  422. // rcBox is the box of rows and columns inside the client area
  423. SetRect(&rcBox,
  424. rcBox.left,
  425. yTopMar,
  426. rcBox.right,
  427. yTopMar + nLines * yChar);
  428. // xCenter is used to center the OK and CANCEL buttons horizontally
  429. xCenter = (rcBox.right - rcBox.left - xButton * 3) / 4;
  430. // yMiniBotMar is the spacing above and below the button
  431. yMiniBotMar = (VERTMARGIN * yBU) / 8 + yLeftOver / 4;
  432. SetWindowPos(GetDlgItem(hdlg, IDOK), NULL, rcBox.left + xCenter,
  433. rcBox.bottom + yMiniBotMar, 0L, 0L,
  434. SWP_NOSIZE | SWP_NOZORDER);
  435. SetWindowPos(GetDlgItem(hdlg, IDCANCEL), NULL,
  436. rcBox.left + xButton + xCenter * 2,
  437. rcBox.bottom + yMiniBotMar, 0L, 0L,
  438. SWP_NOSIZE | SWP_NOZORDER);
  439. SetWindowPos(GetDlgItem(hdlg, IDH_DLG_MIDI_SETUPEDIT), NULL,
  440. rcBox.left + xButton * 2 + xCenter * 3,
  441. rcBox.bottom + yMiniBotMar, 0L, 0L,
  442. SWP_NOSIZE | SWP_NOZORDER);
  443. // this loop could be optimized
  444. // then again, so could the u.s. judicial system
  445. for (i = 0; i < 16; i++, yTopMar += yChar) {
  446. HWND hCheck;
  447. hCheck = GetDlgItem(hdlg, ID_SETUPCHECK + i);
  448. if (i < nLines) {
  449. SetWindowPos(hCheck, NULL,
  450. rcBox.right + (HORZMARGIN * xBU) / 4,
  451. yTopMar + 3, 0L, 0L,
  452. SWP_NOSIZE | SWP_NOZORDER);
  453. ShowWindow(hCheck, SW_SHOWNORMAL);
  454. } else
  455. ShowWindow(hCheck, SW_HIDE);
  456. }
  457. if (iCurPos >= 0 && iCurPos < nLines)
  458. VSetupSetFocus(hdlg, PSF_SHOWIFHIDDEN, 1);
  459. else
  460. VSetupActiveLine(PAL_HIDE, SWP_NOREDRAW);
  461. } /* VSetupSize */
  462. static MMAPERR PASCAL MmaperrInitNew(void)
  463. {
  464. SETUP FAR* lpSetup;
  465. WORD wChan;
  466. if ((hSetup = GlobalAlloc(GHND, (DWORD)sizeof(SETUP))) == NULL)
  467. return MMAPERR_MEMORY;
  468. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  469. lstrcpy(lpSetup->aszSetupName, szCurrent);
  470. lstrcpy(lpSetup->aszSetupDescription, szCurDesc);
  471. for (wChan = 0; wChan < 16; wChan++) {
  472. lpSetup->channels[wChan].wChannel = wChan;
  473. lpSetup->channels[wChan].wDeviceID = MMAP_ID_NOPORT;
  474. lstrcpy(lpSetup->channels[wChan].aszPatchName, szNone);
  475. }
  476. GlobalUnlock(hSetup);
  477. return MMAPERR_SUCCESS;
  478. } /* MmaperrInitNew */
  479. /*
  480. * VSetupEnumPorts
  481. *
  482. * Enumerate available port names and throw them in a combo box.
  483. */
  484. static void PASCAL VSetupEnumPorts(
  485. void)
  486. {
  487. MIDIOUTCAPS moCaps;
  488. UINT i;
  489. nPorts = midiOutGetNumDevs();
  490. for (i = 0; i < nPorts; i++) {
  491. midiOutGetDevCaps(i, &moCaps, sizeof(MIDIOUTCAPS));
  492. SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL,
  493. (LPARAM)(LPSTR)moCaps.szPname);
  494. }
  495. } /* VSetupEnumPorts */
  496. /*
  497. * MmaperrEnumPatches
  498. *
  499. * This function calls mapEnumerate to enumerate all the user-defined
  500. * patchmaps into a combo box.
  501. */
  502. static MMAPERR NEAR PASCAL MmaperrEnumPatches(void)
  503. {
  504. MMAPERR mmaperr;
  505. mmaperr = mapEnumerate(MMAP_PATCH, EnumFunc, MMENUM_BASIC, hPatchCombo, NULL);
  506. if (mmaperr != MMAPERR_SUCCESS)
  507. return mmaperr;
  508. nPatches = (int)(LONG)SendMessage(hPatchCombo, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0);
  509. SendMessage(hPatchCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone);
  510. return MMAPERR_SUCCESS;
  511. } /* MmaperrEnumPatches */
  512. static BOOL NEAR PASCAL FInitSetup(
  513. HWND hdlg)
  514. {
  515. SETUP FAR* lpSetup;
  516. LONG lDBU;
  517. UINT xBU;
  518. UINT yBU;
  519. UINT xWidth; // width of current column
  520. UINT xEdit; // width of edit controls
  521. UINT yEdit; // height of edit/arrow controls
  522. UINT xCombo; // width of combo boxes
  523. UINT yCombo; // height of combo boxes
  524. UINT wCheck;
  525. char szCaption[80];
  526. char szCaptionFormat[80];
  527. MMAPERR mmaperr;
  528. int i;
  529. if (!fNew) {
  530. if ((hSetup = GlobalAlloc(GHND, sizeof(SETUP))) == NULL) {
  531. mmaperr = MMAPERR_MEMORY;
  532. exit00: VShowError(hdlg, mmaperr);
  533. return FALSE;
  534. }
  535. } else if ((mmaperr = MmaperrInitNew()) != MMAPERR_SUCCESS)
  536. goto exit00;
  537. fHidden = FALSE;
  538. iVertPos = 0;
  539. iCurPos = 0;
  540. nLines = 0; // necessary?
  541. nPatches = 0;
  542. nPorts = 0;
  543. hPortList = GetDlgItem(hdlg, ID_SETUPPORTLIST);
  544. hEdit = GetDlgItem(hdlg, ID_SETUPEDIT);
  545. hArrow = GetDlgItem(hdlg, ID_SETUPARROW);
  546. hPortCombo = GetDlgItem(hdlg, ID_SETUPPORTCOMBO);
  547. hPatchCombo = GetDlgItem(hdlg, ID_SETUPPATCHCOMBO);
  548. if (fReadOnly)
  549. {
  550. EnableWindow(GetDlgItem(hdlg,IDOK),FALSE);
  551. SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0);
  552. }
  553. lDBU = GetDialogBaseUnits();
  554. xBU = LOWORD(lDBU);
  555. yBU = HIWORD(lDBU);
  556. xEdit = (40 * xBU) / 4; // 10 chars wide
  557. yEdit = (10 * yBU) / 8; // 10 is a magic cookie
  558. xCombo = (64 * xBU) / 4; // 16 characters long
  559. yCombo = (46 * yBU) / 8; // 46 is a magic cookie
  560. rcBox.left = (HORZMARGIN * xBU) / 4;
  561. rcBox.right = rcBox.left;
  562. rgxPos[0] = rcBox.right;
  563. rcBox.right += xEdit;
  564. rgxPos[1] = rcBox.right;
  565. xWidth = xEdit;
  566. SetWindowPos(hEdit, NULL, 0L, 0L, xWidth, yEdit,
  567. SWP_NOZORDER | SWP_NOMOVE);
  568. // set global arrow control offset to proper position
  569. rcBox.right += xArrowOffset = xWidth - 1;
  570. // width of dst channel arrow control
  571. xWidth = (10 * xBU) / 4;
  572. SetWindowPos(hArrow, NULL, 0L, 0L, xWidth, yEdit,
  573. SWP_NOZORDER | SWP_NOMOVE);
  574. rcBox.right += xWidth - 1;
  575. rgxPos[2] = rcBox.right;
  576. xWidth = (80 * xBU) / 4; // 20 characters long
  577. SetWindowPos(hPortCombo, NULL, 0L, 0L, xWidth,
  578. yCombo, SWP_NOZORDER | SWP_NOMOVE);
  579. rcBox.right += xWidth - 1;
  580. rgxPos[3] = rcBox.right;
  581. xWidth = xCombo;
  582. SetWindowPos(hPatchCombo, NULL, 0L, 0L, xWidth,
  583. yCombo, SWP_NOZORDER | SWP_NOMOVE);
  584. rcBox.right += xWidth - 1;
  585. rgxPos[4] = rcBox.right;
  586. if (!nPorts)
  587. VSetupEnumPorts();
  588. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  589. if (!nPatches)
  590. if ((mmaperr = MmaperrEnumPatches()) != MMAPERR_SUCCESS) {
  591. exit01: GlobalUnlock(hSetup);
  592. GlobalFree(hSetup);
  593. goto exit00;
  594. }
  595. if (!fNew) {
  596. mmaperr = mapReadSetup(szCurrent, lpSetup);
  597. if (mmaperr == MMAPERR_INVALIDPORT) {
  598. if (!InvalidPortMsgBox(hdlg)) {
  599. GlobalUnlock(hSetup);
  600. GlobalFree(hSetup);
  601. return FALSE;
  602. }
  603. mmaperr = mapEnumerate( MMAP_PORTS
  604. , FSetupEnumPortsFunc
  605. , MMENUM_BASIC
  606. , NULL
  607. , (LPSTR)szCurrent
  608. );
  609. }
  610. if (mmaperr != MMAPERR_SUCCESS){
  611. goto exit01;
  612. }
  613. if (lstrcmp(lpSetup->aszSetupDescription, szCurDesc)) {
  614. lstrcpy(lpSetup->aszSetupDescription, szCurDesc);
  615. fNew = TRUE;
  616. }
  617. }
  618. SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone);
  619. for (i = 0; i < 16; i++) {
  620. // check a 3-state button if the channel is active, or gray
  621. // it if the channel is not mapped to a port
  622. if (lpSetup->channels[i].wDeviceID == MMAP_ID_NOPORT)
  623. wCheck = BTN3S_GRAY;
  624. else if (lpSetup->channels[i].dFlags & MMAP_ACTIVE)
  625. wCheck = BTN3S_CHECK;
  626. else
  627. continue;
  628. VSetupActiveChan(i, 0L, wCheck);
  629. }
  630. GlobalUnlock(hSetup);
  631. LoadString(hLibInst, IDS_SETUPS ,szCaptionFormat, sizeof(szCaptionFormat));
  632. wsprintf(szCaption, szCaptionFormat, (LPSTR)szCurrent);
  633. SetWindowText(hWnd, szCaption);
  634. SendMessage(GetDlgItem(hdlg, ID_SETUPDESTMNEM),
  635. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  636. SendMessage(GetDlgItem(hdlg, ID_SETUPPORTMNEM),
  637. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  638. SendMessage(GetDlgItem(hdlg, ID_SETUPPATCHMNEM),
  639. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  640. VSetupSize(hdlg, TRUE);
  641. SetWindowPos(GetDlgItem(hdlg, ID_SETUPDESTMNEM), NULL,
  642. rgxPos[1], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  643. SetWindowPos(GetDlgItem(hdlg, ID_SETUPPORTMNEM), NULL,
  644. rgxPos[2], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  645. SetWindowPos(GetDlgItem(hdlg, ID_SETUPPATCHMNEM), NULL,
  646. rgxPos[3], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  647. Modify(fNew);
  648. return TRUE;
  649. } /* FInitSetup */
  650. static void PASCAL VSetupButtonDown(
  651. HWND hdlg,
  652. LONG lParam)
  653. {
  654. int x = LOWORD(lParam);
  655. int y = HIWORD(lParam);
  656. int iPos;
  657. UINT uFlags;
  658. if (x < rcBox.left || x > rcBox.right)
  659. return;
  660. if (y < rcBox.top || y > rcBox.bottom)
  661. return;
  662. if ((iPos = min(nLines - 1, (y - rcBox.top) / yChar)) == iCurPos)
  663. return;
  664. if (iCurPos >= 0 && iCurPos < nLines) {
  665. uFlags = PSF_REDRAW;
  666. SendMessage(hPortCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0);
  667. SendMessage(hPatchCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0);
  668. UpdateWindow(hdlg);
  669. } else
  670. uFlags = PSF_SHOWIFHIDDEN;
  671. iCurPos = iPos;
  672. VSetupSetFocus(hdlg, uFlags, x);
  673. } /* VSetupButtonDown */
  674. static void PASCAL VSetupPaint(
  675. HWND hdlg)
  676. {
  677. HPEN hPen; // previous pen to restore
  678. SETUP FAR* lpSetup;
  679. CHANNEL FAR* lpChannel;
  680. PAINTSTRUCT ps; // from BeginPaint
  681. RECT rcText;
  682. UINT uDev;
  683. int i; // loop counter
  684. int iVert;
  685. int nBegin; // first row to repaint
  686. int nEnd; // last row to repaint
  687. int iLeft; // left of invalid area
  688. int iTop; // top of invalid area
  689. int iBottom; // bottom of invalid area
  690. char szBuf[MAXPNAMELEN];
  691. // uses GLOBAL hFont - Lord knows why.
  692. // uses GLOBAL rcBox = clipping rectangle???
  693. BeginPaint(hdlg, &ps);
  694. if (!ps.rcPaint.bottom) { // bottom==0 => area must be empty
  695. exit00: EndPaint(hdlg, &ps);
  696. return;
  697. }
  698. hPen = SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
  699. hFont = SelectObject(ps.hdc, hFont);
  700. SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
  701. SetBkMode(ps.hdc, TRANSPARENT);
  702. if (ps.rcPaint.top < rcBox.top) { // need to paint top headings?
  703. iVert = yChar;
  704. TextOut(ps.hdc, 11, iVert, aszSourceChannel, lstrlen(aszSourceChannel));
  705. SetRect(&rcText, rcBox.right + 2, yChar, 0, 0);
  706. DrawText(ps.hdc, aszActive, -1, &rcText,
  707. DT_LEFT | DT_NOCLIP);
  708. }
  709. // calculate top and bottom y coordinates of invalid area
  710. iTop = max(ps.rcPaint.top, rcBox.top);
  711. // if top is below the box, forget about painting
  712. if (iTop > rcBox.bottom) {
  713. exit01: hFont = SelectObject(ps.hdc, hFont); // restore
  714. hPen = SelectObject(ps.hdc, hPen); // restore
  715. goto exit00;
  716. }
  717. iBottom = min(ps.rcPaint.bottom, rcBox.bottom);
  718. // calculate left x coordinate of invalid area
  719. iLeft = max(ps.rcPaint.left, rcBox.left);
  720. // calculate beginning and ending data row to be repainted
  721. nBegin = max(0, (iTop - rcBox.top) / yChar);
  722. nEnd = min(nLines, (iBottom - rcBox.top) / yChar);
  723. // draw vertical lines of the box
  724. for (i = 0; i < 5; i++) {
  725. MMoveTo(ps.hdc, rgxPos[i], iTop);
  726. LineTo(ps.hdc, rgxPos[i], iBottom + 1);
  727. }
  728. // vertical position of first line we have to draw
  729. iVert = rcBox.top + nBegin * yChar;
  730. // lock the map
  731. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  732. // set up an optimization pointer
  733. lpChannel = &lpSetup->channels[iVertPos + nBegin];
  734. for (i = nBegin; i <= nEnd; i++, iVert += yChar, lpChannel++) {
  735. MMoveTo(ps.hdc, iLeft, iVert);
  736. LineTo(ps.hdc, rcBox.right, iVert);
  737. if (i == nLines)
  738. break;
  739. if (iLeft < rgxPos[1]) {
  740. wsprintf(szBuf, aszSetupNumFormat, iVertPos + i + 1);
  741. TextOut(ps.hdc, rgxPos[0] + xChar, iVert + 2,
  742. szBuf, 3);
  743. }
  744. if (iLeft < rgxPos[2]) {
  745. wsprintf(szBuf, aszSetupNumFormat, lpChannel->wChannel + 1);
  746. TextOut(ps.hdc, rgxPos[1] + 2 * xChar, iVert + 2,
  747. szBuf, 3);
  748. }
  749. if (i == iCurPos)
  750. continue;
  751. if (iLeft < rgxPos[3]) {
  752. *szBuf = 0;
  753. uDev = lpChannel->wDeviceID;
  754. if (uDev == MMAP_ID_NOPORT)
  755. uDev = nPorts;
  756. if (uDev <= nPorts) {
  757. RECT sTextRect;
  758. TEXTMETRIC sTM;
  759. SendMessage(hPortCombo, CB_GETLBTEXT,
  760. uDev, (LPARAM)(LPSTR)szBuf);
  761. GetTextMetrics(ps.hdc,(LPTEXTMETRIC)&sTM);
  762. SetRect((LPRECT)&sTextRect,rgxPos[2]+2,iVert+2,rgxPos[3]-2,iVert+2+sTM.tmHeight);
  763. DrawText(ps.hdc, szBuf, -1,(LPRECT)&sTextRect ,DT_NOPREFIX|DT_LEFT|DT_SINGLELINE);
  764. }
  765. }
  766. if (iLeft < rgxPos[4]) {
  767. RECT rc;
  768. SetRect(&rc, rgxPos[3]+2, iVert, rgxPos[4]-2, iVert+yChar);
  769. DrawText(ps.hdc,
  770. lpChannel->aszPatchName,
  771. lstrlen(lpChannel->aszPatchName),
  772. &rc,
  773. DT_LEFT|DT_SINGLELINE|DT_VCENTER
  774. );
  775. // was:
  776. // TextOut(ps.hdc, rgxPos[3] + 2, iVert + 2, lpChannel->aszPatchName,
  777. // lstrlen(lpChannel->aszPatchName));
  778. }
  779. }
  780. GlobalUnlock(hSetup);
  781. goto exit01;
  782. } /* VSetupPaint */
  783. static void PASCAL VSetupArrowScroll(
  784. HWND hdlg,
  785. WORD ScrollCode)
  786. {
  787. SETUP FAR* lpSetup;
  788. WORD wChan;
  789. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  790. wChan = lpSetup->channels[iVertPos + iCurPos].wChannel;
  791. GlobalUnlock(hSetup);
  792. switch (ScrollCode) {
  793. case SB_LINEDOWN:
  794. if (!wChan--)
  795. wChan = 15;
  796. break;
  797. case SB_LINEUP:
  798. if (++wChan > 15)
  799. wChan = 0;
  800. break;
  801. }
  802. SetDlgItemInt(hWnd, ID_SETUPEDIT, wChan + 1, FALSE);
  803. } /* VSetupArrowScroll */
  804. /*
  805. * VSetupCheckMsg
  806. */
  807. static void PASCAL VSetupCheckMsg(
  808. WORD id,
  809. WORD NotifCode)
  810. {
  811. SETUP FAR* lpSetup;
  812. CHANNEL FAR* lpChannel;
  813. if (NotifCode != BN_CLICKED)
  814. return;
  815. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  816. lpChannel = &lpSetup->channels[iVertPos + id - ID_SETUPCHECK];
  817. if (lpChannel->wDeviceID != MMAP_ID_NOPORT) {
  818. VSetupActiveChan( id - ID_SETUPCHECK
  819. , &lpChannel->dFlags
  820. , (lpChannel->dFlags & MMAP_ACTIVE)
  821. ? BTN3S_UNCHECK
  822. : BTN3S_CHECK
  823. );
  824. Modify(TRUE);
  825. }
  826. GlobalUnlock(hSetup);
  827. } /* VSetupCheckMsg */
  828. BOOL FAR PASCAL _loadds SetupBox(
  829. HWND hdlg,
  830. UINT uMessage,
  831. WPARAM wParam,
  832. LPARAM lParam)
  833. {
  834. int iRet;
  835. HWND hwndCheckBox;
  836. switch (uMessage) {
  837. case WM_INITDIALOG:
  838. hWnd = hdlg;
  839. iOldPos = -1;
  840. SetFocus(GetDlgItem(hdlg, ID_SETUPEDIT));
  841. if (!FInitSetup(hdlg))
  842. EndDialog(hdlg, FALSE);
  843. SetFocus(hEdit);
  844. PlaceWindow(hWnd);
  845. return FALSE;
  846. case WM_COMMAND:
  847. { WORD id = LOWORD(wParam);
  848. #if defined(WIN16)
  849. WORD NotifCode = HIWORD(lParam);
  850. HWND hwnd = LOWORD(lParam);
  851. #else
  852. WORD NotifCode = HIWORD(wParam);
  853. HWND hwnd = (HWND)lParam;
  854. #endif //WIN16
  855. switch (id) {
  856. case IDH_DLG_MIDI_SETUPEDIT:
  857. goto DoHelp;
  858. case IDOK:
  859. case IDCANCEL:
  860. if (NotifCode != BN_CLICKED)
  861. break;
  862. if (!fReadOnly && ((id == IDOK) && fModified)) {
  863. iRet = ISetupSave(hdlg, TRUE);
  864. if (iRet == IDCANCEL)
  865. break;
  866. iRet = (iRet == IDYES);
  867. } else
  868. iRet = FALSE;
  869. GlobalFree(hSetup);
  870. EndDialog(hdlg, iRet);
  871. break;
  872. case ID_SETUPGHOSTEDITFIRST:
  873. /* assume the user back-tabbed before the first
  874. * control on the current row, so jump to the
  875. * previous row (if iCurPos > 0) or the last row
  876. * (if iCurPos == 0)
  877. */
  878. if (NotifCode != EN_SETFOCUS)
  879. break;
  880. if (iCurPos < 0)
  881. /* do nothing */ ;
  882. else
  883. if (iCurPos > 0)
  884. iCurPos--;
  885. else
  886. iCurPos = nLines - 1;
  887. VSetupSetFocus(hdlg, PSF_REDRAW, 0);
  888. hwndCheckBox = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos);
  889. if (IsWindowEnabled(hwndCheckBox))
  890. SetFocus(hwndCheckBox);
  891. else
  892. SetFocus(hPatchCombo);
  893. break;
  894. case ID_SETUPGHOSTEDITLAST:
  895. /* assume the user forward-tabbed beyond the last
  896. * control on the current row, so jump to the
  897. * next row (if iCurPos < nLines - 1) or the first row
  898. * (if iCurPos == nLines - 1)
  899. */
  900. if (NotifCode != EN_SETFOCUS)
  901. break;
  902. if (iCurPos < 0)
  903. /* do nothing */ ;
  904. else
  905. if (iCurPos < nLines - 1)
  906. iCurPos++;
  907. else
  908. iCurPos = 0;
  909. VSetupSetFocus(hdlg, PSF_REDRAW, 0);
  910. SetFocus(hEdit);
  911. #if defined(WIN16)
  912. SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
  913. #else
  914. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  915. #endif //WIN16
  916. break;
  917. case ID_SETUPEDIT:
  918. VSetupEditMsg(hdlg, NotifCode);
  919. break;
  920. case ID_SETUPPORTCOMBO:
  921. case ID_SETUPPATCHCOMBO:
  922. VSetupComboMsg(hdlg, id, NotifCode);
  923. break;
  924. default:
  925. if ((id >= ID_SETUPCHECK) &&
  926. (id < ID_SETUPCHECK + 16))
  927. VSetupCheckMsg(id, NotifCode);
  928. else
  929. return FALSE;
  930. }
  931. break;
  932. } /* end of WM_COMMAND */
  933. case WM_PAINT:
  934. VSetupPaint(hdlg);
  935. break;
  936. case WM_LBUTTONDOWN:
  937. VSetupButtonDown(hdlg, (LONG)lParam);
  938. break;
  939. case WM_VSCROLL:
  940. // if (HIWORD(lParam)) // in DOS this is the window ID - I don't see why we need the test
  941. // and in NT we don't have that ID anyway
  942. VSetupArrowScroll(hdlg, LOWORD(wParam));
  943. // LOWORD(wParam) is scroll code. See cpArrow:
  944. // actually the whole of wParam is.
  945. break;
  946. case WM_CHAR:
  947. if ((LONG)lParam == 14)
  948. if (iCurPos == 15)
  949. iCurPos = 0;
  950. else
  951. iCurPos++;
  952. else if ((LONG)lParam == 16)
  953. if (!iCurPos)
  954. iCurPos = 15;
  955. else
  956. iCurPos--;
  957. else
  958. return FALSE;
  959. VSetupSetFocus(hdlg, 0L, 0L);
  960. break;
  961. case WM_CLOSE:
  962. PostMessage(hdlg, WM_COMMAND, (WPARAM)IDOK, (LPARAM)0);
  963. break;
  964. default:
  965. if (uMessage == uHelpMessage) {
  966. DoHelp:
  967. WinHelp(hWnd, szMidiHlp, HELP_CONTEXT,
  968. IDH_DLG_MIDI_SETUPEDIT);
  969. return TRUE;
  970. }
  971. else
  972. return FALSE;
  973. break;
  974. }
  975. return TRUE;
  976. } /* SetupBox */
  977. /*
  978. * FSetupEnumPortsFunc
  979. *
  980. * This function receives port information for each channel in a setup,
  981. * determines if the port is not available in the current environment, and
  982. * if so adds it to a listbox of invalid port names.
  983. *
  984. * The types and parameters are weird because it is being forced into the straightjacket
  985. * of an enumfunc.
  986. */
  987. BOOL FAR PASCAL _loadds FSetupEnumPortsFunc(
  988. LPSTR lpChannel,
  989. LPSTR lpPort,
  990. UINT uCase, // unused
  991. HWND hCombo, //unused
  992. LPSTR DeviceID)
  993. {
  994. SETUP FAR* lpSetup;
  995. INT Idx;
  996. if (DeviceID == (LPSTR)MMAP_ID_NOPORT) {
  997. Idx = ComboLookup(hPortCombo, lpPort);
  998. if (Idx == CB_ERR) {
  999. SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL,
  1000. (LPARAM)lpPort);
  1001. Idx = nPorts++;
  1002. }
  1003. lpSetup = (SETUP FAR*)GlobalLock(hSetup);
  1004. lpSetup->channels[(WORD)(DWORD_PTR)lpChannel - 1].wDeviceID = (WORD)Idx;
  1005. GlobalUnlock(hSetup);
  1006. }
  1007. return TRUE;
  1008. } /* FSetupEnumPortsFunc */