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.

1150 lines
38 KiB

  1. /*
  2. * PATCH.C
  3. *
  4. * Copyright (C) 1990 Microsoft Corporation.
  5. *
  6. * Edit patchmaps 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 Files -=-=-=-=-*/
  12. #include "preclude.h"
  13. #include <windows.h>
  14. #include <mmsystem.h>
  15. #include <port1632.h>
  16. #include <string.h>
  17. #include "hack.h"
  18. #include "midimap.h"
  19. #include "cphelp.h"
  20. #include "midi.h"
  21. #include "extern.h"
  22. #if defined(WIN32)
  23. #define _based(x)
  24. #endif //WIN32
  25. /*-=-=-=-=- Prototypes -=-=-=-=-*/
  26. static SZCODE aszPatchNumFormat[] = "%3d";
  27. static MMAPERR PASCAL MmaperrPatchInit(HWND);
  28. static MMAPERR PASCAL MmaperrPatchInitNew(VOID);
  29. static VOID PASCAL PatchEnumKeys(HWND);
  30. static VOID PASCAL PatchSize(HWND, BOOL);
  31. static VOID PASCAL PatchPaint(VOID);
  32. static VOID PASCAL PatchArrowScroll(WPARAM, LPARAM);
  33. static VOID PASCAL PatchWindowScroll(HWND, UINT, int);
  34. static VOID PASCAL PatchEditMsg(UINT id , WORD NotifCode);
  35. static VOID PASCAL PatchComboMsg(HWND hDlg, WORD NotifCode);
  36. static VOID PASCAL PatchButtonDown(HWND, LONG);
  37. static VOID PASCAL PatchSetFocus(HWND, UINT, int);
  38. static VOID PASCAL PatchActiveLine(UINT, UINT);
  39. static int PASCAL PatchSave(HWND, BOOL);
  40. /*-=-=-=-=- Global Definitions -=-=-=-=-*/
  41. #define PAL_SHOW 0 // show active line
  42. #define PAL_HIDE 1 // hide active line
  43. #define PSF_REDRAW 0x0001 // redraw where line used to be
  44. #define PSF_SHOWIFHIDDEN 0x0002 // show line if hidden
  45. #define DEF_PATCH_ROWS 16 // number of default patch rows
  46. /*-=-=-=-=- Global Variables -=-=-=-=-*/
  47. static HWND hCombo, // keymap combo-box control handle
  48. hScroll, // scroll bar control handle
  49. hVolEdit, // volume edit control handle
  50. hVolArrow; // volume arrow control handle
  51. static HGLOBAL hPatchMap;
  52. static int nKeys, // number of key maps in mapfile
  53. iPatchBase,
  54. xArrowOffset, // patch arrow ctrl positional offset
  55. xVolArrowOffset; // volume arrow ctrl positional offset
  56. static char szCaption[80];
  57. static char szCaptionFormat[80];
  58. /*-=-=-=-=- Functions -=-=-=-=-*/
  59. /*
  60. * PATCHBOX
  61. */
  62. BOOL FAR PASCAL _loadds PatchBox( HWND hDlg,
  63. UINT uMessage,
  64. WPARAM wParam,
  65. LPARAM lParam )
  66. {
  67. int iRet = FALSE;
  68. char szBuf [50];
  69. MMAPERR mmaperr;
  70. switch (uMessage) {
  71. case WM_INITDIALOG :
  72. hWnd = hDlg;
  73. SetFocus(GetDlgItem(hDlg, ID_PATCHNUMEDIT));
  74. if ((mmaperr = MmaperrPatchInit(hDlg)) != MMAPERR_SUCCESS) {
  75. VShowError(hDlg, mmaperr);
  76. EndDialog(hDlg, FALSE);
  77. }
  78. SetScrollRange(hScroll, SB_CTL, 0, iVertMax, FALSE);
  79. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  80. PlaceWindow(hWnd);
  81. return FALSE;
  82. case WM_COMMAND :
  83. { WORD id = LOWORD(wParam);
  84. #if defined(WIN16)
  85. WORD NotifCode = HIWORD(lParam);
  86. HWND hwnd = LOWORD(lParam);
  87. #else
  88. WORD NotifCode = HIWORD(wParam);
  89. HWND hwnd = (HWND)lParam;
  90. #endif //WIN16
  91. switch(id) {
  92. case IDH_DLG_MIDI_PATCHEDIT:
  93. goto DoHelp;
  94. case ID_PATCHGHOSTEDITFIRST:
  95. /* assume the user back-tabbed before the first
  96. * control on the current row, so jump to the
  97. * previous row (if iCurPos > 0) or the last row
  98. * (if iCurPos == 0)
  99. */
  100. if (fHidden) // we shouldn't get these
  101. break; // messages when we're hidden -jyg
  102. if (NotifCode != EN_SETFOCUS)
  103. break;
  104. if (iCurPos < 0)
  105. /* do nothing */ ;
  106. else if (iCurPos > 0)
  107. iCurPos--;
  108. else
  109. {
  110. if (iVertPos != 0)
  111. {
  112. /* at top -- scroll up one line */
  113. PatchWindowScroll(hDlg, SB_LINEUP, 0);
  114. iCurPos = 0;
  115. }
  116. else
  117. {
  118. PatchWindowScroll(hDlg, SB_THUMBPOSITION,iVertMax);
  119. iCurPos = nLines - 1;
  120. PatchSetFocus(hDlg, PSF_REDRAW|PSF_SHOWIFHIDDEN, 0L);
  121. PatchActiveLine(PAL_SHOW, SWP_SHOWWINDOW);
  122. }
  123. }
  124. PatchSetFocus(hDlg, PSF_REDRAW, 1);
  125. SetFocus(hCombo);
  126. break;
  127. case ID_PATCHGHOSTEDITLAST:
  128. /* assume the user forward-tabbed beyond the last
  129. * control on the current row, so jump to the
  130. * next row (if iCurPos < nLines - 1) or the first row
  131. * (if iCurPos == nLines - 1)
  132. */
  133. if (fHidden) //we shouldn't get these messages
  134. break; //when we're hidden -jyg
  135. if (NotifCode != EN_SETFOCUS)
  136. break;
  137. if (iCurPos < 0)
  138. /* do nothing */ ;
  139. else if (iCurPos < nLines - 1)
  140. iCurPos++;
  141. else
  142. {
  143. if (iVertPos != iVertMax)
  144. {
  145. /* at bottom -- scroll down one line */
  146. PatchWindowScroll(hDlg, SB_LINEDOWN, 0);
  147. iCurPos = nLines - 1;
  148. }
  149. else
  150. {
  151. /* wrap to the top cell */
  152. PatchWindowScroll(hDlg, SB_THUMBPOSITION,-iVertMax);
  153. iCurPos = 0;
  154. PatchSetFocus(hDlg, PSF_REDRAW|PSF_SHOWIFHIDDEN, 0L);
  155. PatchActiveLine(PAL_SHOW, SWP_SHOWWINDOW);
  156. }
  157. }
  158. PatchSetFocus(hDlg, PSF_REDRAW, 1);
  159. SetFocus(hEdit);
  160. #if defined(WIN16)
  161. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, MAKELPARAM(0, 32767));
  162. #else
  163. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  164. #endif //WIN16
  165. break;
  166. case IDOK :
  167. case IDCANCEL :
  168. if (NotifCode != BN_CLICKED)
  169. break;
  170. if (!fReadOnly && (id == IDOK) && fModified) {
  171. iRet = PatchSave(hDlg, TRUE);
  172. if (iRet == IDCANCEL)
  173. break;
  174. iRet = (iRet == IDYES);
  175. }
  176. else
  177. iRet = FALSE;
  178. GlobalFree(hPatchMap);
  179. nKeys = 0;
  180. EndDialog(hDlg, iRet);
  181. break;
  182. case ID_PATCHNUMEDIT :
  183. case ID_PATCHVOLEDIT :
  184. PatchEditMsg(id, NotifCode);
  185. break;
  186. case ID_PATCHCOMBO :
  187. PatchComboMsg(hDlg, NotifCode);
  188. break;
  189. case ID_PATCHBASED :
  190. if (NotifCode != BN_CLICKED)
  191. break;
  192. iPatchBase = !iPatchBase;
  193. wsprintf(szBuf, aszPatchNumber,
  194. !iPatchBase);
  195. SetWindowText(hwnd, szBuf);
  196. PatchEditMsg(ID_PATCHNUMEDIT, EN_ACTIVATE);
  197. SetFocus(hEdit);
  198. #if defined(WIN16)
  199. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, MAKELPARAM(0, 32767));
  200. #else
  201. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  202. #endif //WIN16
  203. InvalidateRect(hWnd, &rcBox, TRUE);
  204. break;
  205. default :
  206. return FALSE;
  207. }
  208. break;
  209. } /* end of WM_COMMAND */
  210. case WM_PAINT :
  211. PatchPaint();
  212. break;
  213. case WM_LBUTTONDOWN :
  214. PatchButtonDown(hDlg, (LONG)lParam);
  215. break;
  216. case WM_VSCROLL :
  217. #if defined(WIN16)
  218. if ((HWND)HIWORD(lParam) == hScroll)
  219. PatchWindowScroll(hDlg, (WORD)wParam, (int)LOWORD(lParam));
  220. else
  221. PatchArrowScroll((WORD)wParam, (LONG)lParam);
  222. #else
  223. if ((HWND)(lParam) == hScroll)
  224. PatchWindowScroll(hDlg, LOWORD(wParam), HIWORD(wParam));
  225. else
  226. PatchArrowScroll(LOWORD(wParam), lParam);
  227. #endif //WIN16
  228. break;
  229. case WM_CLOSE :
  230. PostMessage(hDlg, WM_COMMAND, (WPARAM)IDOK, (LPARAM)0);
  231. break;
  232. default:
  233. if (uMessage == uHelpMessage) {
  234. DoHelp:
  235. WinHelp(hWnd, szMidiHlp, HELP_CONTEXT,
  236. IDH_DLG_MIDI_PATCHEDIT);
  237. return TRUE;
  238. }
  239. else
  240. return FALSE;
  241. break;
  242. }
  243. return TRUE;
  244. } /* PatchBox */
  245. /*
  246. * MmaperrPatchInit
  247. */
  248. static MMAPERR PASCAL MmaperrPatchInit(
  249. HWND hDlg)
  250. {
  251. PATCHMAP FAR* lpPatch;
  252. LONG lDBU;
  253. MMAPERR mmaperr;
  254. UINT xBU,
  255. yBU,
  256. xWidth, // width of current column
  257. xArrow, // width of arrow control
  258. xEdit, // width of edit controls
  259. yEdit, // height of edit/arrow controls
  260. xCombo, // width of combo boxes
  261. yCombo; // height of combo boxes
  262. int i;
  263. fHidden = FALSE;
  264. iVertPos = 0;
  265. iCurPos = 0;
  266. nKeys = 0;
  267. nLines = 0; // necessary?
  268. iPatchBase = 1; // getprofile
  269. hEdit = GetDlgItem(hWnd, ID_PATCHNUMEDIT);
  270. hArrow = GetDlgItem(hWnd, ID_PATCHNUMARROW);
  271. hVolEdit = GetDlgItem(hWnd, ID_PATCHVOLEDIT);
  272. hVolArrow = GetDlgItem(hWnd, ID_PATCHVOLARROW);
  273. hCombo = GetDlgItem(hWnd, ID_PATCHCOMBO);
  274. hScroll = GetDlgItem(hWnd, ID_PATCHSCROLL);
  275. if (fReadOnly)
  276. {
  277. EnableWindow(GetDlgItem(hWnd,IDOK),FALSE);
  278. SendMessage(hWnd, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0);
  279. }
  280. lDBU = GetDialogBaseUnits();
  281. xBU = LOWORD(lDBU);
  282. yBU = HIWORD(lDBU);
  283. xArrow = (10 * xBU) / 4; // about yea big
  284. xEdit = (40 * xBU) / 4; // 10 chars wide
  285. yEdit = (10 * yBU) / 8; // cookie heaven
  286. xCombo = (64 * xBU) / 4; // 16 chars wide
  287. yCombo = (46 * yBU) / 8; // oreos
  288. rcBox.left = (HORZMARGIN * xBU) / 4;
  289. for (i = 0, rcBox.right = rcBox.left; i < 6; i++) {
  290. rgxPos [i] = rcBox.right;
  291. switch (i) {
  292. case 0 :
  293. // width of src patch # text (3.5 chars wide)
  294. rcBox.right += xEdit;
  295. break;
  296. case 1 :
  297. // width of src patch name text
  298. rcBox.right += (72 * xBU) / 4; // 18 chars wide
  299. break;
  300. case 2 :
  301. // width of dst patch # edit control
  302. xWidth = xEdit;
  303. SetWindowPos(hEdit, NULL, 0L, 0L,
  304. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  305. // set global arrow control offset to proper position
  306. rcBox.right += xArrowOffset = xWidth - 1;
  307. // width of dst patch # arrow control
  308. xWidth = xArrow;
  309. SetWindowPos(hArrow, NULL, 0L, 0L,
  310. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  311. rcBox.right += xWidth - 1;
  312. break;
  313. case 3 :
  314. // width of volume % edit control
  315. xWidth = xEdit;
  316. SetWindowPos(hVolEdit, NULL, 0L, 0L,
  317. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  318. // set global arrow control offset to proper position
  319. rcBox.right += xVolArrowOffset = xWidth - 1;
  320. // width of volume % arrow control
  321. xWidth = xArrow;
  322. SetWindowPos(hVolArrow, NULL, 0L, 0L,
  323. xWidth, yEdit, SWP_NOZORDER | SWP_NOMOVE);
  324. rcBox.right += xWidth - 1;
  325. break;
  326. case 4 :
  327. // width of keymap combo box. I'd use MMAP_MAXLEN
  328. xWidth = xCombo;
  329. SetWindowPos(hCombo, NULL, 0L, 0L,
  330. xWidth, yCombo, SWP_NOZORDER | SWP_NOMOVE);
  331. rcBox.right += xWidth - 1;
  332. break;
  333. case 5 :
  334. break;
  335. }
  336. }
  337. if (!nKeys)
  338. PatchEnumKeys(hCombo);
  339. if (!fNew) {
  340. if ((hPatchMap = GlobalAlloc(GHND, sizeof(PATCHMAP))) == NULL)
  341. return MMAPERR_MEMORY;
  342. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  343. if ((mmaperr = mapReadPatchMap(szCurrent, lpPatch)) == MMAPERR_SUCCESS)
  344. if (lstrcmp(lpPatch->aszPatchMapDescription, szCurDesc)) {
  345. lstrcpy(lpPatch->aszPatchMapDescription, szCurDesc);
  346. fNew = TRUE;
  347. }
  348. GlobalUnlock(hPatchMap);
  349. if (mmaperr != MMAPERR_SUCCESS) {
  350. GlobalFree(hPatchMap);
  351. hPatchMap = NULL;
  352. return mmaperr;
  353. }
  354. } else if ((mmaperr = MmaperrPatchInitNew()) != MMAPERR_SUCCESS)
  355. return mmaperr;
  356. LoadString(hLibInst, IDS_PATCHES ,szCaptionFormat, sizeof(szCaptionFormat));
  357. wsprintf(szCaption, szCaptionFormat, (LPSTR)szCurrent);
  358. SetWindowText(hWnd, szCaption);
  359. SendMessage(GetDlgItem(hWnd, ID_PATCHDESTMNEM),
  360. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  361. SendMessage(GetDlgItem(hWnd, ID_PATCHVOLMNEM),
  362. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  363. SendMessage(GetDlgItem(hWnd, ID_PATCHKEYMNEM),
  364. WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
  365. PatchSize(hDlg, TRUE);
  366. i = rcBox.top - yChar + 5;
  367. SetWindowPos(GetDlgItem(hWnd, ID_PATCHDESTMNEM), NULL,
  368. rgxPos [2] - xChar + 7, i, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  369. SetWindowPos(GetDlgItem(hWnd, ID_PATCHVOLMNEM), NULL,
  370. rgxPos [3] + xChar - 6, i, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  371. SetWindowPos(GetDlgItem(hWnd, ID_PATCHKEYMNEM), NULL,
  372. rgxPos [4] + xChar, i, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
  373. #if defined(WIN16)
  374. SendMessage(hWnd, WM_COMMAND, (WPARAM)ID_PATCHBASED, MAKELPARAM(GetDlgItem(hWnd, ID_PATCHBASED), BN_CLICKED));
  375. #else
  376. SendMessage( hWnd
  377. , WM_COMMAND
  378. , (WPARAM)MAKELONG(ID_PATCHBASED, BN_CLICKED)
  379. , (LPARAM)GetDlgItem(hWnd, ID_PATCHBASED)
  380. );
  381. #endif //WIN16
  382. Modify(fNew);
  383. return MMAPERR_SUCCESS;
  384. } /* MmaperrPatchInit */
  385. /*
  386. * MmaperrPatchInitNew
  387. */
  388. static MMAPERR PASCAL MmaperrPatchInitNew(
  389. VOID)
  390. {
  391. PATCHMAP FAR* lpPatch;
  392. UINT u;
  393. if ((hPatchMap = GlobalAlloc(GHND,
  394. (DWORD)sizeof(PATCHMAP))) == NULL)
  395. return MMAPERR_MEMORY;
  396. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  397. lstrcpy(lpPatch->aszPatchMapName, szCurrent);
  398. lstrcpy(lpPatch->aszPatchMapDescription, szCurDesc);
  399. for (u = 0; u < MIDIPATCHSIZE; u++) {
  400. lpPatch->keymaps[u].bVolume = 100;
  401. lpPatch->keymaps[u].bDestination = (BYTE)u;
  402. lstrcpy(lpPatch->keymaps[u].aszKeyMapName, szNone);
  403. }
  404. GlobalUnlock(hPatchMap);
  405. return MMAPERR_SUCCESS;
  406. } /* MmaperrPatchInitNew */
  407. /*
  408. * PATCHENUMKEYS
  409. */
  410. static
  411. VOID PASCAL PatchEnumKeys(HWND hCombo)
  412. {
  413. mapEnumerate(MMAP_KEY, EnumFunc, MMENUM_BASIC, hCombo, NULL);
  414. SendMessage(hCombo, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPSTR)szNone);
  415. nKeys = (int)(LONG)SendMessage(hCombo, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0);
  416. } /* PatchEnumKeys */
  417. /*
  418. * PATCHSIZE
  419. */
  420. static
  421. VOID PASCAL PatchSize(HWND hDlg, BOOL fMaximize)
  422. {
  423. HWND hBanana;
  424. RECT rcBanana;
  425. RECT rcOK,
  426. rcWnd;
  427. LONG lDBU;
  428. UINT xBU,
  429. yBU;
  430. int xButton,
  431. xCenter,
  432. yTopMar,
  433. yBotMar,
  434. yLeftOver,
  435. yBox,
  436. yMiniBotMar;
  437. lDBU = GetDialogBaseUnits();
  438. xBU = LOWORD(lDBU);
  439. yBU = HIWORD(lDBU);
  440. // get the rectangle of the OK button
  441. GetClientRect(GetDlgItem(hWnd, IDOK), &rcOK);
  442. // get x-extent of button
  443. xButton = rcOK.right - rcOK.left;
  444. // top margin is 4 characters
  445. yTopMar = (32 * yBU) / 8 - 6; // cookie land
  446. // bottom margin is 2 * minimum bottom margin dialog units +
  447. // height of button in pixels
  448. yBotMar = (VERTMARGIN * 2 * yBU) / 8 + rcOK.bottom - rcOK.top;
  449. if (fMaximize) {
  450. // maximize the patch box
  451. SetWindowPos(hWnd, NULL, 0L, 0L,
  452. rcBox.right - rcBox.left +
  453. (2 * HORZMARGIN * xBU) / 4 +
  454. GetSystemMetrics(SM_CXVSCROLL) +
  455. (GetSystemMetrics(SM_CXDLGFRAME) + 1) * 2,
  456. (DEF_PATCH_ROWS * 10 * yBU) / 8 +
  457. yTopMar + yBotMar +
  458. GetSystemMetrics(SM_CYCAPTION) +
  459. GetSystemMetrics(SM_CYDLGFRAME) * 2,
  460. SWP_NOZORDER | SWP_NOMOVE);
  461. }
  462. // get the x and y extents of the client rectangle
  463. GetClientRect(hWnd, &rcWnd);
  464. xClient = rcWnd.right - rcWnd.left;
  465. yClient = rcWnd.bottom - rcWnd.top;
  466. // yChar is the height of one row in pixels - 1
  467. yChar = (10 * yBU) / 8 - 1;
  468. // xChar is the average width of a character
  469. xChar = xBU;
  470. // yBox is the room we actually have to display patchmap rows
  471. yBox = yClient - yTopMar - yBotMar;
  472. // nLines is the number of setup rows we can display
  473. nLines = min(16, yBox / yChar);
  474. // yLeftOver is how many pixels are left over
  475. yLeftOver = yBox - nLines * yChar;
  476. // add half the leftovers to the top margin
  477. yTopMar += yLeftOver / 2;
  478. // rcBox is the box of rows and columns inside the client area
  479. SetRect(
  480. &rcBox,
  481. rcBox.left,
  482. yTopMar,
  483. rcBox.right,
  484. yTopMar + nLines * yChar);
  485. // xCenter is used to center the OK and CANCEL buttons horizontally
  486. xCenter = (rcBox.right - rcBox.left - xButton * 3) / 4;
  487. // yMiniBotMar is the spacing above and below the button
  488. yMiniBotMar = (VERTMARGIN * yBU) / 8 + yLeftOver / 4;
  489. SetWindowPos(
  490. GetDlgItem(hWnd, IDOK),
  491. NULL,
  492. rcBox.left + xCenter,
  493. rcBox.bottom + yMiniBotMar,
  494. 0L,
  495. 0L,
  496. SWP_NOSIZE | SWP_NOZORDER);
  497. SetWindowPos(
  498. GetDlgItem(hWnd, IDCANCEL),
  499. NULL,
  500. rcBox.left + xButton + xCenter * 2,
  501. rcBox.bottom + yMiniBotMar,
  502. 0L,
  503. 0L,
  504. SWP_NOSIZE | SWP_NOZORDER);
  505. SetWindowPos(
  506. GetDlgItem(hWnd, IDH_DLG_MIDI_PATCHEDIT),
  507. NULL,
  508. rcBox.left + xButton * 2 + xCenter * 3,
  509. rcBox.bottom + yMiniBotMar,
  510. 0L,
  511. 0L,
  512. SWP_NOSIZE | SWP_NOZORDER);
  513. // get the banana button
  514. hBanana = GetDlgItem(hWnd, ID_PATCHBASED);
  515. // get the rectangle of the banana button
  516. GetClientRect(hBanana, &rcBanana);
  517. // set the banana position
  518. SetWindowPos(
  519. hBanana,
  520. NULL,
  521. rcBox.left + (rcBox.right - rcBox.left - rcBanana.right) / 2,
  522. (6 * yBU) / 8,
  523. 0L,
  524. 0L,
  525. SWP_NOSIZE | SWP_NOZORDER);
  526. SetWindowPos(
  527. hScroll,
  528. NULL,
  529. rcBox.right,
  530. rcBox.top,
  531. GetSystemMetrics(SM_CXVSCROLL),
  532. rcBox.bottom - rcBox.top + 1,
  533. SWP_NOZORDER);
  534. iVertMax = max(0, MIDIPATCHSIZE - nLines);
  535. iVertPos = min(iVertMax, iVertPos);
  536. SetScrollRange(hScroll, SB_CTL, 0, iVertMax, FALSE);
  537. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  538. if (iCurPos >= 0 && iCurPos < nLines)
  539. PatchSetFocus(hDlg, PSF_SHOWIFHIDDEN, 1);
  540. else
  541. PatchActiveLine(PAL_HIDE, SWP_NOREDRAW);
  542. } /* PatchSize */
  543. /*
  544. * PATCHPAINT
  545. */
  546. static
  547. VOID PASCAL PatchPaint(VOID)
  548. {
  549. HPEN hPen = 0;
  550. PATCHMAP FAR* lpPatch;
  551. PAINTSTRUCT ps;
  552. int i,
  553. iVert,
  554. iLeft,
  555. nBegin,
  556. nEnd,
  557. iTop,
  558. iBottom;
  559. BOOL fSelected = FALSE;
  560. char szBuf [50];
  561. BeginPaint(hWnd, &ps);
  562. if (!ps.rcPaint.bottom)
  563. goto DonePainting;
  564. hPen = SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
  565. hFont = SelectObject(ps.hdc, hFont);
  566. fSelected = TRUE;
  567. SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
  568. SetBkMode(ps.hdc, TRANSPARENT);
  569. if (ps.rcPaint.top < rcBox.top) {
  570. iVert = rcBox.top - yChar + 5;
  571. TextOut(ps.hdc, 11, iVert, aszSourcePatch, lstrlen(aszSourcePatch));
  572. TextOut(ps.hdc, rgxPos [1] + xChar * 2 - 15, iVert,
  573. aszSourcePatchName, lstrlen(aszSourcePatchName));
  574. }
  575. // calculate top and bottom y coordinates of invalid area
  576. iTop = max(ps.rcPaint.top, rcBox.top);
  577. // if top is below the box, forget about painting
  578. if (iTop > rcBox.bottom)
  579. goto DonePainting;
  580. iBottom = min(ps.rcPaint.bottom, rcBox.bottom);
  581. // calculate left x coordinate of invalid area
  582. iLeft = max(ps.rcPaint.left, rcBox.left);
  583. // calculate beginning and ending data row to be repainted
  584. nBegin = max(0, (iTop - rcBox.top) / yChar);
  585. nEnd = min(nLines, (iBottom - rcBox.top) / yChar);
  586. for (i = 0; i < 6; i++) {
  587. MMoveTo(ps.hdc, rgxPos [i], iTop);
  588. LineTo(ps.hdc, rgxPos [i], iBottom + 1);
  589. }
  590. // vertical position of first line we have to draw
  591. iVert = rcBox.top + nBegin * yChar;
  592. // lock the map
  593. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  594. for (i = nBegin; i <= nEnd; i++, iVert += yChar) {
  595. MMoveTo(ps.hdc, iLeft, iVert);
  596. LineTo(ps.hdc, min(ps.rcPaint.right, rcBox.right), iVert);
  597. if (i == nLines)
  598. break;
  599. if (iLeft < rgxPos [1]) {
  600. wsprintf(szBuf, aszPatchNumFormat, iVertPos + iPatchBase + i);
  601. TextOut(ps.hdc, rgxPos [0] + xChar, iVert + 2,
  602. szBuf, 3);
  603. }
  604. if (iLeft < rgxPos [2]) {
  605. if (!LoadString(hLibInst, IDS_PATCHMAP_BASE +
  606. iVertPos + i + 1, szBuf, sizeof(szBuf)))
  607. LoadString(hLibInst, IDS_RESERVED, szBuf, sizeof(szBuf));
  608. TextOut(ps.hdc, rgxPos [1] + 2, iVert + 2,
  609. szBuf, lstrlen(szBuf));
  610. }
  611. if (i == iCurPos)
  612. continue;
  613. if (iLeft < rgxPos [3]) {
  614. wsprintf(szBuf, aszPatchNumFormat, lpPatch->keymaps[iVertPos + i].bDestination + iPatchBase);
  615. TextOut(ps.hdc, rgxPos [2] + xChar * 2, iVert + 2,
  616. szBuf, 3);
  617. }
  618. if (iLeft < rgxPos [4]) {
  619. wsprintf(szBuf, aszPatchNumFormat, lpPatch->keymaps[iVertPos + i].bVolume);
  620. TextOut(ps.hdc, rgxPos [3] + xChar * 2, iVert + 2,
  621. szBuf, 3);
  622. }
  623. if (iLeft < rgxPos [5])
  624. TextOut(ps.hdc, rgxPos [4] + 2, iVert + 2, lpPatch->keymaps[iVertPos + i].aszKeyMapName,
  625. lstrlen(lpPatch->keymaps[iVertPos + i].aszKeyMapName));
  626. }
  627. GlobalUnlock(hPatchMap);
  628. DonePainting:
  629. if (fSelected) {
  630. hFont = SelectObject(ps.hdc, hFont);
  631. hPen = SelectObject(ps.hdc, hPen);
  632. }
  633. EndPaint(hWnd, &ps);
  634. } /* PatchPaint */
  635. /*
  636. * PATCHARROWSCROLL
  637. *
  638. * Interpret a scroll message for the arrow control.
  639. */
  640. static
  641. VOID PASCAL PatchArrowScroll( WPARAM wParam, // scroll code only (even on 32 bit)
  642. LPARAM lParam ) // (hwnd,posn) (16 bit), hwnd (32 bit)
  643. // posn not actually used.
  644. {
  645. PATCHMAP FAR* lpPatch;
  646. UINT uId;
  647. BYTE bPatch,
  648. bMax,
  649. bMin;
  650. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  651. #if defined(WIN16)
  652. if ((HWND)HIWORD(lParam) == hArrow) {
  653. #else
  654. if ((HWND)lParam == hArrow) {
  655. #endif
  656. uId = ID_PATCHNUMEDIT;
  657. bPatch = lpPatch->keymaps[iVertPos + iCurPos].bDestination + (BYTE)iPatchBase;
  658. bMax = (BYTE)(127 + iPatchBase); // MMAP_MAXPATCHES
  659. bMin = (BYTE)iPatchBase;
  660. }
  661. else {
  662. uId = ID_PATCHVOLEDIT;
  663. bPatch = lpPatch->keymaps[iVertPos + iCurPos].bVolume;
  664. bMax = 200; // MMAP_MAXVOLUME
  665. bMin = 0;
  666. }
  667. GlobalUnlock(hPatchMap);
  668. switch (wParam) {
  669. case SB_LINEDOWN :
  670. if (bPatch-- == bMin)
  671. bPatch = bMax;
  672. break;
  673. case SB_LINEUP :
  674. if (bPatch++ == bMax)
  675. bPatch = bMin;
  676. break;
  677. default:
  678. break;
  679. }
  680. SetDlgItemInt(hWnd, uId, bPatch, FALSE);
  681. } /* PatchArrowScroll */
  682. /*
  683. * PATCHWINDOWSCROLL
  684. */
  685. static
  686. VOID PASCAL PatchWindowScroll( HWND hDlg,
  687. UINT wParam,
  688. int iPos )
  689. {
  690. HDC hDC;
  691. RECT rc;
  692. int iVertInc;
  693. BOOL fWillBeVisible; // will it be visible after scroll?
  694. switch (wParam) {
  695. case SB_LINEUP :
  696. iVertInc = -1;
  697. break;
  698. case SB_LINEDOWN :
  699. iVertInc = 1;
  700. break;
  701. case SB_PAGEUP :
  702. iVertInc = min(-1, -nLines);
  703. break;
  704. case SB_PAGEDOWN :
  705. iVertInc = max(1, nLines);
  706. break;
  707. case SB_THUMBTRACK :
  708. case SB_THUMBPOSITION :
  709. iVertInc = iPos - iVertPos;
  710. break;
  711. default :
  712. iVertInc = 0;
  713. }
  714. iVertInc = max(-iVertPos, min(iVertInc, iVertMax - iVertPos));
  715. if (iVertInc != 0)
  716. {
  717. iVertPos += iVertInc;
  718. iCurPos -= iVertInc;
  719. if (iCurPos < 0 || iCurPos >= nLines) {
  720. SetFocus(NULL);
  721. fWillBeVisible = FALSE;
  722. }
  723. else
  724. fWillBeVisible = TRUE;
  725. // Scroll to the correct position
  726. SetScrollPos(hScroll, SB_CTL, iVertPos, TRUE);
  727. hDC = GetDC(hWnd);
  728. ScrollDC(hDC, 0L, -yChar * iVertInc, &rcBox, &rcBox, NULL, &rc);
  729. ReleaseDC(hWnd, hDC);
  730. if (!fHidden)
  731. PatchActiveLine(PAL_HIDE, SWP_NOREDRAW);
  732. if (fWillBeVisible) {
  733. PatchSetFocus(hDlg, 0L, 0L);
  734. PatchActiveLine(PAL_SHOW, SWP_NOREDRAW);
  735. }
  736. InvalidateRect(hWnd, &rc, TRUE);
  737. UpdateWindow(hWnd);
  738. }
  739. } /* PatchWindowScroll */
  740. /*
  741. * PatchEditMsg
  742. *
  743. * This function deals with EN_UPDATE and EN_ACTIVATE messages sent
  744. * to the patch number and volume percent edit controls through the
  745. * WM_COMMAND message.
  746. */
  747. static
  748. VOID PASCAL PatchEditMsg( UINT id, WORD NotifCode )
  749. {
  750. PATCHMAP FAR* lpPatch;
  751. UINT
  752. uVal, // value of control
  753. uMin, // min value allowed
  754. uMax; // max value allowed
  755. BOOL bTranslate;
  756. if (NotifCode != EN_UPDATE && NotifCode != EN_ACTIVATE)
  757. return;
  758. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  759. switch (NotifCode) {
  760. case EN_UPDATE :
  761. if (id == ID_PATCHNUMEDIT) {
  762. uMax = 127 + iPatchBase;// MMAP_MAXPATCHES
  763. uMin = iPatchBase;
  764. }
  765. else {
  766. uMax = 200; // MMAP_MAXVOLUME
  767. uMin = 0;
  768. }
  769. uVal = (UINT)GetDlgItemInt(hWnd, id, &bTranslate, TRUE);
  770. if ((int)uVal < (int)uMin) {
  771. uVal = uMin;
  772. SetDlgItemInt(hWnd, id, uVal, FALSE);
  773. } else if (uVal > uMax) {
  774. uVal = uMax;
  775. SetDlgItemInt(hWnd, id, uVal, FALSE);
  776. } else {
  777. if (id == ID_PATCHNUMEDIT) {
  778. uVal -= iPatchBase;
  779. if (uVal != lpPatch->keymaps[iVertPos + iCurPos].bDestination) {
  780. lpPatch->keymaps[iVertPos + iCurPos].bDestination = (BYTE)uVal;
  781. Modify(TRUE);
  782. }
  783. } else if (uVal != lpPatch->keymaps[iVertPos + iCurPos].bVolume) {
  784. lpPatch->keymaps[iVertPos + iCurPos].bVolume = (BYTE)uVal;
  785. Modify(TRUE);
  786. }
  787. }
  788. break;
  789. case EN_ACTIVATE :
  790. if (id == ID_PATCHNUMEDIT)
  791. SetDlgItemInt(hWnd, id, lpPatch->keymaps[iVertPos + iCurPos].bDestination + iPatchBase, FALSE);
  792. else
  793. SetDlgItemInt(hWnd, id, lpPatch->keymaps[iVertPos + iCurPos].bVolume, FALSE);
  794. break;
  795. default :
  796. break;
  797. }
  798. GlobalUnlock(hPatchMap);
  799. } /* PatchEditMsg */
  800. /*
  801. * PatchComboMsg
  802. *
  803. * This function deals with the CBN_ACTIVATE and CBN_SELCHANGE messages sent
  804. * to the keymap name combo box through the WM_COMMAND message.
  805. */
  806. static
  807. VOID PASCAL PatchComboMsg(HWND hDlg, WORD NotifCode)
  808. {
  809. PATCHMAP FAR* lpPatch;
  810. char szBuf [MMAP_MAXNAME];
  811. if (NotifCode != CBN_ACTIVATE && NotifCode != CBN_SELCHANGE)
  812. return;
  813. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  814. switch (NotifCode) {
  815. case CBN_ACTIVATE :
  816. SendMessage(hCombo, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)(lpPatch->keymaps[iVertPos + iCurPos].aszKeyMapName));
  817. break;
  818. case CBN_SELCHANGE:
  819. GetWindowText(hCombo, szBuf, MMAP_MAXNAME);
  820. if (!lstrcmpi(szBuf, lpPatch->keymaps[iVertPos + iCurPos].aszKeyMapName))
  821. break;
  822. lstrcpy(lpPatch->keymaps[iVertPos + iCurPos].aszKeyMapName, szBuf);
  823. Modify(TRUE);
  824. break;
  825. default :
  826. break;
  827. }
  828. GlobalUnlock(hPatchMap);
  829. } /* PatchComboMsg */
  830. /*
  831. * PATCHBUTTONDOWN
  832. */
  833. static
  834. VOID PASCAL PatchButtonDown(HWND hDlg, LONG lParam)
  835. {
  836. int x = LOWORD(lParam),
  837. y = HIWORD(lParam),
  838. iPos;
  839. UINT uFlags;
  840. if (x < rcBox.left || x > rcBox.right)
  841. return;
  842. if (y < rcBox.top || y > rcBox.bottom)
  843. return;
  844. iPos = min(nLines - 1, (y - rcBox.top) / yChar);
  845. if (iPos == iCurPos)
  846. return;
  847. if (iCurPos >= 0 && iCurPos < nLines) {
  848. uFlags = PSF_REDRAW;
  849. SendMessage(hCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0);
  850. UpdateWindow(hWnd);
  851. }
  852. else
  853. uFlags = PSF_SHOWIFHIDDEN;
  854. iCurPos = iPos;
  855. PatchSetFocus(hDlg, uFlags, x);
  856. } /* PatchButtonDown */
  857. /*
  858. * PATCHSETFOCUS
  859. */
  860. static
  861. VOID PASCAL PatchSetFocus( HWND hDlg,
  862. UINT uFlags,
  863. int xPos )
  864. {
  865. RECT rc;
  866. int yPos = rcBox.top + iCurPos * yChar;
  867. PatchEditMsg(ID_PATCHNUMEDIT, EN_ACTIVATE);
  868. PatchEditMsg(ID_PATCHVOLEDIT, EN_ACTIVATE);
  869. PatchComboMsg(hDlg, CBN_ACTIVATE);
  870. GetWindowRect(hEdit, &rc);
  871. SetWindowPos(hEdit, NULL, rgxPos [2], yPos, 0L, 0L,
  872. SWP_NOZORDER | SWP_NOSIZE);
  873. SetWindowPos(hArrow, NULL, rgxPos [2] + xArrowOffset, yPos, 0L,
  874. 0L, SWP_NOZORDER | SWP_NOSIZE);
  875. SetWindowPos(hVolEdit, NULL, rgxPos [3], yPos, 0L, 0L,
  876. SWP_NOZORDER | SWP_NOSIZE);
  877. SetWindowPos(hVolArrow, NULL, rgxPos [3] + xVolArrowOffset, yPos,
  878. 0L, 0L, SWP_NOZORDER | SWP_NOSIZE);
  879. SetWindowPos(hCombo, NULL, rgxPos [4], yPos, 0L, 0L,
  880. SWP_NOZORDER | SWP_NOSIZE);
  881. if (fHidden && uFlags & PSF_SHOWIFHIDDEN) {
  882. PatchActiveLine(PAL_SHOW, 0L);
  883. UpdateWindow(hEdit);
  884. UpdateWindow(hArrow);
  885. UpdateWindow(hVolEdit);
  886. UpdateWindow(hVolArrow);
  887. UpdateWindow(hCombo);
  888. }
  889. if (uFlags & PSF_REDRAW && rc.right) {
  890. ScreenToClient(hWnd, (LPPOINT)&rc);
  891. ScreenToClient(hWnd, (LPPOINT)&rc + 1);
  892. rc.right = rcBox.right + 1;
  893. InvalidateRect(hWnd, &rc, FALSE);
  894. UpdateWindow(hWnd);
  895. }
  896. if (xPos < rgxPos [3]) {
  897. if (!fHidden)
  898. SetFocus(hEdit);
  899. #if defined(WIN16)
  900. SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
  901. #else
  902. SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  903. #endif //WIN16
  904. }
  905. else if (xPos < rgxPos [4]) {
  906. if (!fHidden)
  907. SetFocus(hVolEdit);
  908. #if defined(WIN16)
  909. SendMessage(hVolEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
  910. #else
  911. SendMessage(hVolEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  912. #endif //WIN16
  913. }
  914. else if (xPos < rgxPos [5] && !fHidden)
  915. SetFocus(hCombo);
  916. } /* PatchSetFocus */
  917. /*
  918. * PATCHACTIVELINE
  919. */
  920. static
  921. VOID PASCAL PatchActiveLine( UINT uCase,
  922. UINT uFlags )
  923. {
  924. static const UINT uDefFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
  925. switch (uCase) {
  926. case PAL_SHOW :
  927. if (!fHidden)
  928. return;
  929. uFlags |= SWP_SHOWWINDOW;
  930. fHidden = FALSE;
  931. break;
  932. case PAL_HIDE :
  933. if (fHidden)
  934. return;
  935. uFlags |= SWP_HIDEWINDOW;
  936. fHidden = TRUE;
  937. break;
  938. default :
  939. break;
  940. }
  941. uFlags |= uDefFlags;
  942. SetWindowPos(hEdit, NULL, 0L, 0L, 0L, 0L, uFlags);
  943. SetWindowPos(hArrow, NULL, 0L, 0L, 0L, 0L, uFlags);
  944. SetWindowPos(hVolEdit, NULL, 0L, 0L, 0L, 0L, uFlags);
  945. SetWindowPos(hVolArrow, NULL, 0L, 0L, 0L, 0L, uFlags);
  946. SetWindowPos(hCombo, NULL, 0L, 0L, 0L, 0L, uFlags);
  947. if (uCase == PAL_SHOW && !fHidden)
  948. SetFocus(hEdit);
  949. } /* PatchActiveLine */
  950. /*
  951. * PATCHSAVE
  952. */
  953. static int PASCAL PatchSave(
  954. HWND hDlg,
  955. BOOL bQuery)
  956. {
  957. PATCHMAP FAR* lpPatch;
  958. MMAPERR mmaperr;
  959. int iRet = 0; // a value other than IDCANCEL or IDYES
  960. if (bQuery) {
  961. iRet = QuerySave();
  962. if (iRet != IDYES)
  963. return iRet;
  964. }
  965. lpPatch = (PATCHMAP FAR*)GlobalLock(hPatchMap);
  966. mmaperr = mapWrite(MMAP_PATCH, lpPatch);
  967. GlobalUnlock(hPatchMap);
  968. if (mmaperr != MMAPERR_SUCCESS) {
  969. VShowError(hDlg, mmaperr);
  970. return IDCANCEL;
  971. }
  972. Modify(FALSE);
  973. if (fNew)
  974. fNew = FALSE;
  975. return iRet;
  976. } /* PatchSave */