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