1 // ----------------------------------------------------------------------------
2 // macroedit.cxx
3 //
4 // Copyright (C) 2007-2009
5 //		Dave Freese, W1HKJ
6 // Copyright (C) 2009
7 //		Stelios Bounanos, M0GLD
8 //
9 // This file is part of fldigi.
10 //
11 // Fldigi is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // Fldigi is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
23 // ----------------------------------------------------------------------------
24 
25 #include <config.h>
26 
27 #include <string>
28 #ifndef __MINGW32__
29 #  include <glob.h>
30 #endif
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <cstring>
35 #include <cassert>
36 
37 #include "macros.h"
38 #include "macroedit.h"
39 #include "globals.h"
40 #include "status.h"
41 #include "fileselect.h"
42 #include "fl_digi.h"
43 #include "main.h"
44 #include "gettext.h"
45 #include "pixmaps.h"
46 #include "configuration.h"
47 
48 using namespace std;
49 
50 Fl_Double_Window *MacroEditDialog = (Fl_Double_Window *)0;
51 
52 Fl_Button	*btnMacroEditApply = (Fl_Button *)0;
53 Fl_Button	*btnMacroEditClose = (Fl_Button *)0;
54 Fl_Button	*btnInsertMacro = (Fl_Button *)0;
55 Fl_Input2	*macrotext = (Fl_Input2 *)0;
56 Fl_Input2	*labeltext = (Fl_Input2 *)0;
57 static int widths[] = {150, 0};
58 
59 Fl_Hold_Browser *macroDefs=(Fl_Hold_Browser *)0;
60 
61 static int iMacro, iType;
62 static Fl_Input* iInput;
63 
64 // fl_color(0) is always the foreground colour
65 #define LINE_SEP "@B0"
66 
loadBrowser(Fl_Widget * widget)67 void loadBrowser(Fl_Widget *widget) {
68 	Fl_Browser *w = (Fl_Browser *)widget;
69 	/* Do not translate the tags lefthand-side */
70 	w->add(_("<FREQ>\tmy frequency"));
71 	w->add(_("<MODE>\tmode"));
72 	w->add(_("<MYCALL>\tmy call"));
73 	w->add(_("<MYLOC>\tmy locator"));
74 	w->add(_("<MYNAME>\tmy name"));
75 	w->add(_("<MYQTH>\tmy QTH"));
76 	w->add(_("<MYRST>\tmy RST"));
77 	w->add(_("<MYCLASS>\tmy FD class"));
78 	w->add(_("<MYSECTION>\tmy FD section"));
79 	w->add(_("<MYSTATE>\tmy state"));
80 	w->add(_("<MYST>\tmy ST"));
81 	w->add(_("<MYCOUNTY>\tmy county"));
82 	w->add(_("<MYCNTY>\tmy CNTY"));
83 	w->add(_("<ANTENNA>\tmy antenna"));
84 	w->add(_("<BAND>\toperating band"));
85 	w->add(_("<VER>\tFldigi version"));
86 	w->add(_("<DIGI>\tdigital mode (adif)"));
87 
88 	w->add(LINE_SEP);
89 	w->add(_("<CALL>\tother call"));
90 	w->add(_("<NAME>\tother name"));
91 	w->add(_("<QTH>\tother QTH"));
92 	w->add(_("<ST>\tother State"));
93 	w->add(_("<PR>\tother Province"));
94 	w->add(_("<LOC>\tother locator"));
95 	w->add(_("<RST>\tother RST"));
96 
97 	w->add(LINE_SEP);
98 	w->add(_("<INFO1>\tS/N etc."));
99 	w->add(_("<INFO2>\tIMD etc."));
100 
101 	w->add(LINE_SEP);
102 	w->add(_("<QSONBR>\t# QSO recs"));
103 	w->add(_("<NXTNBR>\tnext QSO rec #"));
104 
105 	w->add(LINE_SEP);
106 	w->add(_("<MAPIT>\tmap on google"));
107 	w->add(_("<MAPIT:adr/lat/loc>\tmap by value"));
108 
109 	w->add(LINE_SEP);
110 	w->add(_("<CLRRX>\tclear RX pane"));
111 	w->add(_("<CLRTX>\tclear TX pane"));
112 	w->add(_("<CLRQSO>\tclear QSO fields"));
113 
114 	w->add(LINE_SEP);
115 	w->add(_("<GET>\ttext to NAME/QTH"));
116 
117 #ifdef __WIN32__
118 	w->add(LINE_SEP);
119 	w->add(_("<TALK:on|off|t>\tDigitalk On, Off, Toggle"));
120 #endif
121 
122 	w->add(LINE_SEP);
123 	w->add(_("<CLRLOG>\tclear log fields"));
124 	w->add(_("<LOG>\tsave QSO data"));
125 	w->add(_("<LOG:msg>\tsaveQSO data, append msg to notes"));
126 	w->add(_("<LNW>\tlog at xmt time"));
127 	w->add(_("<LNW:msg>\tsaveQSO data, append msg to notes"));
128 	w->add(_("<EQSL>\tlog eQSL"));
129 	w->add(_("<EQSL:[msg]>\tlog eQSL optional msg"));
130 
131 	w->add(LINE_SEP);
132 	w->add(_("<QSOTIME>\tQSO time (HHMM))"));
133 	w->add(_("<ILDT[:fmt]>\tLDT default '%Y-%m-%d %H:%M%z'"));
134 	w->add(_("<LDT[[fmt]>\tLocal datetime, default '%x %H:%M %Z'"));
135 	w->add(_("<IZDT[:fmt]>\tZDT default '%Y-%m-%d %H:%MZ'"));
136 	w->add(_("<ZDT[:fmt]>\tUTC datetime, default '%x %H:%MZ'"));
137 	w->add(_("<LT[:fmt]>\tlocal time, default %H%M"));
138 	w->add(_("<ZT[:fmt]>\tzulu time default %H%MZ"));
139 	w->add(_("<LD[:fmt]>\tlocal date, default '%Y-%M-%D'"));
140 	w->add(_("<ZD[:fmt]>\tzulu date, default '%Y-%M-%D Z'"));
141 	w->add(_("<WX>\tget weather data"));
142 	w->add(_("<WX:xxxx>\tget weather data for station"));
143 
144 	w->add(LINE_SEP);
145 	w->add(_("<CNTR>\tcontest counter"));
146 	w->add(_("<DECR>\tdecrement counter"));
147 	w->add(_("<INCR>\tincrement counter"));
148 	w->add(_("<XIN>\texchange in"));
149 	w->add(_("<XOUT>\texchange out"));
150 	w->add(_("<XBEG>\texchange begin"));
151 	w->add(_("<XEND>\texchange end"));
152 	w->add(_("<SAVEXCHG>\tsave contest out"));
153 	w->add(_("<SERNO>\tcurrent contest serno"));
154 	w->add(_("<LASTNO>\tlast serno sent"));
155 	w->add(_("<FDCLASS>\tFD class"));
156 	w->add(_("<FDSECT>\tFD section"));
157 	w->add(_("<CLASS>\tcontest class"));
158 	w->add(_("<SECTION>\tARRL section"));
159 
160 	w->add(LINE_SEP);
161 	w->add(_("<RX>\treceive"));
162 	w->add(_("<TX>\ttransmit"));
163 	w->add(_("<TX/RX>\ttoggle T/R"));
164 	w->add(_("<SRCHUP>\tsearch UP for signal"));
165 	w->add(_("<SRCHDN>\tsearch DOWN for signal"));
166 	w->add(_("<GOHOME>\treturn to sweet spot"));
167 	w->add(_("<GOFREQ:NNNN>\tmove to freq NNNN Hz"));
168 	w->add(_("<QSYTO>\tleft-clk QSY button"));
169 	w->add(_("<QSYFM>\tright-clk QSY button"));
170 	w->add(_("<QSY:FFF.F[:NNNN]>\tqsy to kHz, Hz"));
171 	w->add(_("<QSY+:+/-n.nnn>\tincr/decr xcvr freq"));
172 	w->add(_("<RIGMODE:mode>\tvalid xcvr mode"));
173 	w->add(_("<FILWID:width>\tvalid xcvr filter width"));
174 	w->add(_("<RIGLO:lowcut>\tvalid xcvr low cutoff filter"));
175 	w->add(_("<RIGHI:hicut>\tvalid xcvr hi cutoff filter"));
176 	w->add(_("<FOCUS>\trig freq has kbd focus"));
177 
178 	w->add(LINE_SEP);
179 	w->add(_("<QRG:text>\tinsert QRG into Rx text"));
180 
181 	w->add(LINE_SEP);
182 	w->add(_("<FILE:>\tinsert text file"));
183 	w->add(_("<IMAGE:>\tinsert image file"));
184 	w->add(_("<AVATAR>\tsend avatar"));
185 	w->add(LINE_SEP);
186 
187 	w->add(_("<PAUSE>\tpause transmit"));
188 	w->add(_("<IDLE:NN.nn>\tidle signal for NN.nn sec"));
189 	w->add(_("<TIMER:NN>\trepeat every NN sec"));
190 	w->add(_("<AFTER:NN>\trepeat after waiting NN sec"));
191 	w->add(_("<TUNE:NN>\ttune signal for NN sec"));
192 	w->add(_("<WAIT:NN.n>\tdelay xmt for NN.n sec"));
193 	w->add(_("<REPEAT>\trepeat macro continuously"));
194 	w->add(_("<SKED:hhmm[ss][:YYYYMMDD]>\tschedule execution for"));
195 	w->add(_("<UNTIL:hhmm[ss][:YYYYMMDD]>\tend execution at"));
196 	w->add(_("<LOCAL>\tuse local date/time"));
197 
198 	w->add(LINE_SEP);
199 	w->add(_("<TXATTEN:nn.n>\t set xmt attenuator"));
200 
201 	w->add(LINE_SEP);
202 	w->add(_("<CWID>\tCW identifier"));
203 	w->add(_("<ID>\tsend mode ID; TX start only"));
204 	w->add(_("<TEXT>\ttext at start of TX"));
205 	w->add(_("<VIDEO:\tvideo text in TX stream"));
206 	w->add(_("<TXRSID:on|off|t>\tTx RSID on,off,toggle"));
207 	w->add(_("<RXRSID:on|off|t>\tRx RSID on,off,toggle"));
208 	w->add(_("<NRSID:NN>\tTransmit |NN| successive RsID bursts"));
209 	w->add(_("<DTMF:[Wn:][Ln:]chrs>\t[Wait][Len](ms)"));
210 
211 	w->add(LINE_SEP);
212 	w->add(_("<AUDIO:>\tXmt audio wav file"));
213 
214 	w->add(LINE_SEP);
215 	w->add(_("<ALERT:[bark][checkout][doesnot][phone][beeboo][diesel][steam_train][dinner_bell][standard_tone]>"));
216 	w->add(_("<ALERT:>\talert using external wav file"));
217 
218 	w->add(LINE_SEP);
219 	w->add(_("<POST:+/-nn.n>\tCW QSK post-timing"));
220 	w->add(_("<PRE:nn.n>\tCW QSK pre-timing"));
221 	w->add(_("<RISE:nn.n>\tCW rise time"));
222 	w->add(_("<WPM:NN.nn:FF.nn>\tChar WPM:Text WPM (15.0:5.0)"));
223 
224 	w->add(LINE_SEP);
225 	w->add(_("<RIGCAT:[\"text\"][hex ...]:ret>\tsend CAT cmd"));
226 	w->add(_("<FLRIG:[\"text\"][hex ...]>\tsend CAT cmd"));
227 
228 	w->add(LINE_SEP);
229 	w->add(_("<AFC:on|off|t>\tAFC  on,off,toggle"));
230 	w->add(_("<LOCK:on|off|t>\tLOCK on,off,toggle"));
231 	w->add(_("<REV:on|off|t>\tRev on,off,toggle"));
232 
233 	w->add(LINE_SEP);
234 	w->add(_("<MACROS:>\tchange macro defs file"));
235 	w->add(_("<SAVE>\tsave current macro file"));
236 	w->add(_("<BUFFERED>\trun macro from buffered teext"));
237 
238 	w->add(LINE_SEP);
239 	w->add(_("<COMMENT:comment text>\tignore comment text"));
240 	w->add(_("<#comments>\t ignore comments"));
241 
242 	w->add(LINE_SEP);
243 	w->add(_("<CPS_TEST:nn>\tmodem char/sec test on nn chars"));
244 	w->add(_("<CPS_N:n>\tmodem timing test, 'n' random 5 char groups"));
245 	w->add(_("<CPS_FILE:>\tmodem timing test, spec' file"));
246 	w->add(_("<CPS_STRING:s>\tmodem timing test, string 's'"));
247 
248 	w->add(LINE_SEP);
249 	w->add(_("<WAV_TEST>\tWAV file; internal string"));
250 	w->add(_("<WAV_N:n>\tWAV file; 'n' random 5 char groups"));
251 	w->add(_("<WAV_FILE:>\tWAV file; spec' file"));
252 	w->add(_("<WAV_STRING:s>\tWAV file; string 's'"));
253 
254 	w->add(LINE_SEP);
255 	w->add(_("<CSV:on|off|t>\tAnalysis CSV on,off,toggle"));
256 
257 	w->add(LINE_SEP);
258 	w->add(_("<PUSH>\tpush current mode to stack"));
259 	w->add(_("<PUSH:m|f\tpush current mode / audio freq to stack"));
260 	w->add(_("<POP>\tpop current mode/freq from stack"));
261 	w->add(LINE_SEP);
262 	assert(MODE_CONTESTIA < MODE_OLIVIA);
263 	char s[256];
264 	for (trx_mode i = 0; i <= MODE_CONTESTIA; i++) {
265 		snprintf(s, sizeof(s), "<MODEM:%s>", mode_info[i].sname);
266 		w->add(s);
267 	}
268 	// add some Contestia macros
269 	const char* contestia[] = { "250:8", "250:16", "500:8", "500:16", "1000:8", "1000:16" };
270 	for (size_t i = 0; i < sizeof(contestia)/sizeof(*contestia); i++) {
271 		snprintf(s, sizeof(s), "<MODEM:%s:%s>", mode_info[MODE_CONTESTIA].sname, contestia[i]);
272 		w->add(s);
273 	}
274 	for (trx_mode i = MODE_CONTESTIA + 1; i <= MODE_OLIVIA; i++) {
275 		snprintf(s, sizeof(s), "<MODEM:%s>", mode_info[i].sname);
276 		w->add(s);
277 	}
278 	assert(MODE_OLIVIA < MODE_RTTY);
279 	// add some Olivia macros
280 	const char* olivia[] = { "250:8", "250:16", "500:8", "500:16", "1000:8", "500:32", "1000:32" };
281 	for (size_t i = 0; i < sizeof(olivia)/sizeof(*olivia); i++) {
282 		snprintf(s, sizeof(s), "<MODEM:%s:%s>", mode_info[MODE_OLIVIA].sname, olivia[i]);
283 		w->add(s);
284 	}
285 	for (trx_mode i = MODE_OLIVIA + 1; i <= MODE_RTTY; i++) {
286 		snprintf(s, sizeof(s), "<MODEM:%s>", mode_info[i].sname);
287 		w->add(s);
288 	}
289 	// add some RTTY macros
290 	const char* rtty[] = { "170:45.45:5", "170:50:5", "850:75:5" };
291 	for (size_t i = 0; i < sizeof(rtty)/sizeof(*rtty); i++) {
292 		snprintf(s, sizeof(s), "<MODEM:%s:%s>", mode_info[MODE_RTTY].sname, rtty[i]);
293 		w->add(s);
294 	}
295 	for (trx_mode i = MODE_RTTY + 1; i < NUM_MODES; i++) {
296 		snprintf(s, sizeof(s), "<MODEM:%s>", mode_info[i].sname);
297 		w->add(s);
298 	}
299 
300 #ifndef __MINGW32__
301 	glob_t gbuf;
302 	glob(string(ScriptsDir).append("*").c_str(), 0, NULL, &gbuf);
303 	if (gbuf.gl_pathc == 0) {
304 		globfree(&gbuf);
305 		return;
306 	}
307 	w->add(LINE_SEP);
308 	struct stat st;
309 
310 #  if defined(__OpenBSD__)
311 	for (int i = 0; i < gbuf.gl_pathc; i++) {
312 #  else
313 	for (size_t i = 0; i < gbuf.gl_pathc; i++) {
314 #  endif
315 		if (!(stat(gbuf.gl_pathv[i], &st) == 0
316 		      && S_ISREG(st.st_mode) && (st.st_mode & S_IXUSR)))
317 			continue;
318 
319 		const char* p;
320 		if ((p = strrchr(gbuf.gl_pathv[i], '/'))) {
321 			snprintf(s, sizeof(s), "<EXEC>%s</EXEC>", p+1);
322 			w->add(s);
323 		}
324 	}
325 	globfree(&gbuf);
326 #else
327 	w->add("<EXEC>\tlaunch a program");
328 #endif
329 }
330 
331 void cbMacroEditOK(Fl_Widget *w, void *)
332 {
333 	if (w == btnMacroEditClose) {
334 		MacroEditDialog->hide();
335 		return;
336 	}
337 
338 	if (iType == MACRO_EDIT_BUTTON) {
339 		update_macro_button(iMacro, macrotext->value(), labeltext->value());
340 	}
341 	else if (iType == MACRO_EDIT_INPUT)
342 		iInput->value(macrotext->value());
343 }
344 
345 void update_macro_button(int iMacro, const char *text, const char *name)
346 {
347 	macros.text[iMacro].assign(text);
348 	macros.name[iMacro].assign(name);
349 
350 	if (progdefaults.mbar_scheme > MACRO_SINGLE_BAR_MAX) {
351 		if (iMacro < NUMMACKEYS) {
352 			btnMacro[iMacro]->label( macros.name[iMacro].c_str() );
353 			btnMacro[iMacro]->redraw_label();
354 		} else if ((iMacro / NUMMACKEYS) == altMacros) {
355 			btnMacro[(iMacro % NUMMACKEYS) + NUMMACKEYS]->label( macros.name[iMacro].c_str() );
356 			btnMacro[(iMacro % NUMMACKEYS) + NUMMACKEYS]->redraw_label();
357 		}
358 	} else {
359 		btnMacro[iMacro % NUMMACKEYS]->label( macros.name[iMacro].c_str() );
360 		btnMacro[iMacro % NUMMACKEYS]->redraw_label();
361 	}
362 	btnDockMacro[iMacro]->label(macros.name[iMacro].c_str());
363 	btnDockMacro[iMacro]->redraw_label();
364 
365 	macros.changed = true;
366 }
367 
368 void cbInsertMacro(Fl_Widget *, void *)
369 {
370 	int nbr = macroDefs->value();
371 	if (!nbr) return;
372 	string edittext = macrotext->value();
373 	string text = macroDefs->text(nbr);
374 	size_t tab = text.find('\t');
375 	if (tab != string::npos)
376 		text.erase(tab);
377 	if (text == LINE_SEP)
378 		return;
379 	if (text == "<FILE:>") {
380 		string filters = "Text\t*.txt";
381 		const char* p = FSEL::select(
382 			_("Text file to insert"),
383 			filters.c_str(),
384 			HomeDir.c_str());
385 		if (p && *p) {
386 			text.insert(6, p);
387 		} else
388 			text = "";
389 	} else if ((text == "<CPS_FILE:>") || (text == "<WAV_FILE:>")) {
390 		string filters = "Text\t*.txt";
391 		const char* p = FSEL::select(
392 			_("Test text file"),
393 			filters.c_str(),
394 			HomeDir.c_str());
395 		if (p && *p) {
396 			text.insert(10, p);
397 		} else
398 			text = "";
399 	} else if (text == "<IMAGE:>") {
400 		string filters = "*.{png,jpg,bmp}\t*.png";
401 		const char *p = FSEL::select(
402 			_("MFSK image file"),
403 			filters.c_str(),
404 			PicsDir.c_str());
405 		if (p && *p) {
406 			text.insert(7, p);
407 		} else
408 			text = "";
409 	} else if (text == "<MACROS:>") {
410 		string filters = "Macrost\t*.mdf";
411 		const char* p = FSEL::select(
412 			_("Change to Macro file"),
413 			filters.c_str(),
414 			MacrosDir.c_str());
415 		if (p && *p) {
416 			text.insert(8, p);
417 		} else
418 			text = "";
419 	} else if (text == "<ALERT:>") {
420 		string filters = "Audio file\t*.{mp3,wav}";
421 		const char* p = FSEL::select(
422 			_("Select audio file"),
423 			filters.c_str(),
424 			HomeDir.c_str());
425 		if (p && *p) {
426 			text.insert(7, p);
427 		} else
428 			text = "";
429 	} else if (text == "<AUDIO:>") {
430 		string filters = "Audio file\t*.{mp3,wav}";
431 		const char* p = FSEL::select(
432 			_("Select audio file"),
433 			filters.c_str(),
434 			HomeDir.c_str());
435 		if (p && *p) {
436 			text.insert(7, p);
437 		} else
438 			text = "";
439 	}
440 #ifdef __MINGW32__
441 	else if (text == "<EXEC>") {
442 		string filters = "Exe\t*.exe";
443 		const char* p = FSEL::select(
444 			_("Executable file to insert"),
445 			filters.c_str(),
446 			HomeDir.c_str());
447 		if (p && *p) {
448 			string exefile = p;
449 			exefile.append("</EXEC>");
450 			text.insert(6, exefile);
451 		} else
452 			text = "";
453 	}
454 #endif
455 	macrotext->insert(text.c_str());
456 	macrotext->take_focus();
457 }
458 
459 #include <FL/Fl_Tile.H>
460 
461 Fl_Double_Window* make_macroeditor(void)
462 {
463 	Fl_Double_Window* w = new Fl_Double_Window(800, 190, "");
464 
465 	Fl_Group *grpA = new Fl_Group(0, 0, 800, 22);
466 	Fl_Group *grpB = new Fl_Group(450, 0, 350, 22);
467 	btnInsertMacro = new Fl_Button(450, 2, 40, 20);
468 	btnInsertMacro->image(new Fl_Pixmap(left_arrow_icon));
469 	btnInsertMacro->callback(cbInsertMacro);
470 	grpB->end();
471 	grpA->end();
472 
473 	Fl_Group *grpC = new Fl_Group(0, 22, 800, 140);
474 	Fl_Tile *tile = new Fl_Tile(0,22,800,140);
475 	macrotext = new Fl_Input2(0, 22, 450, 140, _("Macro Text"));
476 	macrotext->type(FL_MULTILINE_INPUT);
477 	macrotext->textfont(FL_HELVETICA);
478 	macrotext->align(FL_ALIGN_TOP);
479 
480 	macroDefs = new Fl_Hold_Browser(450, 22, 350, 140, _("Select Tag"));
481 	macroDefs->column_widths(widths);
482 	macroDefs->align(FL_ALIGN_TOP);
483 
484 	Fl_Box *minbox = new Fl_Box(200, 22, 400, 140);
485 	minbox->hide();
486 	tile->end();
487 	tile->resizable(minbox);
488 	grpC->end();
489 
490 	Fl_Group *grpD = new Fl_Group(0, 164, 452, 24);
491 	Fl_Box *box3a = new Fl_Box(0, 164, 327, 24, "");
492 	labeltext = new Fl_Input2(337, 164, 115, 24, _("Macro Button Label"));
493 	labeltext->textfont(FL_HELVETICA);
494 	grpD->end();
495 	grpD->resizable(box3a);
496 
497 	Fl_Group *grpE = new Fl_Group(452, 164, 348, 24);
498 	Fl_Box *box4a = new Fl_Box(452, 164, 92, 24, "");
499 
500 	btnMacroEditApply = new Fl_Button(544, 164, 80, 24, _("Apply"));
501 	btnMacroEditApply->callback(cbMacroEditOK);
502 
503 	btnMacroEditClose = new Fl_Button(626 , 164, 80, 24, _("Close"));
504 	btnMacroEditClose->callback(cbMacroEditOK);
505 	grpE->end();
506 	grpE->resizable(box4a);
507 
508 	w->end();
509 
510 	w->resizable(grpC);
511 
512 	w->size_range( 600, 120);
513 
514 	w->xclass(PACKAGE_NAME);
515 
516 	loadBrowser(macroDefs);
517 
518 	return w;
519 }
520 
521 void editMacro(int n, int t, Fl_Input* in)
522 {
523 	if (!MacroEditDialog)
524 		MacroEditDialog = make_macroeditor();
525 	if (t == MACRO_EDIT_BUTTON) {
526 		string editor_label;
527 		editor_label.append(_("Macro editor - ")).append(progStatus.LastMacroFile);
528 		if (editor_label != MacroEditDialog->label())
529 			MacroEditDialog->copy_label(editor_label.c_str());
530 		macrotext->value(macros.text[n].c_str());
531 		labeltext->value(macros.name[n].c_str());
532 		labeltext->show();
533 	}
534 	else if (t == MACRO_EDIT_INPUT) {
535 		MacroEditDialog->label(in->label());
536 		macrotext->value(in->value());
537 		labeltext->hide();
538 	}
539 	macrotext->textfont(progdefaults.MacroEditFontnbr);
540 	macrotext->textsize(progdefaults.MacroEditFontsize);
541 	iMacro = n;
542 	iType = t;
543 	iInput = in;
544 	MacroEditDialog->show();
545 }
546 
547 void update_macroedit_font()
548 {
549 	if (!MacroEditDialog) return;
550 	if (!MacroEditDialog->visible()) return;
551 	macrotext->textfont(progdefaults.MacroEditFontnbr);
552 	macrotext->textsize(progdefaults.MacroEditFontsize);
553 	MacroEditDialog->redraw();
554 }
555