1 /* DemoEditor.cpp
2 *
3 * Copyright (C) 2009-2021 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 #include "DemoEditor.h"
20 #include "machine.h"
21 #include "praatP.h"
22 #include "../kar/UnicodeData.h"
23
24 Thing_implement (DemoEditor, Editor, 0);
25
26 static DemoEditor theReferenceToTheOnlyDemoEditor;
27
28 /***** DemoEditor methods *****/
29
v_destroy()30 void structDemoEditor :: v_destroy () noexcept {
31 Melder_free (praatPicture);
32 theReferenceToTheOnlyDemoEditor = nullptr;
33 DemoEditor_Parent :: v_destroy ();
34 }
35
v_info()36 void structDemoEditor :: v_info () {
37 DemoEditor_Parent :: v_info ();
38 MelderInfo_writeLine (U"Colour: ", MelderColour_name (((PraatPicture) praatPicture) -> colour));
39 MelderInfo_writeLine (U"Font: ", kGraphics_font_getText (((PraatPicture) praatPicture) -> font));
40 MelderInfo_writeLine (U"Font size: ", ((PraatPicture) praatPicture) -> fontSize);
41 }
42
v_goAway()43 void structDemoEditor :: v_goAway () {
44 if (waitingForInput)
45 userWantsToClose = true;
46 else
47 DemoEditor_Parent :: v_goAway ();
48 }
49
v_createMenus()50 void structDemoEditor :: v_createMenus () {
51 DemoEditor_Parent :: v_createMenus ();
52 }
53
gui_drawingarea_cb_expose(DemoEditor me,GuiDrawingArea_ExposeEvent)54 static void gui_drawingarea_cb_expose (DemoEditor me, GuiDrawingArea_ExposeEvent /* event */) {
55 if (! my graphics)
56 return; // could be the case in the very beginning
57 static integer count=0;
58 //Melder_casual(U"gui_drawingarea_cb_expose ", ++count);
59 //Graphics_clearWs (my foregroundGraphics.get());
60 Graphics_play (my graphics.get(), my graphics.get());
61 }
62
gui_drawingarea_cb_mouse(DemoEditor me,GuiDrawingArea_MouseEvent event)63 static void gui_drawingarea_cb_mouse (DemoEditor me, GuiDrawingArea_MouseEvent event) {
64 if (! my graphics)
65 return; // could be the case in the very beginning
66 if (! event -> isClick())
67 return;
68 my clicked = true;
69 my keyPressed = false;
70 my x = event -> x;
71 my y = event -> y;
72 my key = UNICODE_BULLET;
73 my shiftKeyPressed = event -> shiftKeyPressed;
74 my commandKeyPressed = event -> commandKeyPressed;
75 my optionKeyPressed = event -> optionKeyPressed;
76 }
77
gui_drawingarea_cb_key(DemoEditor me,GuiDrawingArea_KeyEvent event)78 static void gui_drawingarea_cb_key (DemoEditor me, GuiDrawingArea_KeyEvent event) {
79 if (! my graphics)
80 return; // could be the case in the very beginning
81 my clicked = false;
82 my keyPressed = true;
83 my x = 0;
84 my y = 0;
85 my key = event -> key;
86 trace (my key);
87 my shiftKeyPressed = event -> shiftKeyPressed;
88 my commandKeyPressed = event -> commandKeyPressed;
89 my optionKeyPressed = event -> optionKeyPressed;
90 }
91
gui_drawingarea_cb_resize(DemoEditor me,GuiDrawingArea_ResizeEvent event)92 static void gui_drawingarea_cb_resize (DemoEditor me, GuiDrawingArea_ResizeEvent event) {
93 if (! my graphics)
94 return; // could be the case in the very beginning
95 trace (event -> width, U" ", event -> height);
96 Graphics_setWsViewport (my graphics.get(), 0.0, event -> width, 0.0, event -> height);
97 Graphics_setWsWindow (my graphics.get(), 0.0, 100.0, 0.0, 100.0);
98 //Graphics_setViewport (my graphics.get(), 0.0, 100.0, 0.0, 100.0);
99 Graphics_updateWs (my graphics.get());
100 }
101
v_createChildren()102 void structDemoEditor :: v_createChildren () {
103 our drawingArea = GuiDrawingArea_createShown (our windowForm, 0, 0, 0, 0,
104 gui_drawingarea_cb_expose, gui_drawingarea_cb_mouse,
105 gui_drawingarea_cb_key, gui_drawingarea_cb_resize, this, 0
106 );
107 }
108
DemoEditor_init(DemoEditor me)109 void DemoEditor_init (DemoEditor me) {
110 Editor_init (me, 0, 0, 1344, 756, U"", nullptr); // 70 percent of the standard 1920x1080 screen
111
112 my graphics = Graphics_create_xmdrawingarea (my drawingArea);
113 Graphics_setWsWindow (my graphics.get(), 0.0, 100.0, 0.0, 100.0);
114 Graphics_setWsViewport (my graphics.get(),
115 0.0, GuiControl_getWidth (my drawingArea),
116 0.0, GuiControl_getHeight (my drawingArea)
117 );
118 Graphics_startRecording (my graphics.get());
119 Graphics_setViewport (my graphics.get(), 0.0, 100.0, 0.0, 100.0);
120 Graphics_setColour (my graphics.get(), Melder_WHITE);
121 Graphics_setWindow (my graphics.get(), 0.0, 1.0, 0.0, 1.0);
122 Graphics_fillRectangle (my graphics.get(), 0.0, 1.0, 0.0, 1.0);
123 Graphics_setColour (my graphics.get(), Melder_BLACK);
124 Graphics_updateWs (my graphics.get());
125 }
126
DemoEditor_create()127 autoDemoEditor DemoEditor_create () {
128 try {
129 autoDemoEditor me = Thing_new (DemoEditor);
130 DemoEditor_init (me.get());
131 return me;
132 } catch (MelderError) {
133 Melder_throw (U"Demo window not created.");
134 }
135 }
136
Demo_open()137 void Demo_open () {
138 if (Melder_batch) {
139 /*
140 Batch scripts have to be able to run demos.
141 */
142 //Melder_batch = false;
143 }
144 if (! theReferenceToTheOnlyDemoEditor) {
145 autoDemoEditor editor = DemoEditor_create ();
146 Melder_assert (editor);
147 //GuiObject_show (editor -> windowForm);
148 editor -> praatPicture = Melder_calloc_f (structPraatPicture, 1);
149 theCurrentPraatPicture = (PraatPicture) editor -> praatPicture;
150 theCurrentPraatPicture -> graphics = editor -> graphics.get();
151 theCurrentPraatPicture -> font = kGraphics_font::HELVETICA;
152 theCurrentPraatPicture -> fontSize = 10;
153 theCurrentPraatPicture -> lineType = Graphics_DRAWN;
154 theCurrentPraatPicture -> colour = Melder_BLACK;
155 theCurrentPraatPicture -> lineWidth = 1.0;
156 theCurrentPraatPicture -> arrowSize = 1.0;
157 theCurrentPraatPicture -> speckleSize = 1.0;
158 theCurrentPraatPicture -> x1NDC = 0.0;
159 theCurrentPraatPicture -> x2NDC = 100.0;
160 theCurrentPraatPicture -> y1NDC = 0.0;
161 theCurrentPraatPicture -> y2NDC = 100.0;
162 theReferenceToTheOnlyDemoEditor = editor.get();
163 editor.releaseToUser();
164 }
165 if (theReferenceToTheOnlyDemoEditor -> waitingForInput)
166 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
167 U"Please click or type into the Demo window or close it.");
168 theCurrentPraatPicture = (PraatPicture) theReferenceToTheOnlyDemoEditor -> praatPicture;
169 }
170
Demo_close()171 void Demo_close () {
172 theCurrentPraatPicture = & theForegroundPraatPicture;
173 Graphics_updateWs (theReferenceToTheOnlyDemoEditor -> graphics.get());
174 }
175
Demo_windowTitle(conststring32 title)176 int Demo_windowTitle (conststring32 title) {
177 autoDemoOpen demo;
178 Thing_setName (theReferenceToTheOnlyDemoEditor, title);
179 return 1;
180 }
181
Demo_show()182 int Demo_show () {
183 if (! theReferenceToTheOnlyDemoEditor)
184 return 0;
185 autoDemoOpen demo;
186 GuiThing_show (theReferenceToTheOnlyDemoEditor -> windowForm);
187 Graphics_updateWs (theReferenceToTheOnlyDemoEditor -> graphics.get());
188 GuiShell_drain (theReferenceToTheOnlyDemoEditor -> windowForm);
189 return 1;
190 }
191
192 #if cocoa
193 @interface DemoWindowTimer: NSObject
194 - (void) timerCallback: (NSTimer *) timer;
195 @end
196 @implementation DemoWindowTimer
197 - (void) timerCallback: (NSTimer *) timer {
198 (void) timer;
199 printf ("eureka\n");
200 }
201 @end
202 DemoWindowTimer *theDemoWindowTimer;
203 #endif
204
Demo_timer(double duration)205 void Demo_timer (double duration) {
206 #if cocoa
207 if (! theDemoWindowTimer)
208 theDemoWindowTimer = [[DemoWindowTimer alloc] init];
209 [NSTimer scheduledTimerWithTimeInterval: duration
210 target: theDemoWindowTimer
211 selector: @selector (timerCallback)
212 userInfo: nil
213 repeats: false];
214 #endif
215 }
216
Demo_waitForInput(Interpreter interpreter)217 void Demo_waitForInput (Interpreter interpreter) {
218 if (! theReferenceToTheOnlyDemoEditor)
219 return;
220 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
221 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
222 U"Please click or type into the Demo window or close it.");
223 }
224 //GuiObject_show (theReferenceToTheOnlyDemoEditor -> windowForm);
225 theReferenceToTheOnlyDemoEditor -> clicked = false;
226 theReferenceToTheOnlyDemoEditor -> keyPressed = false;
227 theReferenceToTheOnlyDemoEditor -> waitingForInput = true;
228 {// scope
229 autoMelderSaveDefaultDir saveDir;
230 bool wasBackgrounding = Melder_backgrounding;
231 if (wasBackgrounding)
232 praat_foreground ();
233 try {
234 #if gtk
235 do {
236 gtk_main_iteration ();
237 } while (! theReferenceToTheOnlyDemoEditor -> clicked &&
238 ! theReferenceToTheOnlyDemoEditor -> keyPressed &&
239 ! theReferenceToTheOnlyDemoEditor -> userWantsToClose);
240 #elif cocoa
241 do {
242 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
243 [theReferenceToTheOnlyDemoEditor -> windowForm -> d_cocoaShell flushWindow];
244 Graphics_updateWs (theReferenceToTheOnlyDemoEditor -> graphics.get()); // make sure that even texts will be drawn
245 NSEvent *nsEvent = [NSApp
246 nextEventMatchingMask: NSAnyEventMask
247 untilDate: [NSDate distantFuture] // wait
248 inMode: NSDefaultRunLoopMode
249 dequeue: YES
250 ];
251 Melder_assert (nsEvent);
252 [NSApp sendEvent: nsEvent];
253 [NSApp updateWindows]; // called automatically?
254 [pool release];
255 } while (! theReferenceToTheOnlyDemoEditor -> clicked &&
256 ! theReferenceToTheOnlyDemoEditor -> keyPressed &&
257 ! theReferenceToTheOnlyDemoEditor -> userWantsToClose);
258 #elif defined (_WIN32)
259 do {
260 XEvent event;
261 GuiNextEvent (& event);
262 XtDispatchEvent (& event);
263 } while (! theReferenceToTheOnlyDemoEditor -> clicked &&
264 ! theReferenceToTheOnlyDemoEditor -> keyPressed &&
265 ! theReferenceToTheOnlyDemoEditor -> userWantsToClose);
266 #endif
267 } catch (MelderError) {
268 Melder_flushError (U"An error made it to the outer level in the Demo window; should not occur! Please write to paul.boersma@uva.nl");
269 }
270 if (wasBackgrounding)
271 praat_background ();
272 }
273 theReferenceToTheOnlyDemoEditor -> waitingForInput = false;
274 if (theReferenceToTheOnlyDemoEditor -> userWantsToClose) {
275 Interpreter_stop (interpreter);
276 forget (theReferenceToTheOnlyDemoEditor);
277 Melder_throw (U"You interrupted the script.");
278 }
279 }
280
Demo_peekInput(Interpreter interpreter)281 void Demo_peekInput (Interpreter interpreter) {
282 if (! theReferenceToTheOnlyDemoEditor) return;
283 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
284 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
285 U"Please click or type into the Demo window or close it.");
286 }
287 //GuiObject_show (theReferenceToTheOnlyDemoEditor -> windowForm);
288 theReferenceToTheOnlyDemoEditor -> clicked = false;
289 theReferenceToTheOnlyDemoEditor -> keyPressed = false;
290 theReferenceToTheOnlyDemoEditor -> x = 0;
291 theReferenceToTheOnlyDemoEditor -> y = 0;
292 theReferenceToTheOnlyDemoEditor -> key = U'\0';
293 theReferenceToTheOnlyDemoEditor -> shiftKeyPressed = false;
294 theReferenceToTheOnlyDemoEditor -> commandKeyPressed = false;
295 theReferenceToTheOnlyDemoEditor -> optionKeyPressed = false;
296 theReferenceToTheOnlyDemoEditor -> waitingForInput = true;
297 {// scope
298 autoMelderSaveDefaultDir saveDir;
299 //bool wasBackgrounding = Melder_backgrounding;
300 //if (wasBackgrounding) praat_foreground ();
301 try {
302 #if gtk
303 while (gtk_events_pending ()) {
304 gtk_main_iteration ();
305 }
306 #elif cocoa
307 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
308 [theReferenceToTheOnlyDemoEditor -> windowForm -> d_cocoaShell flushWindow];
309 Graphics_updateWs (theReferenceToTheOnlyDemoEditor -> graphics.get()); // make sure that even texts will be drawn
310 while (NSEvent *nsEvent = [NSApp
311 nextEventMatchingMask: NSAnyEventMask
312 untilDate: [NSDate distantPast] // don't wait
313 inMode: NSDefaultRunLoopMode
314 dequeue: YES])
315 {
316 [NSApp sendEvent: nsEvent];
317 }
318 [NSApp updateWindows]; // called automatically?
319 [pool release];
320 #elif defined (_WIN32)
321 XEvent event;
322 while (PeekMessage (& event, 0, 0, 0, PM_REMOVE)) {
323 XtDispatchEvent (& event);
324 }
325 #endif
326 } catch (MelderError) {
327 Melder_flushError (U"An error made it to the outer level in the Demo window; should not occur! Please write to paul.boersma@uva.nl");
328 }
329 //if (wasBackgrounding) praat_background ();
330 }
331 theReferenceToTheOnlyDemoEditor -> waitingForInput = false;
332 if (theReferenceToTheOnlyDemoEditor -> userWantsToClose) {
333 Interpreter_stop (interpreter);
334 forget (theReferenceToTheOnlyDemoEditor);
335 Melder_throw (U"You interrupted the script.");
336 }
337 }
338
Demo_clicked()339 bool Demo_clicked () {
340 if (! theReferenceToTheOnlyDemoEditor)
341 return false;
342 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
343 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
344 U"Please click or type into the Demo window or close it.");
345 }
346 return theReferenceToTheOnlyDemoEditor -> clicked;
347 }
348
Demo_x()349 double Demo_x () {
350 if (! theReferenceToTheOnlyDemoEditor)
351 return undefined;
352 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
353 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
354 U"Please click or type into the Demo window or close it.");
355 }
356 trace (U"NDC before: ", theReferenceToTheOnlyDemoEditor -> graphics -> d_x1NDC, U" ", theReferenceToTheOnlyDemoEditor -> graphics -> d_x2NDC);
357 Graphics_setInner (theReferenceToTheOnlyDemoEditor -> graphics.get());
358 trace (U"NDC after: ", theReferenceToTheOnlyDemoEditor -> graphics -> d_x1NDC, U" ", theReferenceToTheOnlyDemoEditor -> graphics -> d_x2NDC);
359 double xWC, yWC;
360 trace (U"DC: x ", theReferenceToTheOnlyDemoEditor -> x, U", y ", theReferenceToTheOnlyDemoEditor -> y);
361 Graphics_DCtoWC (theReferenceToTheOnlyDemoEditor -> graphics.get(), theReferenceToTheOnlyDemoEditor -> x, theReferenceToTheOnlyDemoEditor -> y, & xWC, & yWC);
362 trace (U"WC: x ", xWC, U", y ", yWC);
363 Graphics_unsetInner (theReferenceToTheOnlyDemoEditor -> graphics.get());
364 return xWC;
365 }
366
Demo_y()367 double Demo_y () {
368 if (! theReferenceToTheOnlyDemoEditor)
369 return undefined;
370 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
371 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
372 U"Please click or type into the Demo window or close it.");
373 }
374 Graphics_setInner (theReferenceToTheOnlyDemoEditor -> graphics.get());
375 double xWC, yWC;
376 Graphics_DCtoWC (theReferenceToTheOnlyDemoEditor -> graphics.get(), theReferenceToTheOnlyDemoEditor -> x, theReferenceToTheOnlyDemoEditor -> y, & xWC, & yWC);
377 Graphics_unsetInner (theReferenceToTheOnlyDemoEditor -> graphics.get());
378 return yWC;
379 }
380
Demo_keyPressed()381 bool Demo_keyPressed () {
382 if (! theReferenceToTheOnlyDemoEditor)
383 return false;
384 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
385 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
386 U"Please click or type into the Demo window or close it.");
387 }
388 return theReferenceToTheOnlyDemoEditor -> keyPressed;
389 }
390
Demo_key()391 char32 Demo_key () {
392 if (! theReferenceToTheOnlyDemoEditor)
393 return U'\0';
394 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
395 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
396 U"Please click or type into the Demo window or close it.");
397 }
398 return theReferenceToTheOnlyDemoEditor -> key;
399 }
400
Demo_shiftKeyPressed()401 bool Demo_shiftKeyPressed () {
402 if (! theReferenceToTheOnlyDemoEditor)
403 return false;
404 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
405 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
406 U"Please click or type into the Demo window or close it.");
407 }
408 return theReferenceToTheOnlyDemoEditor -> shiftKeyPressed;
409 }
410
Demo_commandKeyPressed()411 bool Demo_commandKeyPressed () {
412 if (! theReferenceToTheOnlyDemoEditor)
413 return false;
414 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
415 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
416 U"Please click or type into the Demo window or close it.");
417 }
418 return theReferenceToTheOnlyDemoEditor -> commandKeyPressed;
419 }
420
Demo_optionKeyPressed()421 bool Demo_optionKeyPressed () {
422 if (! theReferenceToTheOnlyDemoEditor)
423 return false;
424 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
425 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
426 U"Please click or type into the Demo window or close it.");
427 }
428 return theReferenceToTheOnlyDemoEditor -> optionKeyPressed;
429 }
430
Demo_input(conststring32 keys)431 bool Demo_input (conststring32 keys) {
432 if (! theReferenceToTheOnlyDemoEditor)
433 return false;
434 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
435 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
436 U"Please click or type into the Demo window or close it.");
437 }
438 return str32chr (keys, theReferenceToTheOnlyDemoEditor -> key) != nullptr;
439 }
440
Demo_clickedIn(double left,double right,double bottom,double top)441 bool Demo_clickedIn (double left, double right, double bottom, double top) {
442 if (! theReferenceToTheOnlyDemoEditor || ! theReferenceToTheOnlyDemoEditor -> clicked)
443 return false;
444 if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
445 Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
446 U"Please click or type into the Demo window or close it.");
447 }
448 if (! theReferenceToTheOnlyDemoEditor -> clicked)
449 return false;
450 double xWC = Demo_x (), yWC = Demo_y ();
451 return xWC >= left && xWC < right && yWC >= bottom && yWC < top;
452 }
453
454 /* End of file DemoEditor.cpp */
455