1 /* Editor.cpp
2 *
3 * Copyright (C) 1992-2021 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse
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 <time.h>
20 #include "ScriptEditor.h"
21 #include "machine.h"
22 #include "EditorM.h"
23 #include "praat_script.h"
24 #include "sendsocket.h"
25
26 #include "enums_getText.h"
27 #include "Editor_enums.h"
28 #include "enums_getValue.h"
29 #include "Editor_enums.h"
30
31 Thing_implement (Editor, Thing, 0);
32
33 #include "prefs_define.h"
34 #include "Editor_prefs.h"
35 #include "prefs_install.h"
36 #include "Editor_prefs.h"
37 #include "prefs_copyToInstance.h"
38 #include "Editor_prefs.h"
39
40 /********** class EditorCommand **********/
41
42 Thing_implement (EditorCommand, Thing, 0);
43
44 /********** class EditorMenu **********/
45
46 Thing_implement (EditorMenu, Thing, 0);
47
48 /********** functions **********/
49
commonCallback(EditorCommand me,GuiMenuItemEvent)50 static void commonCallback (EditorCommand me, GuiMenuItemEvent /* event */) {
51 if (my d_editor && my d_editor -> v_scriptable () && ! str32str (my itemTitle.get(), U"...")) {
52 UiHistory_write (U"\n");
53 UiHistory_write_colonize (my itemTitle.get());
54 }
55 try {
56 my commandCallback (my d_editor, me, nullptr, 0, nullptr, nullptr, nullptr);
57 } catch (MelderError) {
58 if (! Melder_hasError (U"Script exited."))
59 Melder_appendError (U"Menu command \"", my itemTitle.get(), U"\" not completed.");
60 Melder_flushError ();
61 }
62 }
63
EditorMenu_addCommand(EditorMenu me,conststring32 itemTitle,uint32 flags,EditorCommandCallback commandCallback)64 GuiMenuItem EditorMenu_addCommand (EditorMenu me, conststring32 itemTitle /* cattable */, uint32 flags, EditorCommandCallback commandCallback)
65 {
66 autoEditorCommand thee = Thing_new (EditorCommand);
67 thy d_editor = my d_editor;
68 thy menu = me;
69 thy itemTitle = Melder_dup (itemTitle);
70 thy itemWidget =
71 ! commandCallback ? GuiMenu_addSeparator (my menuWidget) :
72 flags & Editor_HIDDEN ? nullptr :
73 GuiMenu_addItem (my menuWidget, itemTitle, flags, commonCallback, thee.get()); // DANGLE BUG: me can be killed by Collection_addItem(), but EditorCommand::destroy doesn't remove the item
74 thy commandCallback = commandCallback;
75 GuiMenuItem result = thy itemWidget;
76 my commands. addItem_move (thee.move());
77 return result;
78 }
79
80 /*GuiObject EditorCommand_getItemWidget (EditorCommand me) { return my itemWidget; }*/
81
Editor_addMenu(Editor me,conststring32 menuTitle,uint32 flags)82 EditorMenu Editor_addMenu (Editor me, conststring32 menuTitle, uint32 flags) {
83 autoEditorMenu thee = Thing_new (EditorMenu);
84 thy d_editor = me;
85 thy menuTitle = Melder_dup (menuTitle);
86 thy menuWidget = GuiMenu_createInWindow (my windowForm, menuTitle, flags);
87 return my menus. addItem_move (thee.move());
88 }
89
90 /*GuiObject EditorMenu_getMenuWidget (EditorMenu me) { return my menuWidget; }*/
91
Editor_addCommand(Editor me,conststring32 menuTitle,conststring32 itemTitle,uint32 flags,EditorCommandCallback commandCallback)92 GuiMenuItem Editor_addCommand (Editor me, conststring32 menuTitle, conststring32 itemTitle, uint32 flags, EditorCommandCallback commandCallback)
93 {
94 try {
95 integer numberOfMenus = my menus.size;
96 for (integer imenu = 1; imenu <= numberOfMenus; imenu ++) {
97 EditorMenu menu = my menus.at [imenu];
98 if (str32equ (menuTitle, menu -> menuTitle.get()))
99 return EditorMenu_addCommand (menu, itemTitle, flags, commandCallback);
100 }
101 Melder_throw (U"Menu \"", menuTitle, U"\" does not exist.");
102 } catch (MelderError) {
103 Melder_throw (U"Command \"", itemTitle, U"\" not inserted in menu \"", menuTitle, U".");
104 }
105 }
106
Editor_scriptCallback(Editor me,EditorCommand cmd,UiForm,integer,Stackel,conststring32,Interpreter)107 static void Editor_scriptCallback (Editor me, EditorCommand cmd, UiForm /* sendingForm */,
108 integer /* narg */, Stackel /* args */, conststring32 /* sendingString */, Interpreter /* interpreter */)
109 {
110 DO_RunTheScriptFromAnyAddedEditorCommand (me, cmd -> script.get());
111 }
112
Editor_addCommandScript(Editor me,conststring32 menuTitle,conststring32 itemTitle,uint32 flags,conststring32 script)113 GuiMenuItem Editor_addCommandScript (Editor me, conststring32 menuTitle, conststring32 itemTitle, uint32 flags,
114 conststring32 script)
115 {
116 integer numberOfMenus = my menus.size;
117 for (integer imenu = 1; imenu <= numberOfMenus; imenu ++) {
118 EditorMenu menu = my menus.at [imenu];
119 if (str32equ (menuTitle, menu -> menuTitle.get())) {
120 autoEditorCommand cmd = Thing_new (EditorCommand);
121 cmd -> d_editor = me;
122 cmd -> menu = menu;
123 cmd -> itemTitle = Melder_dup (itemTitle);
124 cmd -> itemWidget = script == nullptr ? GuiMenu_addSeparator (menu -> menuWidget) :
125 GuiMenu_addItem (menu -> menuWidget, itemTitle, flags, commonCallback, cmd.get()); // DANGLE BUG
126 cmd -> commandCallback = Editor_scriptCallback;
127 if (script [0] == U'\0') {
128 cmd -> script = Melder_dup (U"");
129 } else {
130 structMelderFile file { };
131 Melder_relativePathToFile (script, & file);
132 cmd -> script = Melder_dup (Melder_fileToPath (& file));
133 }
134 GuiMenuItem result = cmd -> itemWidget;
135 menu -> commands. addItem_move (cmd.move());
136 return result;
137 }
138 }
139 Melder_warning (
140 U"Menu \"", menuTitle, U"\" does not exist.\n"
141 U"Command \"", itemTitle, U"\" not inserted in menu \"", menuTitle, U".\n"
142 U"To fix this, go to Praat->Preferences->Buttons->Editors, and remove the script from this menu.\n"
143 U"You may want to install the script in a different menu."
144 );
145 return nullptr;
146 }
147
Editor_setMenuSensitive(Editor me,conststring32 menuTitle,bool sensitive)148 void Editor_setMenuSensitive (Editor me, conststring32 menuTitle, bool sensitive) {
149 integer numberOfMenus = my menus.size;
150 for (integer imenu = 1; imenu <= numberOfMenus; imenu ++) {
151 EditorMenu menu = my menus.at [imenu];
152 if (str32equ (menuTitle, menu -> menuTitle.get())) {
153 GuiThing_setSensitive (menu -> menuWidget, sensitive);
154 return;
155 }
156 }
157 }
158
Editor_getMenuCommand(Editor me,conststring32 menuTitle,conststring32 itemTitle)159 EditorCommand Editor_getMenuCommand (Editor me, conststring32 menuTitle, conststring32 itemTitle) {
160 integer numberOfMenus = my menus.size;
161 for (int imenu = 1; imenu <= numberOfMenus; imenu ++) {
162 EditorMenu menu = my menus.at [imenu];
163 if (str32equ (menuTitle, menu -> menuTitle.get())) {
164 integer numberOfCommands = menu -> commands.size, icommand;
165 for (icommand = 1; icommand <= numberOfCommands; icommand ++) {
166 EditorCommand command = menu -> commands.at [icommand];
167 if (str32equ (itemTitle, command -> itemTitle.get()))
168 return command;
169 }
170 }
171 }
172 Melder_throw (U"Command \"", itemTitle, U"\" not found in menu \"", menuTitle, U"\".");
173 }
174
Editor_doMenuCommand(Editor me,conststring32 commandTitle,integer narg,Stackel args,conststring32 arguments,Interpreter interpreter)175 void Editor_doMenuCommand (Editor me, conststring32 commandTitle, integer narg, Stackel args, conststring32 arguments, Interpreter interpreter) {
176 integer numberOfMenus = my menus.size;
177 for (int imenu = 1; imenu <= numberOfMenus; imenu ++) {
178 EditorMenu menu = my menus.at [imenu];
179 integer numberOfCommands = menu -> commands.size;
180 for (integer icommand = 1; icommand <= numberOfCommands; icommand ++) {
181 EditorCommand command = menu -> commands.at [icommand];
182 if (str32equ (commandTitle, command -> itemTitle.get())) {
183 command -> commandCallback (me, command, nullptr, narg, args, arguments, interpreter);
184 return;
185 }
186 }
187 }
188 Melder_throw (U"Command not available in ", my classInfo -> className, U".");
189 }
190
191 /********** class Editor **********/
192
v_destroy()193 void structEditor :: v_destroy () noexcept {
194 trace (U"enter");
195 MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
196 /*
197 The following command must be performed before the shell is destroyed.
198 Otherwise, we would be forgetting dangling command dialogs here.
199 */
200 our menus.removeAllItems();
201
202 Editor_broadcastDestruction (this);
203 if (our windowForm) {
204 #if gtk
205 if (our windowForm -> d_gtkWindow) {
206 Melder_assert (GTK_IS_WIDGET (our windowForm -> d_gtkWindow));
207 gtk_widget_destroy (GTK_WIDGET (our windowForm -> d_gtkWindow));
208 }
209 #elif motif
210 if (our windowForm -> d_xmShell) {
211 XtDestroyWidget (our windowForm -> d_xmShell);
212 }
213 #elif cocoa
214 if (our windowForm -> drawingArea) {
215 GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea *) our windowForm -> drawingArea -> d_widget;
216 if (cocoaDrawingArea)
217 [cocoaDrawingArea setUserData: nullptr];
218 }
219 if (our windowForm -> d_cocoaShell) {
220 NSWindow *cocoaWindow = our windowForm -> d_cocoaShell;
221 //our windowForm -> d_cocoaShell = nullptr;
222 [cocoaWindow close]; // this should *release* the window as well, because `releasedWhenClosed` is on by default for NSWindows
223 }
224 #endif
225 }
226 if (our ownData)
227 forget (our data);
228 Editor_Parent :: v_destroy ();
229 }
230
v_info()231 void structEditor :: v_info () {
232 MelderInfo_writeLine (U"Editor type: ", Thing_className (this));
233 MelderInfo_writeLine (U"Editor name: ", our name ? our name.get() : U"<no name>");
234 time_t today = time (nullptr);
235 MelderInfo_writeLine (U"Date: ", Melder_peek8to32 (ctime (& today))); // includes a newline
236 if (our data) {
237 MelderInfo_writeLine (U"Data type: ", our data -> classInfo -> className);
238 MelderInfo_writeLine (U"Data name: ", our data -> name.get());
239 }
240 }
241
v_nameChanged()242 void structEditor :: v_nameChanged () {
243 if (our name)
244 GuiShell_setTitle (our windowForm, our name.get());
245 }
246
v_saveData()247 void structEditor :: v_saveData () {
248 if (! our data)
249 return;
250 our previousData = Data_copy (our data);
251 }
252
v_restoreData()253 void structEditor :: v_restoreData () {
254 if (our data && our previousData)
255 Thing_swap (our data, our previousData.get());
256 }
257
menu_cb_sendBackToCallingProgram(Editor me,EDITOR_ARGS_DIRECT)258 static void menu_cb_sendBackToCallingProgram (Editor me, EDITOR_ARGS_DIRECT) {
259 if (my data) {
260 structMelderFile file { };
261 MelderDir_getFile (& Melder_preferencesFolder, U"praat_backToCaller.Data", & file);
262 Data_writeToTextFile (my data, & file);
263 sendsocket (Melder_peek32to8 (my callbackSocket.get()), Melder_peek32to8 (my data -> name.get()));
264 }
265 my v_goAway ();
266 }
267
menu_cb_close(Editor me,EDITOR_ARGS_DIRECT)268 static void menu_cb_close (Editor me, EDITOR_ARGS_DIRECT) {
269 my v_goAway ();
270 }
271
menu_cb_undo(Editor me,EDITOR_ARGS_DIRECT)272 static void menu_cb_undo (Editor me, EDITOR_ARGS_DIRECT) {
273 my v_restoreData ();
274 if (str32nequ (my undoText, U"Undo", 4)) my undoText [0] = U'R', my undoText [1] = U'e';
275 else if (str32nequ (my undoText, U"Redo", 4)) my undoText [0] = U'U', my undoText [1] = U'n';
276 else str32cpy (my undoText, U"Undo?");
277 #if gtk
278 gtk_label_set_label (GTK_LABEL (gtk_bin_get_child (GTK_BIN (my undoButton -> d_widget))), Melder_peek32to8 (my undoText));
279 #elif motif
280 conststring8 text_utf8 = Melder_peek32to8 (my undoText);
281 XtVaSetValues (my undoButton -> d_widget, XmNlabelString, text_utf8, nullptr);
282 #elif cocoa
283 [(GuiCocoaMenuItem *) my undoButton -> d_widget setTitle: (NSString *) Melder_peek32toCfstring (my undoText)];
284 #endif
285 /*
286 Send a message to myself (e.g., I will redraw myself).
287 */
288 my v_dataChanged ();
289 /*
290 Send a message to my boss (e.g., she will notify the others that depend on me).
291 */
292 Editor_broadcastDataChanged (me);
293 }
294
menu_cb_searchManual(Editor,EDITOR_ARGS_DIRECT)295 static void menu_cb_searchManual (Editor /* me */, EDITOR_ARGS_DIRECT) {
296 Melder_search ();
297 }
298
menu_cb_newScript(Editor me,EDITOR_ARGS_DIRECT)299 static void menu_cb_newScript (Editor me, EDITOR_ARGS_DIRECT) {
300 autoScriptEditor scriptEditor = ScriptEditor_createFromText (me, nullptr);
301 scriptEditor.releaseToUser();
302 }
303
menu_cb_openScript(Editor me,EDITOR_ARGS_DIRECT)304 static void menu_cb_openScript (Editor me, EDITOR_ARGS_DIRECT) {
305 autoScriptEditor scriptEditor = ScriptEditor_createFromText (me, nullptr);
306 TextEditor_showOpen (scriptEditor.get());
307 scriptEditor.releaseToUser();
308 }
309
v_createMenuItems_file(EditorMenu)310 void structEditor :: v_createMenuItems_file (EditorMenu /* menu */) {
311 }
312
v_createMenuItems_edit(EditorMenu menu)313 void structEditor :: v_createMenuItems_edit (EditorMenu menu) {
314 if (our data)
315 our undoButton = EditorMenu_addCommand (menu, U"Cannot undo", GuiMenu_INSENSITIVE + 'Z', menu_cb_undo);
316 }
317
INFO_EDITOR__settingsReport(Editor me,EDITOR_ARGS_DIRECT_WITH_OUTPUT)318 static void INFO_EDITOR__settingsReport (Editor me, EDITOR_ARGS_DIRECT_WITH_OUTPUT) {
319 INFO_EDITOR
320 Thing_info (me);
321 INFO_EDITOR_END
322 }
323
INFO_DATA__info(Editor me,EDITOR_ARGS_DIRECT_WITH_OUTPUT)324 static void INFO_DATA__info (Editor me, EDITOR_ARGS_DIRECT_WITH_OUTPUT) {
325 INFO_DATA
326 Thing_info (my data);
327 INFO_DATA_END
328 }
329
v_createMenuItems_query(EditorMenu menu)330 void structEditor :: v_createMenuItems_query (EditorMenu menu) {
331 v_createMenuItems_query_info (menu);
332 }
333
v_createMenuItems_query_info(EditorMenu menu)334 void structEditor :: v_createMenuItems_query_info (EditorMenu menu) {
335 EditorMenu_addCommand (menu, U"Editor info", 0, INFO_EDITOR__settingsReport);
336 EditorMenu_addCommand (menu, U"Settings report", Editor_HIDDEN, INFO_EDITOR__settingsReport);
337 if (our data)
338 EditorMenu_addCommand (menu, Melder_cat (Thing_className (data), U" info"), 0, INFO_DATA__info);
339 }
340
v_createMenus()341 void structEditor :: v_createMenus () {
342 EditorMenu menu = Editor_addMenu (this, U"File", 0);
343 v_createMenuItems_file (menu);
344 if (v_editable ()) {
345 menu = Editor_addMenu (this, U"Edit", 0);
346 v_createMenuItems_edit (menu);
347 }
348 if (v_hasQueryMenu ()) {
349 menu = Editor_addMenu (this, U"Query", 0);
350 v_createMenuItems_query (menu);
351 }
352 }
353
BOOLEAN_VARIABLE(v_form_pictureWindow_eraseFirst)354 BOOLEAN_VARIABLE (v_form_pictureWindow_eraseFirst)
355 void structEditor :: v_form_pictureWindow (EditorCommand cmd) {
356 LABEL (U"Picture window:")
357 BOOLEAN_FIELD (v_form_pictureWindow_eraseFirst, U"Erase first", true)
358 }
v_ok_pictureWindow(EditorCommand cmd)359 void structEditor :: v_ok_pictureWindow (EditorCommand cmd) {
360 SET_BOOLEAN (v_form_pictureWindow_eraseFirst, our pref_picture_eraseFirst ())
361 }
v_do_pictureWindow(EditorCommand)362 void structEditor :: v_do_pictureWindow (EditorCommand /* cmd */) {
363 our pref_picture_eraseFirst () = v_form_pictureWindow_eraseFirst;
364 }
365
OPTIONMENU_ENUM_VARIABLE(kEditor_writeNameAtTop,v_form_pictureMargins_writeNameAtTop)366 OPTIONMENU_ENUM_VARIABLE (kEditor_writeNameAtTop, v_form_pictureMargins_writeNameAtTop)
367 void structEditor :: v_form_pictureMargins (EditorCommand cmd) {
368 LABEL (U"Margins:")
369 OPTIONMENU_ENUM_FIELD (kEditor_writeNameAtTop, v_form_pictureMargins_writeNameAtTop,
370 U"Write name at top", kEditor_writeNameAtTop::DEFAULT)
371 }
v_ok_pictureMargins(EditorCommand cmd)372 void structEditor :: v_ok_pictureMargins (EditorCommand cmd) {
373 SET_ENUM (v_form_pictureMargins_writeNameAtTop, kEditor_writeNameAtTop, pref_picture_writeNameAtTop ())
374 }
v_do_pictureMargins(EditorCommand)375 void structEditor :: v_do_pictureMargins (EditorCommand /* cmd */) {
376 pref_picture_writeNameAtTop () = v_form_pictureMargins_writeNameAtTop;
377 }
378
gui_window_cb_goAway(Editor me)379 static void gui_window_cb_goAway (Editor me) {
380 Melder_assert (me);
381 Melder_assert (Thing_isa (me, classEditor));
382 my v_goAway ();
383 }
384
385 void praat_addCommandsToEditor (Editor me);
Editor_init(Editor me,int x,int y,int width,int height,conststring32 title,Daata data)386 void Editor_init (Editor me, int x, int y, int width, int height, conststring32 title, Daata data) {
387 double xmin, ymin, widthmax, heightmax;
388 Gui_getWindowPositioningBounds (& xmin, & ymin, & widthmax, & heightmax);
389 /*
390 Negative widths are relative to the whole screen.
391 */
392 if (width < 0)
393 width += (int) widthmax;
394 if (height < 0)
395 height += (int) heightmax;
396 /*
397 Don't start with a maximized window, because then the user doesn't know what a click on the maximize button means.
398 */
399 Melder_clipRight (& width, (int) widthmax - 100);
400 Melder_clipRight (& height, (int) heightmax - 100);
401 /*
402 Make sure that the window has at least a sane size,
403 just in case the user made the previous window very small (Praat's FunctionEditor saves the last size),
404 or the user edited the preferences file (which might save a window size).
405 */
406 Melder_clipLeft (200, & width);
407 Melder_clipLeft (150, & height);
408 /*
409 Now that the size is right, establish the position.
410 */
411 int left, right, top, bottom;
412 if (x > 0) {
413 /*
414 Positive x: relative to the left edge of the screen.
415 */
416 left = (int) xmin + x;
417 right = left + width;
418 } else if (x < 0) {
419 /*
420 Negative x: relative to the right edge of the screen.
421 */
422 right = (int) xmin + (int) widthmax + x;
423 left = right - width;
424 } else {
425 /*
426 Zero x: randomize between the left and right edge of the screen.
427 */
428 left = (int) NUMrandomInteger ((int) xmin + 4, (int) xmin + (int) widthmax - width - 4);
429 right = left + width;
430 }
431 if (y > 0) {
432 /*
433 Positive y: relative to the top of the screen.
434 */
435 top = (int) ymin + y;
436 bottom = top + height;
437 } else if (y < 0) {
438 /*
439 Negative y: relative to the bottom of the screen.
440 */
441 bottom = (int) ymin + (int) heightmax + y;
442 top = bottom - height;
443 } else {
444 /*
445 Zero y: randomize between the top and bottom of the screen.
446 */
447 top = (int) NUMrandomInteger ((int) ymin + 4, (int) ymin + (int) heightmax - height - 4);
448 //Melder_casual (ymin, U" ", heightmax, U" ", height, U" ", top);
449 bottom = top + height;
450 }
451 #if defined (macintoshXXX) || gtk
452 top += Machine_getTitleBarHeight ();
453 bottom += Machine_getTitleBarHeight ();
454 #endif
455 my windowForm = GuiWindow_create (left, top, width, height, 450, 350, title, gui_window_cb_goAway, me, my v_canFullScreen () ? GuiWindow_FULLSCREEN : 0);
456 Thing_setName (me, title);
457 my data = data;
458 my v_copyPreferencesToInstance ();
459
460 /*
461 Create menus.
462 */
463
464 if (my v_hasMenuBar ())
465 GuiWindow_addMenuBar (my windowForm);
466
467 my v_createChildren ();
468
469 if (my v_hasMenuBar ()) {
470 my v_createMenus ();
471 EditorMenu helpMenu = Editor_addMenu (me, U"Help", 0);
472 my v_createHelpMenuItems (helpMenu);
473 EditorMenu_addCommand (helpMenu, U"-- search --", 0, nullptr);
474 my searchButton = EditorMenu_addCommand (helpMenu, U"Search manual...", 'M', menu_cb_searchManual);
475 if (my v_scriptable ()) {
476 Editor_addCommand (me, U"File", U"New editor script", 0, menu_cb_newScript);
477 Editor_addCommand (me, U"File", U"Open editor script...", 0, menu_cb_openScript);
478 Editor_addCommand (me, U"File", U"-- after script --", 0, 0);
479 }
480 /*
481 Add the scripted commands.
482 */
483 praat_addCommandsToEditor (me);
484 if (my callbackSocket)
485 Editor_addCommand (me, U"File", U"Send back to calling program", 0, menu_cb_sendBackToCallingProgram);
486 Editor_addCommand (me, U"File", U"Close", 'W', menu_cb_close);
487 }
488 GuiThing_show (my windowForm);
489 }
490
Editor_save(Editor me,conststring32 text)491 void Editor_save (Editor me, conststring32 text) {
492 my v_saveData ();
493 if (! my undoButton)
494 return;
495 GuiThing_setSensitive (my undoButton, true);
496 Melder_sprint (my undoText,100, U"Undo ", text);
497 #if gtk
498 gtk_label_set_label (GTK_LABEL (gtk_bin_get_child (GTK_BIN (my undoButton -> d_widget))), Melder_peek32to8 (my undoText));
499 #elif motif
500 conststring8 text_utf8 = Melder_peek32to8 (my undoText);
501 XtVaSetValues (my undoButton -> d_widget, XmNlabelString, text_utf8, nullptr);
502 #elif cocoa
503 [(GuiCocoaMenuItem *) my undoButton -> d_widget setTitle: (NSString *) Melder_peek32toCfstring (my undoText)];
504 #endif
505 }
506
Editor_openPraatPicture(Editor me)507 void Editor_openPraatPicture (Editor me) {
508 my pictureGraphics = praat_picture_editor_open (my pref_picture_eraseFirst ());
509 }
Editor_closePraatPicture(Editor me)510 void Editor_closePraatPicture (Editor me) {
511 if (my data && my pref_picture_writeNameAtTop () != kEditor_writeNameAtTop::NO_) {
512 Graphics_setNumberSignIsBold (my pictureGraphics, false);
513 Graphics_setPercentSignIsItalic (my pictureGraphics, false);
514 Graphics_setCircumflexIsSuperscript (my pictureGraphics, false);
515 Graphics_setUnderscoreIsSubscript (my pictureGraphics, false);
516 Graphics_textTop (my pictureGraphics,
517 my pref_picture_writeNameAtTop () == kEditor_writeNameAtTop::FAR_,
518 my data -> name.get()
519 );
520 Graphics_setNumberSignIsBold (my pictureGraphics, true);
521 Graphics_setPercentSignIsItalic (my pictureGraphics, true);
522 Graphics_setCircumflexIsSuperscript (my pictureGraphics, true);
523 Graphics_setUnderscoreIsSubscript (my pictureGraphics, true);
524 }
525 praat_picture_editor_close ();
526 }
527
528 /* End of file Editor.cpp */
529