RunnerMFC.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /* RunnerMFC.cpp
  2. *
  3. * Copyright (C) 2001-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. * a selection of changes:
  20. * pb 2002/07/08 goodness
  21. * pb 2005/11/21 play again
  22. * pb 2005/12/02 response sounds are played
  23. * pb 2005/12/04 oops button
  24. * pb 2005/12/08 multiple experiments
  25. * pb 2011/03/03 reaction times for mouse clicks
  26. * pb 2011/04/14 reaction times for key presses
  27. */
  28. #include "RunnerMFC.h"
  29. #include "EditorM.h"
  30. #include "machine.h"
  31. Thing_implement (RunnerMFC, Editor, 0);
  32. void structRunnerMFC :: v_destroy () noexcept {
  33. our RunnerMFC_Parent :: v_destroy ();
  34. }
  35. void structRunnerMFC :: v_dataChanged () {
  36. Graphics_updateWs (our graphics.get());
  37. }
  38. static int RunnerMFC_startExperiment (RunnerMFC me) {
  39. my data = my experiments->at [my iexperiment];
  40. Melder_assert (my data -> classInfo == classExperimentMFC);
  41. ExperimentMFC_start ((ExperimentMFC) my data);
  42. Thing_setName (me, ((ExperimentMFC) my data) -> name.get());
  43. Editor_broadcastDataChanged (me);
  44. Graphics_updateWs (my graphics.get());
  45. return 1;
  46. }
  47. static void drawControlButton (RunnerMFC me, double left, double right, double bottom, double top, conststring32 visibleText) {
  48. Graphics_setColour (my graphics.get(), Graphics_MAROON);
  49. Graphics_setLineWidth (my graphics.get(), 3.0);
  50. Graphics_fillRectangle (my graphics.get(), left, right, bottom, top);
  51. Graphics_setColour (my graphics.get(), Graphics_YELLOW);
  52. Graphics_rectangle (my graphics.get(), left, right, bottom, top);
  53. Graphics_text (my graphics.get(), 0.5 * (left + right), 0.5 * (bottom + top), visibleText);
  54. }
  55. static void drawNow (RunnerMFC me) {
  56. if (! my graphics) return; // could be the case in the very beginning
  57. ExperimentMFC experiment = (ExperimentMFC) my data;
  58. integer iresponse;
  59. if (! my data) return;
  60. Graphics_setGrey (my graphics.get(), 0.8);
  61. Graphics_fillRectangle (my graphics.get(), 0.0, 1.0, 0.0, 1.0);
  62. Graphics_setGrey (my graphics.get(), 0.0);
  63. if (my blanked) return;
  64. if (experiment -> trial == 0) {
  65. Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_HALF);
  66. Graphics_setFontSize (my graphics.get(), 24);
  67. Graphics_text (my graphics.get(), 0.5, 0.5, experiment -> startText.get());
  68. } else if (experiment -> pausing) {
  69. Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_HALF);
  70. Graphics_setFontSize (my graphics.get(), 24);
  71. Graphics_text (my graphics.get(), 0.5, 0.5, experiment -> pauseText.get());
  72. if (experiment -> oops_right > experiment -> oops_left && experiment -> trial > 1) {
  73. drawControlButton (me,
  74. experiment -> oops_left, experiment -> oops_right, experiment -> oops_bottom, experiment -> oops_top,
  75. experiment -> oops_label.get()
  76. );
  77. }
  78. } else if (experiment -> trial <= experiment -> numberOfTrials) {
  79. conststring32 visibleText = experiment -> stimulus [experiment -> stimuli [experiment -> trial]]. visibleText.get();
  80. autostring32 visibleText_dup = Melder_dup_f (visibleText ? visibleText : U"");
  81. conststring32 visibleText_p = visibleText_dup.get();
  82. Graphics_setFont (my graphics.get(), kGraphics_font::TIMES);
  83. Graphics_setFontSize (my graphics.get(), 10);
  84. Graphics_setColour (my graphics.get(), Graphics_BLACK);
  85. Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_TOP);
  86. Graphics_text (my graphics.get(), 0.0, 1.0, experiment -> trial, U" / ", experiment -> numberOfTrials);
  87. Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_TOP);
  88. Graphics_setFontSize (my graphics.get(), 24);
  89. /*
  90. * The run text.
  91. */
  92. if (visibleText_p [0] != U'\0') {
  93. char32 *visibleText_q = str32chr (visibleText_p, U'|');
  94. if (visibleText_q)
  95. *visibleText_q = U'\0';
  96. Graphics_text (my graphics.get(), 0.5, 1.0, visibleText_p [0] != U'\0' ? visibleText_p : experiment -> runText.get());
  97. if (visibleText_q)
  98. visibleText_p = visibleText_q + 1;
  99. else
  100. visibleText_p += str32len (visibleText_p);
  101. } else {
  102. Graphics_text (my graphics.get(), 0.5, 1.0, experiment -> runText.get());
  103. }
  104. Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_HALF);
  105. for (iresponse = 1; iresponse <= experiment -> numberOfDifferentResponses; iresponse ++) {
  106. ResponseMFC response = & experiment -> response [iresponse];
  107. conststring32 textToDraw = response -> label.get(); // can be overridden
  108. if (visibleText_p [0] != U'\0') {
  109. char32 *visibleText_q = str32chr (visibleText_p, U'|');
  110. if (visibleText_q) *visibleText_q = U'\0';
  111. textToDraw = visibleText_p; // override
  112. if (visibleText_q) visibleText_p = visibleText_q + 1; else visibleText_p += str32len (visibleText_p);
  113. }
  114. if (str32nequ (textToDraw, U"\\FI", 3)) {
  115. structMelderFile file { };
  116. MelderDir_relativePathToFile (& experiment -> rootDirectory, textToDraw + 3, & file);
  117. Graphics_imageFromFile (my graphics.get(), Melder_fileToPath (& file), response -> left, response -> right, response -> bottom, response -> top);
  118. } else {
  119. Graphics_setColour (my graphics.get(),
  120. response -> name [0] == U'\0' ? Graphics_SILVER :
  121. experiment -> responses [experiment -> trial] == iresponse ? Graphics_RED :
  122. experiment -> ok_right > experiment -> ok_left || experiment -> responses [experiment -> trial] == 0 ?
  123. Graphics_YELLOW : Graphics_SILVER
  124. );
  125. Graphics_setLineWidth (my graphics.get(), 3.0);
  126. Graphics_fillRectangle (my graphics.get(), response -> left, response -> right, response -> bottom, response -> top);
  127. Graphics_setColour (my graphics.get(), Graphics_MAROON);
  128. Graphics_rectangle (my graphics.get(), response -> left, response -> right, response -> bottom, response -> top);
  129. Graphics_setFontSize (my graphics.get(), response -> fontSize ? response -> fontSize : 24);
  130. Graphics_text (my graphics.get(), 0.5 * (response -> left + response -> right),
  131. 0.5 * (response -> bottom + response -> top), textToDraw);
  132. }
  133. Graphics_setFontSize (my graphics.get(), 24);
  134. }
  135. for (iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
  136. GoodnessMFC goodness = & experiment -> goodness [iresponse];
  137. Graphics_setColour (my graphics.get(), experiment -> responses [experiment -> trial] == 0 ? Graphics_SILVER :
  138. experiment -> goodnesses [experiment -> trial] == iresponse ? Graphics_RED : Graphics_YELLOW);
  139. Graphics_setLineWidth (my graphics.get(), 3.0);
  140. Graphics_fillRectangle (my graphics.get(), goodness -> left, goodness -> right, goodness -> bottom, goodness -> top);
  141. Graphics_setColour (my graphics.get(), Graphics_MAROON);
  142. Graphics_rectangle (my graphics.get(), goodness -> left, goodness -> right, goodness -> bottom, goodness -> top);
  143. Graphics_setFontSize (my graphics.get(), goodness -> fontSize ? goodness -> fontSize : 24);
  144. Graphics_text (my graphics.get(),
  145. 0.5 * (goodness -> left + goodness -> right),
  146. 0.5 * (goodness -> bottom + goodness -> top),
  147. goodness -> label.get()
  148. );
  149. Graphics_setFontSize (my graphics.get(), 24);
  150. }
  151. if (experiment -> replay_right > experiment -> replay_left && my numberOfReplays < experiment -> maximumNumberOfReplays) {
  152. drawControlButton (me,
  153. experiment -> replay_left, experiment -> replay_right, experiment -> replay_bottom, experiment -> replay_top,
  154. experiment -> replay_label.get()
  155. );
  156. }
  157. if (experiment -> ok_right > experiment -> ok_left &&
  158. experiment -> responses [experiment -> trial] != 0 &&
  159. (experiment -> numberOfGoodnessCategories == 0 || experiment -> goodnesses [experiment -> trial] != 0))
  160. {
  161. drawControlButton (me,
  162. experiment -> ok_left, experiment -> ok_right, experiment -> ok_bottom, experiment -> ok_top,
  163. experiment -> ok_label.get()
  164. );
  165. }
  166. if (experiment -> oops_right > experiment -> oops_left && experiment -> trial > 1) {
  167. drawControlButton (me,
  168. experiment -> oops_left, experiment -> oops_right, experiment -> oops_bottom, experiment -> oops_top,
  169. experiment -> oops_label.get()
  170. );
  171. }
  172. } else {
  173. Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_HALF);
  174. Graphics_setFontSize (my graphics.get(), 24);
  175. Graphics_text (my graphics.get(), 0.5, 0.5, experiment -> endText.get());
  176. if (experiment -> oops_right > experiment -> oops_left && experiment -> trial > 1) {
  177. drawControlButton (me,
  178. experiment -> oops_left, experiment -> oops_right, experiment -> oops_bottom, experiment -> oops_top,
  179. experiment -> oops_label.get()
  180. );
  181. }
  182. }
  183. }
  184. static void gui_drawingarea_cb_expose (RunnerMFC me, GuiDrawingArea_ExposeEvent event) {
  185. Melder_assert (event -> widget == my d_drawingArea);
  186. drawNow (me);
  187. }
  188. static void gui_drawingarea_cb_resize (RunnerMFC me, GuiDrawingArea_ResizeEvent event) {
  189. if (! my graphics) return;
  190. Graphics_setWsViewport (my graphics.get(), 0.0, event -> width, 0.0, event -> height);
  191. Graphics_setWsWindow (my graphics.get(), 0.0, event -> width, 0.0, event -> height);
  192. Graphics_setViewport (my graphics.get(), 0.0, event -> width, 0.0, event -> height);
  193. Graphics_updateWs (my graphics.get());
  194. }
  195. static void do_ok (RunnerMFC me) {
  196. ExperimentMFC experiment = (ExperimentMFC) my data;
  197. Melder_assert (experiment -> trial >= 1 && experiment -> trial <= experiment -> numberOfTrials);
  198. my numberOfReplays = 0;
  199. if (experiment -> trial == experiment -> numberOfTrials) {
  200. experiment -> trial ++;
  201. Editor_broadcastDataChanged (me);
  202. Graphics_updateWs (my graphics.get());
  203. } else if (experiment -> breakAfterEvery != 0 && experiment -> trial % experiment -> breakAfterEvery == 0) {
  204. experiment -> pausing = true;
  205. Editor_broadcastDataChanged (me);
  206. Graphics_updateWs (my graphics.get());
  207. } else {
  208. experiment -> trial ++;
  209. Editor_broadcastDataChanged (me);
  210. if (experiment -> blankWhilePlaying) {
  211. my blanked = true;
  212. drawNow (me);
  213. Graphics_flushWs (my graphics.get());
  214. }
  215. if (experiment -> stimuliAreSounds) {
  216. autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
  217. if (experiment -> blankWhilePlaying)
  218. MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel::SYNCHRONOUS);
  219. ExperimentMFC_playStimulus (experiment, experiment -> stimuli [experiment -> trial]);
  220. }
  221. my blanked = false;
  222. Graphics_updateWs (my graphics.get());
  223. }
  224. }
  225. static void do_oops (RunnerMFC me) {
  226. ExperimentMFC experiment = (ExperimentMFC) my data;
  227. Melder_assert (experiment -> trial >= 2 && experiment -> trial <= experiment -> numberOfTrials + 1);
  228. if (experiment -> trial <= experiment -> numberOfTrials) {
  229. experiment -> responses [experiment -> trial] = 0;
  230. experiment -> goodnesses [experiment -> trial] = 0;
  231. }
  232. experiment -> trial --;
  233. experiment -> responses [experiment -> trial] = 0;
  234. experiment -> goodnesses [experiment -> trial] = 0;
  235. experiment -> pausing = false;
  236. my numberOfReplays = 0;
  237. Editor_broadcastDataChanged (me);
  238. if (experiment -> blankWhilePlaying) {
  239. my blanked = true;
  240. drawNow (me);
  241. Graphics_flushWs (my graphics.get());
  242. }
  243. if (experiment -> stimuliAreSounds) {
  244. autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
  245. if (experiment -> blankWhilePlaying)
  246. MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel::SYNCHRONOUS);
  247. ExperimentMFC_playStimulus (experiment, experiment -> stimuli [experiment -> trial]);
  248. }
  249. my blanked = false;
  250. Graphics_updateWs (my graphics.get());
  251. }
  252. static void do_replay (RunnerMFC me) {
  253. ExperimentMFC experiment = (ExperimentMFC) my data;
  254. Melder_assert (experiment -> trial >= 1 && experiment -> trial <= experiment -> numberOfTrials);
  255. my numberOfReplays ++;
  256. Editor_broadcastDataChanged (me);
  257. if (experiment -> blankWhilePlaying) {
  258. my blanked = true;
  259. drawNow (me);
  260. Graphics_flushWs (my graphics.get());
  261. }
  262. if (experiment -> stimuliAreSounds) {
  263. autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
  264. if (experiment -> blankWhilePlaying)
  265. MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel::SYNCHRONOUS);
  266. ExperimentMFC_playStimulus (experiment, experiment -> stimuli [experiment -> trial]);
  267. }
  268. my blanked = false;
  269. Graphics_updateWs (my graphics.get());
  270. }
  271. static void gui_drawingarea_cb_click (RunnerMFC me, GuiDrawingArea_ClickEvent event) {
  272. if (! my graphics) return; // could be the case in the very beginning
  273. ExperimentMFC experiment = (ExperimentMFC) my data;
  274. if (! my data) return;
  275. double reactionTime = Melder_clock () - experiment -> startingTime;
  276. if (! experiment -> blankWhilePlaying)
  277. reactionTime -= experiment -> stimulusInitialSilenceDuration;
  278. double x, y;
  279. Graphics_DCtoWC (my graphics.get(), event -> x, event -> y, & x, & y);
  280. if (experiment -> trial == 0) { // the first click of the experiment
  281. experiment -> trial ++;
  282. Editor_broadcastDataChanged (me);
  283. if (experiment -> blankWhilePlaying) {
  284. my blanked = true;
  285. drawNow (me);
  286. Graphics_flushWs (my graphics.get());
  287. }
  288. if (experiment -> stimuliAreSounds) {
  289. if (experiment -> numberOfTrials < 1) {
  290. Melder_flushError (U"There are zero trials in this experiment.");
  291. forget (me);
  292. return;
  293. }
  294. autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
  295. if (experiment -> blankWhilePlaying)
  296. MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel::SYNCHRONOUS);
  297. ExperimentMFC_playStimulus (experiment, experiment -> stimuli [1]); // works only if there is at least one trial
  298. }
  299. my blanked = false;
  300. Graphics_updateWs (my graphics.get());
  301. } else if (experiment -> pausing) { // a click to leave the break
  302. if (x > experiment -> oops_left && x < experiment -> oops_right &&
  303. y > experiment -> oops_bottom && y < experiment -> oops_top && experiment -> trial > 1)
  304. {
  305. do_oops (me);
  306. } else {
  307. experiment -> pausing = false;
  308. experiment -> trial ++;
  309. Editor_broadcastDataChanged (me);
  310. if (experiment -> blankWhilePlaying) {
  311. my blanked = true;
  312. drawNow (me);
  313. Graphics_flushWs (my graphics.get());
  314. }
  315. if (experiment -> stimuliAreSounds) {
  316. autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
  317. if (experiment -> blankWhilePlaying)
  318. MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel::SYNCHRONOUS);
  319. ExperimentMFC_playStimulus (experiment, experiment -> stimuli [experiment -> trial]);
  320. }
  321. my blanked = false;
  322. Graphics_updateWs (my graphics.get());
  323. }
  324. } else if (experiment -> trial <= experiment -> numberOfTrials) {
  325. if (x > experiment -> ok_left && x < experiment -> ok_right &&
  326. y > experiment -> ok_bottom && y < experiment -> ok_top &&
  327. experiment -> responses [experiment -> trial] != 0 &&
  328. (experiment -> numberOfGoodnessCategories == 0 || experiment -> goodnesses [experiment -> trial] != 0))
  329. {
  330. do_ok (me);
  331. } else if (x > experiment -> replay_left && x < experiment -> replay_right &&
  332. y > experiment -> replay_bottom && y < experiment -> replay_top &&
  333. my numberOfReplays < experiment -> maximumNumberOfReplays)
  334. {
  335. do_replay (me);
  336. } else if (x > experiment -> oops_left && x < experiment -> oops_right &&
  337. y > experiment -> oops_bottom && y < experiment -> oops_top)
  338. {
  339. if (experiment -> trial > 1) {
  340. do_oops (me);
  341. }
  342. } else if (experiment -> responses [experiment -> trial] == 0 || experiment -> ok_right > experiment -> ok_left) {
  343. for (integer iresponse = 1; iresponse <= experiment -> numberOfDifferentResponses; iresponse ++) {
  344. ResponseMFC response = & experiment -> response [iresponse];
  345. if (x > response -> left && x < response -> right && y > response -> bottom && y < response -> top && response -> name [0] != '\0') {
  346. experiment -> responses [experiment -> trial] = iresponse;
  347. experiment -> reactionTimes [experiment -> trial] = reactionTime;
  348. if (experiment -> responsesAreSounds) {
  349. ExperimentMFC_playResponse (experiment, iresponse);
  350. }
  351. if (experiment -> ok_right <= experiment -> ok_left && experiment -> numberOfGoodnessCategories == 0) {
  352. do_ok (me);
  353. } else {
  354. Editor_broadcastDataChanged (me);
  355. Graphics_updateWs (my graphics.get());
  356. }
  357. }
  358. }
  359. if (experiment -> responses [experiment -> trial] != 0 && experiment -> ok_right > experiment -> ok_left) {
  360. for (integer iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
  361. GoodnessMFC cat = & experiment -> goodness [iresponse];
  362. if (x > cat -> left && x < cat -> right && y > cat -> bottom && y < cat -> top) {
  363. experiment -> goodnesses [experiment -> trial] = iresponse;
  364. Editor_broadcastDataChanged (me);
  365. Graphics_updateWs (my graphics.get());
  366. }
  367. }
  368. }
  369. } else if (experiment -> responses [experiment -> trial] != 0) {
  370. Melder_assert (experiment -> ok_right <= experiment -> ok_left);
  371. for (integer iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
  372. GoodnessMFC cat = & experiment -> goodness [iresponse];
  373. if (x > cat -> left && x < cat -> right && y > cat -> bottom && y < cat -> top) {
  374. experiment -> goodnesses [experiment -> trial] = iresponse;
  375. do_ok (me);
  376. }
  377. }
  378. }
  379. } else {
  380. if (x > experiment -> oops_left && x < experiment -> oops_right &&
  381. y > experiment -> oops_bottom && y < experiment -> oops_top)
  382. {
  383. do_oops (me);
  384. return;
  385. }
  386. if (my iexperiment < my experiments->size) {
  387. my iexperiment ++;
  388. if (! RunnerMFC_startExperiment (me)) {
  389. Melder_flushError ();
  390. forget (me);
  391. return;
  392. }
  393. }
  394. }
  395. }
  396. static void gui_drawingarea_cb_key (RunnerMFC me, GuiDrawingArea_KeyEvent event) {
  397. if (! my graphics) return; // could be the case in the very beginning
  398. ExperimentMFC experiment = (ExperimentMFC) my data;
  399. if (! my data) return;
  400. double reactionTime = Melder_clock () - experiment -> startingTime;
  401. if (! experiment -> blankWhilePlaying)
  402. reactionTime -= experiment -> stimulusInitialSilenceDuration;
  403. if (experiment -> trial == 0) {
  404. } else if (experiment -> pausing) {
  405. } else if (experiment -> trial <= experiment -> numberOfTrials) {
  406. if (experiment -> ok_key && experiment -> ok_key [0] == event -> key &&
  407. experiment -> responses [experiment -> trial] != 0 &&
  408. (experiment -> numberOfGoodnessCategories == 0 || experiment -> goodnesses [experiment -> trial] != 0))
  409. {
  410. do_ok (me);
  411. } else if (experiment -> replay_key && experiment -> replay_key [0] == event -> key &&
  412. my numberOfReplays < experiment -> maximumNumberOfReplays)
  413. {
  414. do_replay (me);
  415. } else if (experiment -> oops_key && experiment -> oops_key [0] == event -> key) {
  416. if (experiment -> trial > 1) {
  417. do_oops (me);
  418. }
  419. } else if (experiment -> responses [experiment -> trial] == 0 || experiment -> ok_right > experiment -> ok_left) {
  420. for (integer iresponse = 1; iresponse <= experiment -> numberOfDifferentResponses; iresponse ++) {
  421. ResponseMFC response = & experiment -> response [iresponse];
  422. if (response -> key && response -> key [0] == event -> key) {
  423. experiment -> responses [experiment -> trial] = iresponse;
  424. experiment -> reactionTimes [experiment -> trial] = reactionTime;
  425. if (experiment -> responsesAreSounds) {
  426. ExperimentMFC_playResponse (experiment, iresponse);
  427. }
  428. if (experiment -> ok_right <= experiment -> ok_left && experiment -> numberOfGoodnessCategories == 0) {
  429. do_ok (me);
  430. } else {
  431. Editor_broadcastDataChanged (me);
  432. Graphics_updateWs (my graphics.get());
  433. }
  434. }
  435. }
  436. if (experiment -> responses [experiment -> trial] != 0 && experiment -> ok_right > experiment -> ok_left) {
  437. for (integer iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
  438. GoodnessMFC cat = & experiment -> goodness [iresponse];
  439. if (cat -> key && cat -> key [0] == event -> key) {
  440. experiment -> goodnesses [experiment -> trial] = iresponse;
  441. Editor_broadcastDataChanged (me);
  442. Graphics_updateWs (my graphics.get());
  443. }
  444. }
  445. }
  446. } else if (experiment -> responses [experiment -> trial] != 0) {
  447. Melder_assert (experiment -> ok_right <= experiment -> ok_left);
  448. for (integer iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
  449. GoodnessMFC cat = & experiment -> goodness [iresponse];
  450. if (cat -> key && cat -> key [0] == event -> key) {
  451. experiment -> goodnesses [experiment -> trial] = iresponse;
  452. do_ok (me);
  453. }
  454. }
  455. }
  456. }
  457. }
  458. void structRunnerMFC :: v_createChildren () {
  459. our d_drawingArea = GuiDrawingArea_createShown (our windowForm, 0, 0, Machine_getMenuBarHeight (), 0,
  460. gui_drawingarea_cb_expose, gui_drawingarea_cb_click, gui_drawingarea_cb_key, gui_drawingarea_cb_resize, this, 0);
  461. }
  462. autoRunnerMFC RunnerMFC_create (conststring32 title, autoExperimentMFCList experiments) {
  463. try {
  464. autoRunnerMFC me = Thing_new (RunnerMFC);
  465. Editor_init (me.get(), 0, 0, 2000, 2000, title, nullptr);
  466. my experiments = experiments.move();
  467. my graphics = Graphics_create_xmdrawingarea (my d_drawingArea);
  468. structGuiDrawingArea_ResizeEvent event { my d_drawingArea, 0, 0 };
  469. event. width = GuiControl_getWidth (my d_drawingArea);
  470. event. height = GuiControl_getHeight (my d_drawingArea);
  471. gui_drawingarea_cb_resize (me.get(), & event);
  472. my iexperiment = 1;
  473. RunnerMFC_startExperiment (me.get());
  474. return me;
  475. } catch (MelderError) {
  476. Melder_throw (U"Experiment window not created.");
  477. }
  478. }
  479. /* End of file RunnerMFC.cpp */