File: f.widgets.cc

package info (click to toggle)
fotoxx 24.70-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 21,888 kB
  • sloc: cpp: 78,255; makefile: 116; xml: 52
file content (1987 lines) | stat: -rw-r--r-- 99,267 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
/********************************************************************************

   Fotocx - edit photos and manage collections

   Copyright 2007-2024 Michael Cornelison
   source code URL: https://kornelix.net
   contact: mkornelix@gmail.com

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version. See https://www.gnu.org/licenses

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   See the GNU General Public License for more details.

*********************************************************************************

   Fotocx window and menu build functions

   build_widgets           build widgets and menus for F/G/M view modes
   m_viewmode              set current F/G/M view mode
   popup_menufunc          image/thumb right-click menu func
   image_Rclick_popup      popup menu for image right-click
   gallery_Lclick_func     thumbnail left-click function
   gallery_Rclick_popup    popup menu for thumbnail right-click
   m_custom_menu           build custom user menu
   m_edit_script           edit a script file calling multiple edit functions
   m_edit_script_addfunc   edit_done() hook to insert dialog settings into script
   m_run_script            run script like edit function for current image file
   m_batch_script          run script for batch of selected image files
   m_plugins               plugins menu function
   m_edit_plugins          add/revise/delete plugin menu functions
   m_run_plugin            run a plugin menu command and update image

*********************************************************************************/

#define EX extern                                                                //  enable extern declarations
#include "fotocx.h"                                                              //  (variables in fotocx.h are defined)

using namespace zfuncs;

/********************************************************************************/

GtkWidget   *mFile, *mGallery, *mMaps, *mMeta, *mSelect;
GtkWidget   *mEdit, *mRepair, *mRefine, *mEffects, *mWarp, *mComb;
GtkWidget   *mBatch, *mTools, *mHelp, *mDevmenu;
GtkWidget   *popmenu_image, *popmenu_raw, *popmenu_mpo, *popmenu_video;
GtkWidget   *popmenu_thumb, *popmenu_album;


//  initialize widgets and menus for F/G/M view modes
//  called from main() before gtk_main() loop is entered

void build_widgets()
{
   Mwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);                                   //  create main window
   gtk_window_set_title(MWIN,Frelease);

   MWhbox = gtk_box_new(HORIZONTAL,0);                                           //  main window top container
   gtk_container_add(GTK_CONTAINER(Mwin),MWhbox);

   MWmenu = gtk_box_new(VERTICAL,0);                                             //  container for main window menus
   gtk_box_pack_start(GTK_BOX(MWhbox),MWmenu,0,1,0);

   MWvbox = gtk_box_new(VERTICAL,0);                                             //  container for F/G/M views
   gtk_box_pack_start(GTK_BOX(MWhbox),MWvbox,1,1,0);

   G_SIGNAL(Mwin,"delete-event",delete_event,0);                                 //  connect signals to main window
   G_SIGNAL(Mwin,"destroy",destroy_event,0);
   G_SIGNAL(Mwin,"window-state-event",state_event,0);
   G_SIGNAL(Mwin,"key-press-event",KBpress,0);                                   //  connect KB events to main window
   G_SIGNAL(Mwin,"key-release-event",KBrelease,0);

   //  F view widgets - image file

   Fhbox = gtk_box_new(HORIZONTAL,0);                                            //  top container
   gtk_box_pack_start(GTK_BOX(MWvbox),Fhbox,1,1,0);
   Fvbox = gtk_box_new(VERTICAL,0);                                              //  vbox for image
   gtk_box_pack_start(GTK_BOX(Fhbox),Fvbox,1,1,0);
   Fpanel = gtk_box_new(HORIZONTAL,0);                                           //  panel over image
   gtk_box_pack_start(GTK_BOX(Fvbox),Fpanel,0,0,0);
   gtk_widget_set_size_request(Fpanel,0,20);
   Fpanlab = gtk_label_new("panel");
   gtk_box_pack_start(GTK_BOX(Fpanel),Fpanlab,0,0,0);
   Fpanelshow = 1;                                                               //  panel normally shows
   Fdrawin = gtk_drawing_area_new();                                             //  image drawing area
   gtk_box_pack_start(GTK_BOX(Fvbox),Fdrawin,1,1,0);
   gtk_widget_hide(Fhbox);

   gtk_widget_add_events(Fdrawin,GDK_BUTTON_PRESS_MASK);                         //  connect mouse events to image window
   gtk_widget_add_events(Fdrawin,GDK_BUTTON_RELEASE_MASK);
   gtk_widget_add_events(Fdrawin,GDK_BUTTON_MOTION_MASK);
   gtk_widget_add_events(Fdrawin,GDK_POINTER_MOTION_MASK);
   gtk_widget_add_events(Fdrawin,GDK_SCROLL_MASK);
   G_SIGNAL(Fdrawin,"button-press-event",mouse_event,0);                         //  connect signals
   G_SIGNAL(Fdrawin,"button-release-event",mouse_event,0);
   G_SIGNAL(Fdrawin,"motion-notify-event",mouse_event,0);
   G_SIGNAL(Fdrawin,"scroll-event",mouse_event,0);
   G_SIGNAL(Fdrawin,"draw",Fpaint,0);
   drag_drop_dest(Fdrawin,drop_event);                                           //  accept drag-drop file

   //  G view widgets - thumbnail gallery

   Ghbox = gtk_box_new(HORIZONTAL,0);                                            //  top container
   gtk_box_pack_start(GTK_BOX(MWvbox),Ghbox,1,1,0);
   Gvbox = gtk_box_new(VERTICAL,0);                                              //  vbox for gallery
   gtk_box_pack_start(GTK_BOX(Ghbox),Gvbox,1,1,0);
   Gpanel = gtk_box_new(HORIZONTAL,0);                                           //  top panel for [TOP] and navi buttons
   gtk_box_pack_start(GTK_BOX(Gvbox),Gpanel,0,0,2);
   Galbum = gtk_button_new_with_label("Album");                                  //  [Album] button in panel
   gtk_box_pack_start(GTK_BOX(Gpanel),Galbum,0,0,3);
   Gtop = gtk_button_new_with_label("TOP");                                      //  [TOP] button in panel
   gtk_box_pack_start(GTK_BOX(Gpanel),Gtop,0,0,3);
   Gsep = gtk_label_new(0);
   gtk_label_set_markup(GTK_LABEL(Gsep),"<span font=\"sans bold 12\" >@</span>");
   gtk_box_pack_start(GTK_BOX(Gpanel),Gsep,0,0,10);

   Gsep = gtk_separator_new(HORIZONTAL);                                         //  separator line
   gtk_box_pack_start(GTK_BOX(Gvbox),Gsep,0,0,3);
   Gscroll = gtk_scrolled_window_new(0,0);                                       //  scrolled window for gallery
   gtk_scrolled_window_set_policy(SCROLLWIN(Gscroll),NEVER,ALWAYS);
   Gadjust = gtk_scrolled_window_get_vadjustment(SCROLLWIN(Gscroll));
   gtk_box_pack_start(GTK_BOX(Gvbox),Gscroll,1,1,0);
   Gdrawin = gtk_drawing_area_new();                                             //  gallery drawing area
   gtk_container_add(GTK_CONTAINER(Gscroll),Gdrawin);
   gtk_widget_hide(Ghbox);

   gtk_widget_add_events(Gdrawin,GDK_BUTTON_PRESS_MASK);                         //  connect mouse events to gallery window
   gtk_widget_add_events(Gdrawin,GDK_BUTTON_RELEASE_MASK);
   gtk_widget_add_events(Gdrawin,GDK_POINTER_MOTION_MASK);
   G_SIGNAL(Gtop,"clicked",navi::newtop,0);
   G_SIGNAL(Galbum,"clicked",navi::newalbum,0);
   G_SIGNAL(Gdrawin,"button-press-event",navi::mouse_event,0);
   G_SIGNAL(Gdrawin,"button-release-event",navi::mouse_event,0);
   G_SIGNAL(Gdrawin,"motion-notify-event",navi::mouse_event,0);
   G_SIGNAL(Gdrawin,"draw",navi::gallery_paint,null);
   drag_drop_source(Gdrawin,navi::gallery_dragfile);                             //  start file drag-drop
   drag_drop_dest(Gdrawin,navi::gallery_dropfile);                               //  accept drag-drop file

   //  M view widgets - internet map

   Mhbox = gtk_box_new(HORIZONTAL,0);                                            //  top container
   gtk_box_pack_start(GTK_BOX(MWvbox),Mhbox,1,1,0);
   Mvbox = gtk_box_new(VERTICAL,0);                                              //  vbox for map window
   gtk_box_pack_start(GTK_BOX(Mhbox),Mvbox,1,1,0);
   gtk_widget_hide(Mhbox);

   //  menu popup text (tool tips) ----------------------------------------

   //  main menu buttons
   ch * File_tip = "File: new session, open, rename, copy/move, delete, print";
   ch * Gallery_tip = "Gallery: thumbnails, new/recent, sort, select, bookmarks, albums, slide show";
   ch * Maps_tip = "Maps: internet world map, images by map location";
   ch * custom_menu_tip = "Custom menu: add favorite or frequent functions here";
   ch * prev_next_tip = "Left/right click: previous/next image (also ←/→ keys)";
   ch * zoom_menu_tip = "Left/right click: zoom image/thumbnail in/out (also +/- keys)";
   ch * save_tip = "Save modified image as new file or new file version";
   ch * metadata_tip = "View/edit metadata, manage tags, images by location/date, search images";
   ch * select_tip = "Select image areas to edit separately, copy/paste selections";
   ch * undo_redo_tip = "Left/right click: undo/redo one edit step \n"
                           "  (with A-key: undo/redo all edits) \n"
                           " Middle click: go back to selected edit step";
   ch * edit_tip = "Edit: crop, rotate, retouch, rescale, markup, paint edits, copy areas, plugins";
   ch * repair_tip = "Repair: sharpen, blur, denoise, defog, red eyes, smart erase, adjust color";
   ch * refine_tip = "Refine: edit histogram, flatten histogram, local contrast, amplify contrast, retinex, saturation";
   ch * effects_tip = "Effects: cartoon, sketch, paint, emboss, dither, add texture, change colors, custom convolution";
   ch * warp_tip = "Warp: unbend, fix perspective, warp, unwarp closeup, flatten, image transforms";
   ch * combine_tip = "Combine: HDR, HDF, stack, panorama, mashup, image array";
   ch * batch_tip = "Batch: copy, move, convert, RAW convert, add/change metadata, custom scripts";
   ch * tools_tip = "Tools: image index, settings, shortcuts, magnify, find duplicates, grid lines";
   ch * help_tip = "Help: user guide, tutorial, change log, licenses, privacy, about";

   //  file menu
   ch * new_session_tip = "Open a parallel Fotocx session";
   ch * open_file_tip = "Select and view an image file";
   ch * cycle2files_tip = "Cycle 2 Prior Files";
   ch * cycle3files_tip = "Cycle 3 Prior Files";
   ch * view360_tip = "View 360 degree panorama image";
   ch * rename_tip = "Change file name";
   ch * permissions_tip = "View and change file permissions";
   ch * change_alpha_tip = "Add/Remove image file alpha channel (transparency)";
   ch * blank_image_tip = "Create a blank image";
   ch * copy_move_tip = "Copy or Move image file to new location";
   ch * copyto_desktop_tip = "Copy image file to the desktop";
   ch * copyto_clipboard_tip = "Copy image file to the clipboard";
   ch * deltrash_tip = "Delete or trash an image file";
   ch * convert_adobe_tip = "Convert Adobe document file into jpeg file(s)";
   ch * set_wallpaper_tip = "Set image file as desktop wallpaper (GNOME only)";
   ch * print_image_tip = "Print the current image file";
   ch * print_calibrated_tip = "Print current image file with adjusted colors";
   ch * calib_printer_tip = "Printer color calibration tool";
   ch * quit_tip = "Quit Fotocx";

   //  gallery menu
   ch * thumbview_tip = "Gallery view with thumbnails and file data";
   ch * metaview_tip = "Gallery view with thumbnails and basic metadata";
   ch * recentfiles_tip = "Gallery of recently viewed image files";
   ch * newfiles_tip = "Gallery of newest image files";
   ch * gallery_sort_tip = "Change gallery sort order";
   ch * gallery_screen_tip = "Select newest, oldest, matching pattern ...";
   ch * gallery_home_tip = "Jump to gallery beginning [home]";
   ch * gallery_end_tip = "Jump to gallery end [end]";
   ch * current_folder_tip = "Set gallery from current image file folder";
   ch * recent_folders_tip = "Set gallery to recently used folder";
   ch * folder_tree_tip = "Show folder tree, click any branch for gallery view";
   ch * select_files_tip = "Select input files for subsequent function";
   ch * rename_folder_tip = "Rename current folder (current gallery)";
   ch * add_subfolder_tip = "Add a new subfolder to current gallery";
   ch * bookmarks_tip = "Set and recall bookmarked image locations";
   ch * manage_albums_tip = "Organize images into albums";
   ch * update_albums_tip = "Update albums for new file versions";
   ch * album_mass_update_tip = "Mass update album files";
   ch * gallery2album_tip = "Save current gallery as album";
   ch * slideshow_tip = "Start a slide show";

   //  maps menu
   ch * map_regions_tip = "Add custom map region names, go to named region";
   ch * map_location_tip = "Input (partial) location name, find full name, go there";
   ch * set_map_markers_tip = "Show map markers for all images or current gallery";
   ch * show_on_map_tip = "Show current image location on map";

   //  metadata menu
   ch * meta_view_main_tip = "Show key metadata for current image or clicked thumbnail";
   ch * meta_view_all_tip = "List all metadata for current image or clicked thumbnail";
   ch * meta_edit_main_tip = "Edit key metadata: tags/geotags/caption/rating ...";
   ch * meta_edit_any_tip = "Edit any metadata item";
   ch * meta_delete_tip = "Remove selected image metadata";
   ch * meta_copy_tip = "Copy metadata from one image to another";
   ch * meta_fix_tip = "Repair malformed metadata preventing metadata edits";
   ch * meta_manage_tags_tip = "Define tags (keywords) used for searching images";
   ch * meta_choose_caps_tip = "Choose metadata shown on image (captions etc.)";
   ch * meta_toggle_caps_tip = "Toggle image metadata display ON/OFF";
   ch * meta_places_dates_tip = "Find all images for a location [date range]";
   ch * meta_timeline_tip = "Show image counts in year/month calendar, select, report";
   ch * search_images_tip = "Find images meeting multiple search criteria";

   //  select area menu
   ch * select_area_tip = "Select objects or areas for separate editing";
   ch * select_find_gap_tip = "Find a gap in an area outline";
   ch * select_blend_tip = "Blend area edits using the mouse";
   ch * select_show_tip = "Show (outline) selected areas";
   ch * select_hide_tip = "Hide selected areas";
   ch * select_enable_tip = "Enable areas for editing";
   ch * select_disable_tip = "Disable areas for editing";
   ch * select_invert_tip = "Invert selected areas (selected ↔ not selected)";
   ch * select_clear_tip = "Erase existing areas";
   ch * select_copy_tip = "Copy area for later pasting into image";
   ch * select_paste_tip = "Paste previously copied area into image";
   ch * select_load_tip = "Open a file and paste as selected area into image";
   ch * select_save_tip = "Save selected area to a file with transparency";

   //  edit menu
   ch * rotate_tip = "Rotate or level image, upright, mirror";
   ch * upright_tip = "Upright a rotated image with one button";
   ch * crop_tip = "Crop (trim) image margins";
   ch * retouch_tip = "Adjust brightness, contrast, color";
   ch * rescale_tip = "Change image pixel dimensions";
   ch * margins_tip = "Add margins around an image";
   ch * markup_tip = "Draw on image: text, line/arrow, box, circle, ellipse";
   ch * color_mode_tip = "Set black-white/color, negative/positive, sepia";
   ch * paint_edits_tip = "Paint current edit function gradually using the mouse";
   ch * paint_image_tip = "Paint on image using the mouse";
   ch * paint_transp_tip = "Paint image transparency using the mouse";
   ch * area_fill_tip = "Fill selected areas or transparent areas with a color";
   ch * copy_in_image_tip = "Copy pixels within an image using the mouse";
   ch * copy_from_image_tip = "Copy pixels from another image using the mouse";
   ch * copy_prior_edit_tip = "Copy pixels from prior edits using the mouse";

   //  repair menu
   ch * sharpen_tip = "Sharpen the image (various methods)";
   ch * blur_tip = "Blur the image (various methods)";
   ch * denoise_tip = "Suppress noise from low-light photos";
   ch * defog_tip = "Reduce fog/haze in an image or selected area";
   ch * redeyes_tip = "Fix red-eyes from flash photo";
   ch * smart_erase_tip = "Remove unwanted objects in an image";
   ch * remove_halo_tip = "Remove halos left by other edit functions";
   ch * jpeg_artifacts_tip = "Suppress JPEG compression artifacts";
   ch * anti_alias_tip = "Remove jaggies on image feature hard edges";
   ch * adjust_RGB_tip = "Adjust color using RGB or CMY colors";
   ch * adjust_HSL_tip = "Adjust color using HSL colors";
   ch * remove_dust_tip = "Remove dust spots from old scanned photos";
   ch * fringes_tip = "Fix color fringes (chromatic aberration)";

   //  refine menu
   ch * edit_hist_tip = "Edit brightness histogram directly";
   ch * flat_hist_tip = "Flatten brightness histogram to enhance details";
   ch * localcon_tip = "Rescale RGB levels to increase local contrast";
   ch * amplifycon_tip = "Amplify existing contrast to enhance visibility of details";
   ch * retinex_tip = "Rescale RGB - reduce color caste and fog/haze";
   ch * saturation_tip = "Adjust color saturation based on brightness";
   ch * soft_focus_tip = "Apply a soft focus effect to an image";
   ch * match_colors_tip = "Match image colors with those of another image";
   ch * brite_ramp_tip = "Add a brightness/color ramp across an image";
   ch * vignette_tip = "Add/remove brightness/color radially from chosen center";

   //  effects menu
   ch * outlines_tip = "Convert image into a line drawing";
   ch * sketch_tip = "Convert image into a simulated sketch";
   ch * cartoon_tip = "Convert image into a cartoon drawing";
   ch * emboss_tip = "Create an embossed or 3D appearance";
   ch * tiles1_tip = "Convert image into square tiles with 3D effect";
   ch * tiles2_tip = "Convert image into irregular tiles matching image";
   ch * painting_tip = "Convert image into a simulated painting";
   ch * texture_tip = "Add texture to an image";
   ch * pattern_tip = "Tile image with a repeating pattern";
   ch * dither_tip = "Convert image into dithered dots";
   ch * engrave_tip = "Convert image into black/white lines";
   ch * mosaic_tip = "Create a mosaic with tiles made from all images";
   ch * add_noise_tip = "Add random noise to an image";
   ch * set_colors_tip = "Set number of colors for R/G/B or total";
   ch * shift_colors_tip = "Shift/convert image colors into other colors";
   ch * alien_colors_tip = "Change image colors using an algorithm";
   ch * anykernel_tip = "Process an image using a custom convolution kernel";

   //  warp menu
   ch * unbend_tip = "Remove image curvature, especially in panoramas";
   ch * perspective_tip = "Fix perspective for object photographed from an angle";
   ch * warp_area_tip = "Distort image areas using the mouse";
   ch * warp_curved_tip = "Warp image (curved) using the mouse";
   ch * warp_linear_tip = "Warp image (linear) using the mouse";
   ch * warp_affine_tip = "Warp image (affine) using the mouse";
   ch * warp_radial_tip = "Add/remove barrel/pincushion distortion";
   ch * unwarp_closeup_tip = "Rectify closeup face photo (balloon face)";
   ch * makewaves_tip = "Warp an image with a wave pattern";
   ch * twist_tip = "Twist image centered at mouse position";
   ch * sphere_tip = "Make a spherical projection of an image";
   ch * inside_out_tip = "Turn an image inside-out";
   ch * tiny_planet_tip = "Convert an image into a Tiny Planet";
   ch * escher_spiral_tip = "Generate an inward spiraling repeating image";
   ch * flatphoto_tip = "Flatten photo of a curved image";

   //  combine menu
   ch * HDR_tip = "High Dynamic Range - combine bright/dark images for better detail";
   ch * HDF_tip = "High Depth of Field - combine near/far focus images for deeper focus";
   ch * stack_paint_tip = "Combine multiple photos to erase passing people, etc.";
   ch * stack_noise_tip = "Combine multiple noisy photos into a low-noise image";
   ch * stack_layers_tip = "Combine multiple images in layers, select and paint layers";
   ch * stack_split_tip = "Compare two images split by a sliding boundary";
   ch * panorama_tip = "Combine 2-6 images into a wide panorama";
   ch * show_cim_files_tip = "Show input files used in combine function";
   ch * mashup_tip = "Arrange images and text in a layout (montage)";
   ch * image_array_tip = "Combine many images into a array of images";

   //  batch menu
   ch * batch_convert_tip = "Rename/convert/rescale/move selected image files";
   ch * batch_copy_move_tip = "Copy/move selected image files to a new folder";
   ch * batch_upright_tip = "Upright rotated image files, selected or ALL";
   ch * batch_deltrash_tip = "Delete or Trash selected image files";
   ch * batch_RAW_tip = "Convert camera RAW files to tiff/png/jpeg";
   ch * batch_overlay_tip = "Add overlay image (e.g. copyright) to selected images";
   ch * batch_tags_tip = "Add/remove tags for selected image files";
   ch * batch_rename_tags_tip = "Revise tag names for all image files";
   ch * batch_photo_DT_tip = "Set or shift photo date/time for selected image files";
   ch * batch_change_meta_tip = "Add/change/delete metadata for selected image files";
   ch * batch_report_meta_tip = "Report selected metadata for selected image files";
   ch * batch_meta_mover_tip = "Move metadata between keys (e.g. caption -> description)";
   ch * batch_geotags_tip = "Add/revise location/geocoordinates for selected image files";
   ch * export_filelist_tip = "Create a file of selected image files";
   ch * export_files_tip = "Export selected image files to a folder";

   //  tools menu
   ch * index_tip = "Index new image files and make thumbnails";
   ch * quick_index_tip = "Quick incremental index update";
   ch * settings_tip = "User preferences and settings";
   ch * KB_shortcuts_tip = "Show or make Keyboard Shortcuts";
   ch * RGB_hist_tip = "RGB brightness histogram graph";
   ch * magnify_tip = "Magnify image around the mouse position";
   ch * measure_image_tip = "Measure distances within an image";
   ch * show_RGB_tip = "Show RGB colors at mouse position";
   ch * grid_settings_tip = "Set grid line counts or spacing";
   ch * toggle_grid_tip = "Toggle grid lines on and off";
   ch * line_color_tip = "Set foreground line color (crop, grid, select, warp)";
   ch * darkbrite_tip = "Highlight darkest and brightest pixels";
   ch * monitor_color_tip = "Chart to adjust monitor color";
   ch * duplicates_tip = "Search all image files and report duplicates";
   ch * resources_tip = "Show memory and CPU resources used";

   //  help menu
   ch * user_guide_tip = "Read or search the user guide";
   ch * video_tutorial_tip = "Fotocx video tutorial on YouTube";
   ch * outboard_programs_tip = "List outboard programs and functions";
   ch * logfile_tip = "View the log file (info and error messages)";
   ch * command_params_tip = "List Fotocx command line parameters";
   ch * changelog_tip = "Show Fotocx changes for recent releases";
   ch * copyright_tip = "Fotocx copyright notice";
   ch * privacy_tip = "Fotocx privacy policy";
   ch * about_tip = "Show Fotocx installed version and author contact";
   ch * homepage_tip = "Fotocx web site (information and downloads)";
   ch * uninstall_tip = "Remove Fotocx application and data files";


   //  build menu table ---------------------------------------------------------

   #define MENU(_topmenu, _text, _icon, _tip, _func, _arg)        \
      me = Nmenus++;                                              \
      if (me >= maxmenus) zappcrash("maxmenus exceeded");         \
      menutab[me].topmenu = _topmenu;                             \
      menutab[me].menu = _text;                                   \
      menutab[me].icon = _icon;                                   \
      menutab[me].desc = _tip;                                    \
      menutab[me].func = _func;                                   \
      if (_arg) menutab[me].arg = _arg;                           \
      else menutab[me].arg = _text;                               \

   int      me;
   Nmenus = 0;

   mFile = create_popmenu();
   MENU(mFile,    "New Session", 0,           new_session_tip,              m_new_session, 0 );
   MENU(mFile,    "Open Image File", 0,       open_file_tip,                m_open_file, 0 );
   MENU(mFile,    "Cycle 2 Files", 0,         cycle2files_tip,              m_cycle2files, 0 );
   MENU(mFile,    "Cycle 3 Files", 0,         cycle3files_tip,              m_cycle3files, 0 );
   MENU(mFile,    "View 360° Pano", 0,        view360_tip,                  m_view360, 0);
   MENU(mFile,    "Rename", 0,                rename_tip,                   m_rename, 0 );
   MENU(mFile,    "Permissions", 0,           permissions_tip,              m_permissions, 0 );
   MENU(mFile,    "Change Alpha", 0,          change_alpha_tip,             m_change_alpha, 0 );
   MENU(mFile,    "Blank Image", 0,           blank_image_tip,              m_blank_image, 0 );
   MENU(mFile,    "Copy/Move", 0,             copy_move_tip,                m_copy_move, 0 );
   MENU(mFile,    "Copy to Desktop", 0,       copyto_desktop_tip,           m_copyto_desktop, 0 );
   MENU(mFile,    "Copy to Clipboard", 0,     copyto_clipboard_tip,         m_copyto_clip, 0 );
   MENU(mFile,    "Delete/Trash", 0,          deltrash_tip,                 m_delete_trash, 0 );
   MENU(mFile,    "Convert Adobe", 0,         convert_adobe_tip,            m_convert_adobe, 0 );
   MENU(mFile,    "Set Wallpaper", 0,         set_wallpaper_tip,            m_wallpaper, 0 );
   MENU(mFile,    "Print Image", 0,           print_image_tip,              m_print_image, 0 );
   MENU(mFile,    "Print Calibrated", 0,      print_calibrated_tip,         m_print_calibrated, 0 );
   MENU(mFile,    "Calibrate Printer", 0,     calib_printer_tip,            m_calibrate_printer, 0 );
   MENU(mFile,    "Quit", 0,                  quit_tip,                     m_quit, 0 );

   mGallery = create_popmenu();
   MENU(mGallery,   "Thumb View", 0,          thumbview_tip,                m_thumbview, 0 );
   MENU(mGallery,   "Meta View", 0,           metaview_tip,                 m_metaview, 0 );
   MENU(mGallery,   "Recent Files", 0,        recentfiles_tip,              m_recentfiles, 0 );
   MENU(mGallery,   "Newest Files", 0,        newfiles_tip,                 m_newfiles, 0 );
   MENU(mGallery,   "Gallery Sort", 0,        gallery_sort_tip,             m_gallery_sort, 0);
   MENU(mGallery,   "Gallery Screen", 0,      gallery_screen_tip,           m_gallery_screen, 0);
   MENU(mGallery,   "Gallery Home", 0,        gallery_home_tip,             navi::menufuncx, "Home" );
   MENU(mGallery,   "Gallery End", 0,         gallery_end_tip,              navi::menufuncx, "End" );
   MENU(mGallery,   "Current Folder", 0,      current_folder_tip,           m_current_folder, 0 );
   MENU(mGallery,   "Recent Folders", 0,      recent_folders_tip,           m_recent_folders, 0 );
   MENU(mGallery,   "Folder Tree", 0,         folder_tree_tip,              m_folder_tree, 0 );
   MENU(mGallery,   "Select Files", 0,        select_files_tip,             m_select_files, 0 );
   MENU(mGallery,   "Rename Folder", 0,       rename_folder_tip,            m_rename_folder, 0 );
   MENU(mGallery,   "Add Subfolder", 0,       add_subfolder_tip,            m_add_subfolder, 0 );
   MENU(mGallery,   "Bookmarks", 0,           bookmarks_tip,                m_bookmarks, 0 );
   MENU(mGallery,   "Manage Albums", 0,       manage_albums_tip,            m_manage_albums, 0 );
   MENU(mGallery,   "Update Albums", 0,       update_albums_tip,            m_update_albums, 0 );
   MENU(mGallery,   "Gallery to Album", 0,    gallery2album_tip,            m_gallery2album, 0 );
   MENU(mGallery,   "Album Mass Update", 0,   album_mass_update_tip,        m_album_mass_update, 0 );
   MENU(mGallery,   "Slide Show", 0,          slideshow_tip,                m_slideshow, 0 );

   mMaps = create_popmenu();
   MENU(mMaps,     "Map Regions", 0,          map_regions_tip,              m_map_regions, 0 );
   MENU(mMaps,     "Map Location", 0,         map_location_tip,             m_map_location, 0 );
   MENU(mMaps,     "Map Markers", 0,          set_map_markers_tip,          m_set_map_markers, 0 );
   MENU(mMaps,     "Show on Map", 0,          show_on_map_tip,              m_map_zoomin, 0 );

   mMeta = create_popmenu();
   MENU(mMeta,    "View Main Meta", 0,        meta_view_main_tip,           m_meta_view_short, 0 );
   MENU(mMeta,    "View All Meta", 0,         meta_view_all_tip,            m_meta_view_long, 0 );
   MENU(mMeta,    "Edit Main Meta", 0,        meta_edit_main_tip,           m_meta_edit_main, 0 );
   MENU(mMeta,    "Edit Any Meta", 0,         meta_edit_any_tip,            m_meta_edit_any, 0 );
   MENU(mMeta,    "Delete Meta", 0,           meta_delete_tip,              m_meta_delete, 0 );
   MENU(mMeta,    "Copy Meta", 0,             meta_copy_tip,                m_meta_copy, 0 );
   MENU(mMeta,    "Fix Meta", 0,              meta_fix_tip,                 m_meta_fix, 0 );
   MENU(mMeta,    "Manage Tags", 0,           meta_manage_tags_tip,         m_meta_manage_tags, 0 );
   MENU(mMeta,    "Choose Captions", 0,       meta_choose_caps_tip,         m_meta_choose_caps, 0 );
   MENU(mMeta,    "Toggle Captions", 0,       meta_toggle_caps_tip,         m_meta_toggle_caps, 0 );
   MENU(mMeta,    "Places/Dates", 0,          meta_places_dates_tip,        m_meta_places_dates, 0 );
   MENU(mMeta,    "Timeline", 0,              meta_timeline_tip,            m_meta_timeline, 0 );
   MENU(mMeta,    "Search", 0,                search_images_tip,            m_search_images, 0 );

   mSelect = create_popmenu();
   MENU(mSelect,     "Select Area", 0,        select_area_tip,              m_select_area, 0 );
   MENU(mSelect,     "Find Gap", 0,           select_find_gap_tip,          m_select_find_gap, 0 );
   MENU(mSelect,     "Area Blend", 0,         select_blend_tip,             m_select_blend, 0 );
   MENU(mSelect,     "Show", 0,               select_show_tip,              m_select_show, 0 );
   MENU(mSelect,     "Hide", 0,               select_hide_tip,              m_select_hide, 0 );
   MENU(mSelect,     "Enable", 0,             select_enable_tip,            m_select_enable, 0 );
   MENU(mSelect,     "Disable", 0,            select_disable_tip,           m_select_disable, 0 );
   MENU(mSelect,     "Invert", 0,             select_invert_tip,            m_select_invert, 0 );
   MENU(mSelect,     "Clear", 0,              select_clear_tip,             m_select_clear, 0 );
   MENU(mSelect,     "Copy", 0,               select_copy_tip,              m_select_copy, 0 );
   MENU(mSelect,     "Paste", 0,              select_paste_tip,             m_select_paste, 0 );
   MENU(mSelect,     "Load", 0,               select_load_tip,              m_select_load, 0 );
   MENU(mSelect,     "Save", 0,               select_save_tip,              m_select_save, 0 );

   mEdit = create_popmenu();
   MENU(mEdit,    "Rotate", 0,                rotate_tip,                   m_rotate, 0 );
   MENU(mEdit,    "Upright", 0,               upright_tip,                  m_upright, 0 );
   MENU(mEdit,    "Crop", 0,                  crop_tip,                     m_crop, 0 );
   MENU(mEdit,    "Retouch", 0,               retouch_tip,                  m_retouch, 0 );
   MENU(mEdit,    "Rescale", 0,               rescale_tip,                  m_rescale, 0 );
   MENU(mEdit,    "Margins", 0,               margins_tip,                  m_margins, 0 );
   MENU(mEdit,    "Markup", 0,                markup_tip,                   m_markup, 0 );
   MENU(mEdit,    "Color Mode", 0,            color_mode_tip,               m_color_mode, 0 );
   MENU(mEdit,    "Paint Edits", 0,           paint_edits_tip,              m_paint_edits, 0 );
   MENU(mEdit,    "Paint Image", 0,           paint_image_tip,              m_paint_image, 0 );
   MENU(mEdit,    "Paint Transp", 0,          paint_transp_tip,             m_paint_transp, 0 );
   MENU(mEdit,    "Area Fill", 0,             area_fill_tip,                m_area_fill, 0 );
   MENU(mEdit,    "Copy in Image", 0,         copy_in_image_tip,            m_copy_in_image, 0 );
   MENU(mEdit,    "Copy From Image", 0,       copy_from_image_tip,          m_copy_from_image, 0 );
   MENU(mEdit,    "Copy Prior Edit", 0,       copy_prior_edit_tip,          m_copy_prior_edit, 0 );

   mRepair = create_popmenu();
   MENU(mRepair,     "Sharpen", 0,            sharpen_tip,                  m_sharpen, 0 );
   MENU(mRepair,     "Blur", 0,               blur_tip,                     m_blur, 0 );
   MENU(mRepair,     "Denoise", 0,            denoise_tip,                  m_denoise, 0 );
   MENU(mRepair,     "Defog", 0,              defog_tip,                    m_defog, 0 );
   MENU(mRepair,     "Red Eyes", 0,           redeyes_tip,                  m_redeyes, 0 );
   MENU(mRepair,     "Smart Erase", 0,        smart_erase_tip,              m_smart_erase, 0 );
   MENU(mRepair,     "Remove Halo", 0,        remove_halo_tip,              m_remove_halo, 0 );
   MENU(mRepair,     "JPEG Artifacts", 0,     jpeg_artifacts_tip,           m_jpeg_artifacts, 0 );
   MENU(mRepair,     "Anti-Alias", 0,         anti_alias_tip,               m_anti_alias, 0 );
   MENU(mRepair,     "Adjust RGB", 0,         adjust_RGB_tip,               m_adjust_RGB, 0 );
   MENU(mRepair,     "Adjust HSL", 0,         adjust_HSL_tip,               m_adjust_HSL, 0 );
   MENU(mRepair,     "Remove Dust", 0,        remove_dust_tip,              m_remove_dust, 0 );
   MENU(mRepair,     "Color Fringes", 0,      fringes_tip,                  m_fringes, 0 );

   mRefine = create_popmenu();
   MENU(mRefine,     "Edit Histogrsm", 0,        edit_hist_tip,             m_edit_hist, 0 );
   MENU(mRefine,     "Flatten Histogram", 0,     flat_hist_tip,             m_flat_hist, 0 );
   MENU(mRefine,     "Local Contrast", 0,        localcon_tip,              m_localcon, 0 );
   MENU(mRefine,     "Amplify Contrast", 0,      amplifycon_tip,            m_amplifycon, 0 );
   MENU(mRefine,     "Global Retinex", 0,        retinex_tip,               m_gretinex, 0 );
   MENU(mRefine,     "Local Retinex", 0,         retinex_tip,               m_lretinex, 0 );
   MENU(mRefine,     "Saturation", 0,            saturation_tip,            m_saturation, 0 );
   MENU(mRefine,     "Soft Focus", 0,            soft_focus_tip,            m_soft_focus, 0 );
   MENU(mRefine,     "Match Colors", 0,          match_colors_tip,          m_match_colors, 0 );
   MENU(mRefine,     "Brightness Ramp", 0,       brite_ramp_tip,            m_brite_ramp, 0 );
   MENU(mRefine,     "Vignette", 0,              vignette_tip,              m_vignette, 0 );

   mEffects = create_popmenu();
   MENU(mEffects,    "Outlines", 0,              outlines_tip,              m_outlines, 0 );
   MENU(mEffects,    "Sketch", 0,                sketch_tip,                m_sketch, 0 );
   MENU(mEffects,    "Cartoon", 0,               cartoon_tip,               m_cartoon, 0 );
   MENU(mEffects,    "Emboss", 0,                emboss_tip,                m_emboss, 0 );
   MENU(mEffects,    "Tiles1", 0,                tiles1_tip,                m_tiles1, 0 );
   MENU(mEffects,    "Tiles2", 0,                tiles2_tip,                m_tiles2, 0 );
   MENU(mEffects,    "Painting", 0,              painting_tip,              m_painting, 0 );
   MENU(mEffects,    "Texture", 0,               texture_tip,               m_texture, 0 );
   MENU(mEffects,    "Pattern", 0,               pattern_tip,               m_pattern, 0 );
   MENU(mEffects,    "Dither", 0,                dither_tip,                m_dither, 0 );
   MENU(mEffects,    "Engrave", 0,               engrave_tip,               m_engrave, 0 );
   MENU(mEffects,    "Mosaic", 0,                mosaic_tip,                m_mosaic, 0 );
   MENU(mEffects,    "Add Noise", 0,             add_noise_tip,             m_add_noise, 0 );
   MENU(mEffects,    "Set Colors", 0,            set_colors_tip,            m_set_colors, 0 ); 
   MENU(mEffects,    "Shift Colors", 0,          shift_colors_tip,          m_shift_colors, 0 );
   MENU(mEffects,    "Alien Colors", 0,          alien_colors_tip,          m_alien_colors, 0 );
   MENU(mEffects,    "Custom Kernel", 0,         anykernel_tip,             m_anykernel, 0 );

   mWarp = create_popmenu();
   MENU(mWarp,    "Unbend", 0,                   unbend_tip,                m_unbend, 0 );
   MENU(mWarp,    "Perspective", 0,              perspective_tip,           m_perspective, 0 );
   MENU(mWarp,    "Warp Area", 0,                warp_area_tip,             m_warp_area, 0 );
   MENU(mWarp,    "Warp Curved", 0,              warp_curved_tip,           m_warp_curved, 0 );
   MENU(mWarp,    "Warp Linear", 0,              warp_linear_tip,           m_warp_linear, 0 );
   MENU(mWarp,    "Warp Affine", 0,              warp_affine_tip,           m_warp_affine, 0 );
   MENU(mWarp,    "Warp Radial", 0,              warp_radial_tip,           m_warp_radial, 0);
   MENU(mWarp,    "Unwarp Closeup", 0,           unwarp_closeup_tip,        m_unwarp_closeup, 0 );
   MENU(mWarp,    "Make Waves", 0,               makewaves_tip,             m_makewaves, 0);
   MENU(mWarp,    "Twist", 0,                    twist_tip,                 m_twist, 0);
   MENU(mWarp,    "Sphere", 0,                   sphere_tip,                m_sphere, 0);
   MENU(mWarp,    "Inside-out", 0,               inside_out_tip,            m_inside_out, 0);
   MENU(mWarp,    "Tiny Planet", 0,              tiny_planet_tip,           m_tiny_planet, 0);
   MENU(mWarp,    "Escher Spiral", 0,            escher_spiral_tip,         m_escher_spiral, 0);
   MENU(mWarp,    "Flatten Photo", 0,            flatphoto_tip,             m_flatphoto, 0 );

   mComb = create_popmenu();
   MENU(mComb,    "HDR", 0,                      HDR_tip,                   m_HDR, 0 );
   MENU(mComb,    "HDF", 0,                      HDF_tip,                   m_HDF, 0 );
   MENU(mComb,    "Stack/Paint", 0,              stack_paint_tip,           m_stack_paint, 0 );
   MENU(mComb,    "Stack/Noise", 0,              stack_noise_tip,           m_stack_noise, 0 );
   MENU(mComb,    "Stack/Layers", 0,             stack_layers_tip,          m_stack_layers, 0 );
   MENU(mComb,    "Stack/Split", 0,              stack_split_tip,           m_stack_split, 0 );
   MENU(mComb,    "Panorama", 0,                 panorama_tip,              m_panorama, 0 );
   MENU(mComb,    "Show CIM Files", 0,           show_cim_files_tip,        m_cim_show_files, 0 );
   MENU(mComb,    "Mashup", 0,                   mashup_tip,                m_mashup, 0 );
   MENU(mComb,    "Image Array", 0,              image_array_tip,           m_image_array, 0 );

   mBatch = create_popmenu();
   MENU(mBatch,   "Batch Convert", 0,            batch_convert_tip,         m_batch_convert, 0 );
   MENU(mBatch,   "Batch Copy/Move", 0,          batch_copy_move_tip,       m_batch_copy_move, 0 );
   MENU(mBatch,   "Batch Upright", 0,            batch_upright_tip,         m_batch_upright, 0 );
   MENU(mBatch,   "Batch Delete/Trash", 0,       batch_deltrash_tip,        m_batch_deltrash, 0 );
   MENU(mBatch,   "Batch RAW", 0,                batch_RAW_tip,             m_batch_RAW, 0 );
   MENU(mBatch,   "Batch Overlay", 0,            batch_overlay_tip,         m_batch_overlay, 0 );
   MENU(mBatch,   "Batch Tags", 0,               batch_tags_tip,            m_batch_tags, 0 );
   MENU(mBatch,   "Batch Rename Tags", 0,        batch_rename_tags_tip,     m_batch_rename_tags, 0 );
   MENU(mBatch,   "Batch Photo Date", 0,         batch_photo_DT_tip,        m_batch_photo_date_time, 0 );
   MENU(mBatch,   "Batch Change Meta", 0,        batch_change_meta_tip,     m_batch_change_meta, 0 );
   MENU(mBatch,   "Batch Report Meta", 0,        batch_report_meta_tip,     m_batch_report_meta, 0 );
   MENU(mBatch,   "Batch Move Meta", 0,          batch_meta_mover_tip,      m_batch_meta_mover, 0 );
   MENU(mBatch,   "Batch Geotags", 0,            batch_geotags_tip,         m_batch_geotags, 0 );
   MENU(mBatch,   "Export File List", 0,         export_filelist_tip,       m_export_filelist, 0 );
   MENU(mBatch,   "Export Files", 0,             export_files_tip,          m_export_files, 0 );

   mTools = create_popmenu();
   MENU(mTools,   "Index Files", 0,              index_tip,                 m_index, 0 );
   MENU(mTools,   "Quick Index", 0,              quick_index_tip,           m_quick_index, 0 );
   MENU(mTools,   "Settings", 0,                 settings_tip,              m_settings, 0 );
   MENU(mTools,   "KB Shortcuts", 0,             KB_shortcuts_tip,          m_KB_shortcuts, 0 );
   MENU(mTools,   "RGB Histogram", 0,            RGB_hist_tip,              m_RGB_hist, 0 );
   MENU(mTools,   "Magnify Image", 0,            magnify_tip,               m_magnify, 0 );
   MENU(mTools,   "Measure Image", 0,            measure_image_tip,         m_measure_image, 0 );
   MENU(mTools,   "Show RGB", 0,                 show_RGB_tip,              m_show_RGB, 0 );
   MENU(mTools,   "Grid Settings", 0,            grid_settings_tip,         m_grid_settings, 0 );
   MENU(mTools,   "Toggle Grid", 0,              toggle_grid_tip,           m_toggle_grid, 0 );
   MENU(mTools,   "Line Color", 0,               line_color_tip,            m_line_color, 0 );
   MENU(mTools,   "Dark/Bright Pixels", 0,       darkbrite_tip,             m_darkbrite, 0 );
   MENU(mTools,   "Monitor Color", 0,            monitor_color_tip,         m_monitor_color, 0 );
   MENU(mTools,   "Find Duplicates", 0,          duplicates_tip,            m_duplicates, 0 );
   MENU(mTools,   "Show Resources", 0,           resources_tip,             m_resources, 0 );

   mHelp = create_popmenu();
   MENU(mHelp,    "User Guide", 0,               user_guide_tip,            m_help, 0 );
   MENU(mHelp,    "Video Tutorial", 0,           video_tutorial_tip,        m_help, 0 );
   MENU(mHelp,    "Outboard Programs", 0,        outboard_programs_tip,     m_help, 0 );
   MENU(mHelp,    "Log File", 0,                 logfile_tip,               m_help, 0 );
   MENU(mHelp,    "Command Params", 0,           command_params_tip,        m_help, 0 );
   MENU(mHelp,    "Change Log", 0,               changelog_tip,             m_help, 0 );
   MENU(mHelp,    "Copyright", 0,                copyright_tip,             m_help, 0 );
   MENU(mHelp,    "Privacy", 0,                  privacy_tip,               m_help, 0 );
   MENU(mHelp,    "About", 0,                    about_tip,                 m_help, 0 );
   MENU(mHelp,    "Home Page", 0,                homepage_tip,              m_help, 0 );
   MENU(mHelp,    "Uninstall", 0,                uninstall_tip,             m_help, 0 );

   //  main menu buttons - must be last

   MENU(0,  "File",         "file.png",          File_tip,            (cbFunc *) popup_menu, (ch *) mFile);
   MENU(0,  "Gallery",      "gallery.png",       Gallery_tip,         (cbFunc *) popup_menu, (ch *) mGallery);
   MENU(0,  "Maps",         "maps.png",          Maps_tip,            (cbFunc *) popup_menu, (ch *) mMaps);
   MENU(0,  "Custom",       "custom.png",        custom_menu_tip,     m_custom_menu, 0 );
   MENU(0,  "Zoom",         "zoom.png",          zoom_menu_tip,       m_zoom_menu, 0 );
   MENU(0,  "Prev/Next",    "prev-next.png",     prev_next_tip,       m_prev_next, 0 );
   MENU(0,  "Save",         "save.png",          save_tip,            m_file_save, 0 );
   MENU(0,  "Metadata",     "metadata.png",      metadata_tip,        (cbFunc *) popup_menu, (ch *) mMeta);
   MENU(0,  "Select",       "select.png",        select_tip,          (cbFunc *) popup_menu, (ch *) mSelect);
   MENU(0,  "Undo/Redo",    "undo-redo.png",     undo_redo_tip,       m_undo_redo, 0 );
   MENU(0,  "Edit",         "edit.png",          edit_tip,            (cbFunc *) popup_menu, (ch *) mEdit);
   MENU(0,  "Repair",       "repair.png",        repair_tip,          (cbFunc *) popup_menu, (ch *) mRepair);
   MENU(0,  "Refine",       "refine.png",        refine_tip,          (cbFunc *) popup_menu, (ch *) mRefine);
   MENU(0,  "Effects",      "effects.png",       effects_tip,         (cbFunc *) popup_menu, (ch *) mEffects);
   MENU(0,  "Warp",         "warp.png",          warp_tip,            (cbFunc *) popup_menu, (ch *) mWarp);
   MENU(0,  "Combine",      "combine.png",       combine_tip,         (cbFunc *) popup_menu, (ch *) mComb);
   MENU(0,  "Batch",        "batch.png",         batch_tip,           (cbFunc *) popup_menu, (ch *) mBatch);
   MENU(0,  "Tools",        "tools.png",         tools_tip,           (cbFunc *) popup_menu, (ch *) mTools);
   MENU(0,  "Help",         "help.png",          help_tip,            (cbFunc *) popup_menu, (ch *) mHelp);

   //  show developer tools menu if required

   if (Fdevmenu)
   {
      mDevmenu = create_popmenu();
      MENU(mDevmenu, "zmalloc report",    0,       "show memory allocations",    m_zmalloc_report,    0);
      MENU(mDevmenu, "zmalloc growth",    0,       "show memory growth by tag",  m_zmalloc_growth,    0);
      MENU(mDevmenu, "mouse events",      0,       "toggle: show mouse events",  m_mouse_events,      0);
      MENU(mDevmenu, "Audit User Guide",  0,       "check all user guide links", m_audit_userguide,   0);
      MENU(mDevmenu, "zappcrash test",    0,       "backtrace dump",             m_zappcrash_test,    0 );
      MENU(mDevmenu, "Edit Template",     0,       "edit function template",     m_template,          0);
      MENU(0,        "Dev-Tools", "devmenu.png",   "developer tools",  (cbFunc *) popup_menu, (ch *) mDevmenu);
   }

   int   Vmenus = Nmenus;                                                        //  visible menus stop here

   //  internal functions not shown in menus

   MENU(mDevmenu, "Copy From Image Slave", 0, "slave process",  m_copy_from_image_slave, 0 );
   MENU(mDevmenu, "Autosearch",            0, "search results > stdout", m_autosearch, 0);
   MENU(mEffects, "dither0",               0, 0,          m_dither0, 0 );
   MENU(mEffects, "dither1",               0, 0,          m_dither1, 0 );
   MENU(mEffects, "dither2",               0, 0,          m_dither2, 0 );
   MENU(mEffects, "dither3",               0, 0,          m_dither3, 0 );
   MENU(mEdit,    "Plugins",               0, 0,          m_plugins, 0);
   MENU(mBatch,   "Edit Script",           0, 0,          m_edit_script, 0 );
   MENU(mBatch,   "Run Script",            0, 0,          m_run_script, 0);
   MENU(mBatch,   "Batch Script",          0, 0,          m_batch_script, 0);

   //  build the menu buttons for the main menu ---------------------------

   float    frgb[3], brgb[3];
   frgb[0] = MFrgb[0] / 256.0;                                                   //  menu font color
   frgb[1] = MFrgb[1] / 256.0;                                                   //  convert range to 0-1
   frgb[2] = MFrgb[2] / 256.0;
   brgb[0] = MBrgb[0] / 256.0;                                                   //  menu background color
   brgb[1] = MBrgb[1] / 256.0;                                                   //  convert range to 0-1
   brgb[2] = MBrgb[2] / 256.0;

   Vmenu *Xvm = Vmenu_new(MWmenu,frgb,brgb);                                     //  create main menu

   int   siz = iconsize;                                                         //  user settings parameter

   for (me = 0; me < Vmenus; me++)
   {
      if (menutab[me].topmenu)                                                   //  submenu within top menu
         add_popmenu_item(menutab[me].topmenu, menutab[me].menu,
                menutab[me].func, menutab[me].arg, menutab[me].desc);

      else                                                                       //  top menu (button)
      {
         if (strmatch(menu_style,"icons")) {                                     //  icons only
            if (menutab[me].icon)
               Vmenu_add(Xvm, 0, menutab[me].icon,siz,siz,menutab[me].desc,
                                 menutab[me].func, menutab[me].arg);
            else                                                                 //  no icon, use menu text
               Vmenu_add(Xvm, menutab[me].menu, 0, 0, 0, menutab[me].desc,
                                 menutab[me].func, menutab[me].arg);
         }

         else if (strmatch(menu_style,"text")) {                                 //  text only
            Vmenu_add(Xvm, menutab[me].menu, 0, 0, 0, menutab[me].desc,
                        menutab[me].func, menutab[me].arg);
         }

         else                                                                    //  icons + menu text
            Vmenu_add(Xvm, menutab[me].menu, menutab[me].icon, siz, siz,
                        menutab[me].desc, menutab[me].func, menutab[me].arg);
      }
   }

   Vmenu_add_setup(Xvm, 0, m_viewmode, "F");                                     //  add setup functions
   Vmenu_add_setup(Xvm, 1, m_viewmode, "G");                                     //    for top 3 menu buttons
   Vmenu_add_setup(Xvm, 2, m_viewmode, "M");                                     //      to set corresp. view mode

   Vmenu_add_RMfunc(Xvm, 0, m_viewmode, "F");                                    //  add right-mouse function
   Vmenu_add_RMfunc(Xvm, 1, m_viewmode, "G");                                    //    for top 3 menu buttons
   Vmenu_add_RMfunc(Xvm, 2, m_viewmode, "M");


   //  build table of eligible menus for KB shortcut assignment -----------------

   #define KBshort(_menu, _func, _arg)                               \
      me = Nkbsf++;                                                  \
      if (me >= maxkbsf) zappcrash("maxkbs exceeded");               \
      kbsftab[me].menu = _menu;                                      \
      kbsftab[me].func = _func;                                      \
      kbsftab[me].arg = _arg;

   Nkbsf = 0;

   //       menu                    called function           arg
   KBshort("Adjust HSL",            m_adjust_HSL,              0     );
   KBshort("Adjust RGB",            m_adjust_RGB,              0     );
   KBshort("Amplify Contrast",      m_amplifycon,              0     );
   KBshort("Blur",                  m_blur,                    0     );
   KBshort("Bookmarks",             m_bookmarks,               0     );
   KBshort("Choose Captions",       m_meta_choose_caps,        0     );
   KBshort("Color Mode",            m_color_mode,              0     );
   KBshort("Copy/Move",             m_copy_move,               0     );
   KBshort("Copy to Clipboard",     m_copyto_clip,             0     );
   KBshort("Copy to Desktop",       m_copyto_desktop,          0     );
   KBshort("Crop",                  m_crop,                    0     );
   KBshort("Current Album",         m_current_album,           0     );
   KBshort("Current Folder",        m_current_folder,          0     );
   KBshort("Cycle 2 Files",         m_cycle2files,             0     );
   KBshort("Cycle 3 Files",         m_cycle3files,             0     );
   KBshort("Delete Meta",           m_meta_delete,             0     );
   KBshort("Delete/Trash",          m_delete_trash,            0     );
   KBshort("Denoise",               m_denoise,                 0     );
   KBshort("Dither",                m_dither,                  0     );
   KBshort("Edit Any Meta",         m_meta_edit_any,           0     );
   KBshort("Edit Histogram",        m_edit_hist,               0     );
   KBshort("Edit Main Meta",        m_meta_edit_main,          0     );
   KBshort("File View",             m_viewmode,               "F"    );
   KBshort("Flatten Histogram",     m_flat_hist,               0     );
   KBshort("Folder Tree",           m_folder_tree,             0     );
   KBshort("Gallery View",          m_viewmode,               "G"    );
   KBshort("Global Retinex",        m_gretinex,                0     );
   KBshort("Grid Settings",         m_grid_settings,           0     );
   KBshort("KB Shortcuts",          m_KB_shortcuts,            0     );
   KBshort("Recent Folders",        m_recent_folders,          0     );
   KBshort("Line Color",            m_line_color,              0     );
   KBshort("Local Retinex",         m_lretinex,                0     );
   KBshort("Magnify Image",         m_magnify,                 0     );
   KBshort("Manage Albums",         m_manage_albums,           0     );
   KBshort("Map View",              m_viewmode,               "M"    );
   KBshort("Markup",                m_markup,                  0     );
   KBshort("Meta View",             m_metaview,                0     );
   KBshort("Newest",                m_newfiles,                0     );
   KBshort("New Session",           m_new_session,             0     );
   KBshort("New Version",           m_file_save_version,       0     );
   KBshort("Open Image File",       m_open_file,               0     );
   KBshort("Permissions",           m_permissions,             0     );
   KBshort("Places/Dates",          m_meta_places_dates,       0     );
   KBshort("Print Calibrated",      m_print_calibrated,        0     );
   KBshort("Print Image",           m_print_image,             0     );
   KBshort("Quit",                  m_quit,                    0     );
   KBshort("Recent",                m_recentfiles,             0     );
   KBshort("Red Eyes",              m_redeyes ,                0     );
   KBshort("Redo",                  m_redo,                    0     );
   KBshort("Rename",                m_rename,                  0     );
   KBshort("Replace",               m_file_save_replace,       0     );
   KBshort("Rescale",               m_rescale,                 0     );
   KBshort("Retouch",               m_retouch,                 0     );
   KBshort("RGB Histogram",         m_RGB_hist,                0     );
   KBshort("Rotate",                m_rotate,                  0     );
   KBshort("Save",                  m_file_save,               0     );
   KBshort("Search",                m_search_images,           0     );
   KBshort("Select Area",           m_select_area,             0     );
   KBshort("Select Files",          m_select_files,            0     );
   KBshort("Set Colors",            m_set_colors,              0     );
   KBshort("Settings",              m_settings,                0     );
   KBshort("Sharpen",               m_sharpen,                 0     );
   KBshort("Show Hidden",           m_show_hidden,             0     );
   KBshort("Show on Map",           m_map_zoomin,              0     );
   KBshort("Show Resources",        m_resources,               0     );
   KBshort("Timeline",              m_meta_timeline,           0     );
   KBshort("Toggle Captions",       m_meta_toggle_caps,        0     );
   KBshort("Toggle Grid",           m_toggle_grid,             0     );
   KBshort("Undo",                  m_undo,                    0     );
   KBshort("Upright",               m_upright,                 0     );
   KBshort("View 360° Pano",        m_view360,                 0     );
   KBshort("View Main Meta",        m_meta_view_short,         0     );
   KBshort("zmalloc by tag",        m_zmalloc_report,          0     );
   KBshort("zmalloc growth",        m_zmalloc_growth,          0     );
   KBshort("Zoom-in",               m_zoom,                   "in"   );
   KBshort("Zoom-out",              m_zoom,                   "out"  );
   //  zdialog completion buttons that can have KB shortcuts assigned
   KBshort("Apply",                 0,                         0     );
   KBshort("Cancel",                0,                         0     );
   KBshort("OK",                    0,                         0     );
   KBshort("Reset",                 0,                         0     );

   //  build right-click popup menus --------------------------------------------

   ch    *menumeta1 = "View Main Meta";
   ch    *menumeta1A = "View All Meta";
   ch    *menumeta2 = "Edit Main Meta";
   ch    *menurename = "Rename";
   ch    *menudeltrash = "Delete/Trash";
   ch    *menucopymove = "Copy/Move";
   ch    *menucopytodesktop = "Copy to Desktop";
   ch    *menucopytoclip = "Copy to Clipboard";
   ch    *menurotateimage = "Rotate";
   ch    *menucropimage = "Crop";
   ch    *menuretouch = "Retouch";
   ch    *menurescale = "Rescale";
   ch    *menusharpen = "Sharpen";
   ch    *menublur = "Blur";
   ch    *menudenoise = "Denoise";
   ch    *menuedithist = "Edit Histogram";
   ch    *menuflattenhist = "Flatten Histogram";
   ch    *menulocalcon = "Local Contrast";
   ch    *menuamplifycon = "Amplify Contrast";
   ch    *menusaturation = "Saturation";
   ch    *menushowonmap = "Show on Map";                                         //  24.60
   ch    *menuaddtoselection = "Add to Selection";                               //  24.20
   ch    *menuthumbframe = "Thumbnail Frame";
   ch    *menupopimage = "Popup Image";
   ch    *menualbumaddselfiles = "Add Selected Files Here";
   ch    *menualbumaddcurrfile = "Add Current File Here";
   ch    *menuremovefromalbum = "Remove from Album";

   popmenu_image = create_popmenu();                                             //  popup menu for image files
   add_popmenu_item(popmenu_image,menumeta1,popup_menufunc,"view main meta");
   add_popmenu_item(popmenu_image,menumeta1A,popup_menufunc,"view all meta");
   add_popmenu_item(popmenu_image,menumeta2,popup_menufunc,"edit main meta");
   add_popmenu_item(popmenu_image,menurename,popup_menufunc,"rename");
   add_popmenu_item(popmenu_image,menudeltrash,popup_menufunc,"delete/trash");
   add_popmenu_item(popmenu_image,menucopymove,popup_menufunc,"copymove");
   add_popmenu_item(popmenu_image,menucopytodesktop,popup_menufunc,"copytodesktop");
   add_popmenu_item(popmenu_image,menucopytoclip,popup_menufunc,"copytoclip");
   add_popmenu_item(popmenu_image,menurotateimage,popup_menufunc,"rotate");
   add_popmenu_item(popmenu_image,menucropimage,popup_menufunc,"crop");
   add_popmenu_item(popmenu_image,menuretouch,popup_menufunc,"retouch");
   add_popmenu_item(popmenu_image,menurescale,popup_menufunc,"rescale");
   add_popmenu_item(popmenu_image,menusharpen,popup_menufunc,"sharpen");
   add_popmenu_item(popmenu_image,menublur,popup_menufunc,"blur");
   add_popmenu_item(popmenu_image,menudenoise,popup_menufunc,"denoise");
   add_popmenu_item(popmenu_image,menuedithist,popup_menufunc,"edit hist");
   add_popmenu_item(popmenu_image,menuflattenhist,popup_menufunc,"flatten hist");
   add_popmenu_item(popmenu_image,menulocalcon,popup_menufunc,"local contrast");
   add_popmenu_item(popmenu_image,menuamplifycon,popup_menufunc,"amplify contrast");
   add_popmenu_item(popmenu_image,menusaturation,popup_menufunc,"saturation");
   add_popmenu_item(popmenu_image,menushowonmap,popup_menufunc,"show on map");
   add_popmenu_item(popmenu_image,menuaddtoselection,popup_menufunc,"add to selection");                               //  24.20

   popmenu_raw = create_popmenu();                                               //  popup menu for RAW files
   add_popmenu_item(popmenu_raw,menumeta1,popup_menufunc,"view main meta");
   add_popmenu_item(popmenu_raw,menumeta1A,popup_menufunc,"view all meta");
   add_popmenu_item(popmenu_raw,menumeta2,popup_menufunc,"edit main meta");
   add_popmenu_item(popmenu_raw,menurename,popup_menufunc,"rename");
   add_popmenu_item(popmenu_raw,menudeltrash,popup_menufunc,"delete/trash");
   add_popmenu_item(popmenu_raw,menucopymove,popup_menufunc,"copymove");

   popmenu_video = create_popmenu();                                             //  popup menu for VIDEO files
   add_popmenu_item(popmenu_video,menumeta1,popup_menufunc,"view main meta");
   add_popmenu_item(popmenu_video,menumeta1A,popup_menufunc,"view all meta");
   add_popmenu_item(popmenu_video,menumeta2,popup_menufunc,"edit main meta");
   add_popmenu_item(popmenu_video,menurename,popup_menufunc,"rename");
   add_popmenu_item(popmenu_video,menudeltrash,popup_menufunc,"delete/trash");
   add_popmenu_item(popmenu_video,menucopymove,popup_menufunc,"copymove");
   add_popmenu_item(popmenu_video,menucopytodesktop,popup_menufunc,"copytodesktop");
   add_popmenu_item(popmenu_video,menuthumbframe,popup_menufunc,"thumbnail_frame");

   popmenu_thumb = create_popmenu();                                             //  gallery thumbnail popup menu
   add_popmenu_item(popmenu_thumb,menupopimage,popup_menufunc,"popimage");
   add_popmenu_item(popmenu_thumb,menumeta1,popup_menufunc,"view main meta");
   add_popmenu_item(popmenu_thumb,menumeta1A,popup_menufunc,"view all meta");
   add_popmenu_item(popmenu_thumb,menumeta2,popup_menufunc,"edit main meta");
   add_popmenu_item(popmenu_thumb,menurename,popup_menufunc,"rename");
   add_popmenu_item(popmenu_thumb,menudeltrash,popup_menufunc,"delete/trash");
   add_popmenu_item(popmenu_thumb,menucopymove,popup_menufunc,"copymove");
   add_popmenu_item(popmenu_thumb,menucopytodesktop,popup_menufunc,"copytodesktop");
   add_popmenu_item(popmenu_thumb,menucopytoclip,popup_menufunc,"copytoclip");

   popmenu_album = create_popmenu();                                             //  album thumbnail popup menu
   add_popmenu_item(popmenu_album,menupopimage,popup_menufunc,"popimage");
   add_popmenu_item(popmenu_album,menumeta1,popup_menufunc,"view main meta");
   add_popmenu_item(popmenu_album,menumeta1A,popup_menufunc,"view all meta");
   add_popmenu_item(popmenu_album,menumeta2,popup_menufunc,"edit main meta");
   add_popmenu_item(popmenu_album,menucopytodesktop,popup_menufunc,"copytodesktop");
   add_popmenu_item(popmenu_album,menucopytoclip,popup_menufunc,"copytoclip");
   add_popmenu_item(popmenu_album,menualbumaddselfiles,popup_menufunc,"albumaddselfiles");
   add_popmenu_item(popmenu_album,menualbumaddcurrfile,popup_menufunc,"albumaddcurrfile");
   add_popmenu_item(popmenu_album,menuremovefromalbum,popup_menufunc,"removefromalbum");

   return;
}


//  right-click popup menu response function

void popup_menufunc(GtkWidget *, ch *menu)
{
   if (strmatch(menu,"view main meta")) meta_view(1);
   if (strmatch(menu,"view all meta")) meta_view(2);
   if (strmatch(menu,"edit main meta")) m_meta_edit_main(0,0);
   if (strmatch(menu,"rename")) m_rename(0,0);
   if (strmatch(menu,"delete/trash")) m_delete_trash(0,0);
   if (strmatch(menu,"copymove")) m_copy_move(0,0);
   if (strmatch(menu,"copytodesktop")) m_copyto_desktop(0,0);
   if (strmatch(menu,"copytoclip")) m_copyto_clip(0,0);
   if (strmatch(menu,"rotate")) m_rotate(0,0);
   if (strmatch(menu,"crop")) m_crop(0,0);
   if (strmatch(menu,"retouch")) m_retouch(0,0);
   if (strmatch(menu,"rescale")) m_rescale(0,0);
   if (strmatch(menu,"sharpen")) m_sharpen(0,0);
   if (strmatch(menu,"blur")) m_blur(0,0);
   if (strmatch(menu,"denoise")) m_denoise(0,0);
   if (strmatch(menu,"edit hist")) m_edit_hist(0,0);
   if (strmatch(menu,"flatten hist")) m_flat_hist(0,0);
   if (strmatch(menu,"local contrast")) m_localcon(0,0);
   if (strmatch(menu,"amplify contrast")) m_amplifycon(0,0);
   if (strmatch(menu,"saturation")) m_saturation(0,0);
   if (strmatch(menu,"show on map")) m_map_zoomin(0,0);
   if (strmatch(menu,"add to selection")) add_file_to_selection(curr_file);      //  24.20
   if (strmatch(menu,"thumbnail_frame")) m_thumbframe(0,0);
   if (strmatch(menu,"popimage")) gallery_popimage();
   if (strmatch(menu,"albumaddselfiles")) album_add_selfiles(2);
   if (strmatch(menu,"albumaddcurrfile")) album_add_currfile(2);
   if (strmatch(menu,"removefromalbum")) album_remove_file(clicked_posn);

   return;
}


//  main window mouse right-click popup menu

void image_Rclick_popup()
{
   int      ftype;

   if (! curr_file) return;

   ftype = image_file_type(curr_file);
   if (ftype == IMAGE) popup_menu(Mwin,popmenu_image);
   if (ftype == RAW) popup_menu(Mwin,popmenu_raw);
   if (ftype == VIDEO) popup_menu(Mwin,popmenu_video);
   return;
}


//  gallery thumbnail mouse left-click function
//  open the clicked file in view mode F

void gallery_Lclick_func(int Nth)
{
   ch       *file;
   int      err = 0;

   if (clicked_file) {                                                           //  free memory of clicked thumbnail
      zfree(clicked_file);
      clicked_file = 0;
   }

   file = gallery(0,"get",Nth);
   if (! file) return;

   err = f_open(file,Nth,0,1);                                                   //  clicked file >> current file
   if (! err) viewmode('F');
   zfree(file);
   return;
}


//  gallery thumbnail mouse right-click popup menu

void gallery_Rclick_popup(int Nth)
{
   FTYPE    ftype;

   clicked_posn = Nth;                                                           //  clicked gallery position (0 base)
   clicked_file = gallery(0,"get",Nth);                                          //  clicked_file is subject for zfree()
   if (! clicked_file) return;

   if (navi::gallerytype == ALBUM) {
      popup_menu(Mwin,popmenu_album);
      return;
   }

   ftype = image_file_type(clicked_file);
   if (ftype == IMAGE) popup_menu(Mwin,popmenu_thumb);
   if (ftype == RAW) popup_menu(Mwin,popmenu_raw);
   if (ftype == VIDEO) popup_menu(Mwin,popmenu_video);

   return;
}


/********************************************************************************/

//  set window view mode, F/G/M

void m_viewmode(GtkWidget *, ch *fgm)                                            //  menu function
{
   viewmode(fgm[0]);
   return;
}


void viewmode(ch fgm)                                                            //  callable
{
   ch     wintitle[100];

   Plog(1,"m_viewmode %c \n",fgm);

   if (! fgm) fgm = '0';                                                         //  null -> '0'

   if (fgm == FGM) {                                                             //  no view mode change
      zfuncs::vmenustop = 0;                                                     //  continue menu func
      return;
   }

   zfuncs::vmenustop = 1;                                                        //  view mode change, stop menu func

   if (fgm == '0')                                                               //  set no view mode (blank window)
   {
      gtk_widget_hide(Fhbox);
      gtk_widget_hide(Ghbox);
      gtk_widget_hide(Mhbox);
      FGM = '0';
      PFGM = '0';                                                                //  remember last F/G view

      Cstate = 0;                                                                //  no image drawing area
      Cdrawin = 0;
      gdkwin = 0;

      if (zd_deltrash) m_delete_trash(0,0);                                      //  set target file in active dialog
      if (zd_copymove) m_copy_move(0,0);
      if (zd_metaview) meta_view(0);
      if (zd_rename) m_rename(0,0);
      if (zd_permissions) m_permissions(0,0);
   }

   if (fgm == 'F')                                                               //  set F view mode for image file
   {      
      gtk_widget_hide(Ghbox);
      gtk_widget_hide(Mhbox);
      gtk_widget_show_all(Fhbox);
      if (! Fpanelshow) gtk_widget_hide(Fpanel);                                 //  no panel

      Cstate = &Fstate;                                                          //  set drawing area
      Cdrawin = Fdrawin;
      gdkwin = gtk_widget_get_window(Fdrawin);                                   //  GDK window

/***
      gdk_window_hide(gdkwin);                                                   //  *** gdk bug workaround *** remove     24.40
      zmainsleep(0.001);
      gdk_window_show_unraised(gdkwin);                                          //  sometimes fails to paint  U22.04
***/

      FGM = 'F';
      PFGM = 'F';                                                                //  remember last F/G view

      set_mwin_title();

      if (zd_deltrash) m_delete_trash(0,0);                                      //  set target file in active dialog
      if (zd_copymove) m_copy_move(0,0);
      if (zd_metaview) meta_view(0);
      if (zd_rename) m_rename(0,0);
      if (zd_permissions) m_permissions(0,0);
   }

   if (fgm == 'G')                                                               //  set G view mode for thumbnail gallery
   {
      gtk_widget_hide(Fhbox);
      gtk_widget_hide(Mhbox);
      gtk_widget_show_all(Ghbox);
      FGM = 'G';
      PFGM = 'G';                                                                //  remember last F/G view

      Cstate = 0;                                                                //  no image drawing area
      Cdrawin = 0;
      gdkwin = 0;

      if (curr_file) gallery(curr_file,"paint",0);                               //  set gallery posn. at curr. file
      else gallery(0,"paint",-1);                                                //  else leave unchanged
   }

   if (fgm == 'M')                                                               //  set M view mode for maps
   {
      if (Findexvalid == 0) {
         zmessageACK(Mwin,"image index disabled");                               //  no image index
         return;
      }

      if (CEF) return;                                                           //  don't interrupt edit func.

      gtk_widget_hide(Fhbox);
      gtk_widget_hide(Ghbox);
      gtk_widget_show_all(Mhbox);
      FGM = 'M';

      Cstate = 0;                                                                //  no image drawing area
      Cdrawin = 0;
      gdkwin = 0;

      m_worldmap(0,"init");                                                      //  load initial map
      snprintf(wintitle,100,"%s   Image Locations",Frelease);
      gtk_window_set_title(MWIN,wintitle);                                       //  window title
   }

   return;
}


/********************************************************************************/

//  generate custom user menu from custom menu file
//  menu entry options:
//     # comment or heading                  comment or heading for a group of menunames
//     menuname   # tooltip                  start a fotocx menu function
//     album  albumname                      open an album
//     file  filename                        open an image file


namespace custom_menu_names
{
   ch    **menulist = 0;
   int   Nm = 0;
}


//  menu function

void m_custom_menu(GtkWidget *, ch *)                                            //  24.20
{
   using namespace custom_menu_names;

   void custom_menu_process(GtkWidget *, ch *);
   void custom_menu_edit(GtkWidget *, ch *);

   GtkWidget   *popmenu;
   ch          *menu, *text, *pp;
   int         ii, nn;

   F1_help_topic = "custom menu";

   Plog(1,"m_custom_menu \n");

   if (menulist) zreadfile_free(menulist);                                       //  clear prior
   Nm = zreadfile(custom_menu_file,menulist);                                    //  (may be empty)

   popmenu = create_popmenu();                                                   //  create popup menu

   for (ii = 0; ii < Nm; ii++)                                                   //  parse:  menuname # text
   {
      menu = text = 0;

      pp = strchr(menulist[ii],'#');                                             //  get text alone after '#'
      if (pp) {
         *pp = 0;
         text = pp + 1;
         nn = strTrim2(text);                                                    //  remove blanks
         if (! nn) text = 0;
      }
      
      nn = strTrim2(menulist[ii]);                                               //  get menuname before '#'
      if (nn) menu = menulist[ii];                                               //  have menuname # text (tool tip) 
      else {
         *pp = '#';                                                              //  no menuname, restore '#'
         menu = pp;                                                              //  have only # text 
         text = 0;
      }  
      
      if (strmatchN(menu,"album",5)) text = "view album";

      add_popmenu_item(popmenu,menu,custom_menu_process,0,text);
   }

   add_popmenu_item(popmenu,"Edit Menu",custom_menu_edit,0,"edit this menu");    //  add menu edit function at end

   popup_menu(Mwin,popmenu);                                                     //  show popup menu

   return;
}


//  process custom menu entry:

void custom_menu_process(GtkWidget *, ch *text)                                  //  24.20
{
   using namespace custom_menu_names;

   ch       text2[300], albumfile[300];
   int      ii;

   Plog(1,"custom menu: %s \n",text);
   
   if (*text == '#') return;                                                     //  text = # comment - do nothing

   if (strchr(text,'~')) 
      repl_1str(text,text2,300,"~",getenv("HOME"));                              //  replace embedded "~" or "$HOME"
   else if (strstr(text,"$HOME"))                                                //    with "/home/<user>"
      repl_1str(text,text2,300,"$HOME",getenv("HOME"));
   else strncpy0(text2,text,300);
   
   if (strmatchcaseN(text2,"album",5))                                           //  text = album albumname
   {
      strTrim2(text2+5);
      snprintf(albumfile,300,"%s/%s",albums_folder,text2+5);                     //  add albums folder before name
      album_show(albumfile);                                                     //  show the album
      return;
   }
   
   if (strmatchcaseN(text2,"file",4))                                            //  text = file filename
   {
      strTrim2(text2+4);
      f_open(text2+4);                                                           //  show the file (image) 
      viewmode('F');
      return;
   }

   for (ii = 0; ii < Nmenus; ii++)                                               //  text = fotocx menu name
   {                                                                             //  find menu name in menu table
      if (! menutab[ii].menu) continue;                                          //  separator, null menu
      if (strmatchcase(text,menutab[ii].menu)) break;
   }

   if (ii < Nmenus) menutab[ii].func(0,0);                                       //  found, call menu function
   else zmessageACK(Mwin,text);                                                  //  menu not found, display it

   return;
}


void custom_menu_edit(GtkWidget *, ch *)                                         //  edit the custom menu file
{
   zdialog_edit_textfile(Mwin,custom_menu_file);                                 //  edit new menu                         24.30
   return;
}


/********************************************************************************

    Build a script file with one or more predefined edit functions
     that can be executed like a single edit function.

    fotocx.h:  ch       scriptfile[200];               //  current script file
               FILE     *script_fid;                   //  script file FID
               int      Fscriptbuild;                  //  flag, script build in progress

***/


//  menu function

void m_edit_script(GtkWidget *, ch *menu)
{
   int  edit_script_dialog_event(zdialog *zd, ch *event);

   zdialog  *zd;

   F1_help_topic = "script files";

   Plog(1,"m_edit_script \n");

/***
       _________________________________________
      |         Script Files                    |
      |                                         |
      |  [start]  begin making a script file    |
      |  [close]  finish making a script file   |
      |                                         |
      |                                     [X] |
      |_________________________________________|

***/

   zd = zdialog_new("Script Files",Mwin," X ",null);

   zdialog_add_widget(zd,"hbox","hb1","dialog");
   zdialog_add_widget(zd,"button","start","hb1","Start","space=5");
   zdialog_add_widget(zd,"label","labstart","hb1","begin making a script file");
   zdialog_add_widget(zd,"hbox","hb2","dialog");
   zdialog_add_widget(zd,"button","close","hb2","Close","space=5");
   zdialog_add_widget(zd,"label","labclose","hb2","finish making a script file");

   zdialog_run(zd,edit_script_dialog_event,"parent");
   return;
}


//  dialog event and completion function

int edit_script_dialog_event(zdialog *zd, ch *event)
{
   int  edit_script_start(void);
   int  edit_script_close(void);

   if (zd->zstat) {                                                              //  canceled
      zdialog_free(zd);
      if (script_fid) fclose(script_fid);
      script_fid = 0;
      Fscriptbuild = 0;
      return 1;
   }

   if (strmatch(event,"start"))                                                  //  start building script
      edit_script_start();

   if (strmatch(event,"close")) {                                                //  script if finished
      edit_script_close();
      zdialog_free(zd);
   }

   return 1;
}


//  start building a script file
//  if Fscriptbuild is active, edit_done() saves edit settings in script file

int edit_script_start()
{
   ch       *pp;

   if (Fscriptbuild) {
      zmessageACK(Mwin,"script already started");
      return 0;
   }

   pp = zgetfile("start a new script file",MWIN,"save",scripts_folder,1);
   if (! pp) return 0;

   strncpy0(scriptfile,pp,200);                                                  //  script file name from user
   zfree(pp);

   pp = strrchr(scriptfile,'/');                                                 //  script name = file base name
   if (! pp || strlen(pp) > 99) {
      zmessageACK(Mwin,"script file name too big");
      return 0;
   }

   script_fid = fopen(scriptfile,"w");                                           //  open script file
   if (! script_fid) {
      zmessageACK(Mwin,strerror(errno));
      return 0;
   }

   fprintf(script_fid,"script name: %s\n",pp+1);                                 //  write header record
   Fscriptbuild = 1;

   zmessageACK(Mwin,"perform edits to be included in the script file");
   return 1;
}


//  this function is called from edit_done() when Fscriptbuild is active
//  save all widget settings in the script file data

void edit_script_addfunc(editfunc *CEF)
{
   int      err;

   fprintf(script_fid,"menu: %s\n",CEF->menuname);                               //  write "menu: menu name"

   if (CEF->zd) {
      err = zdialog_save_widgets(CEF->zd,CEF->sd,CEF->menuname,script_fid);      //  write widget settings
      if (err) {
         zmessageACK(Mwin,"script file error");
         return;
      }
   }

   zmessageACK(Mwin,"%s added to script",CEF->menuname);
   return;
}


//  complete and save a script file under construction

int edit_script_close()
{
   if (! Fscriptbuild) {
      zmessageACK(Mwin,"no script file was started");
      return 0;
   }

   fprintf(script_fid,"menu: end");
   fclose(script_fid);
   script_fid = 0;
   Fscriptbuild = 0;
   zmessageACK(Mwin,"script file closed");
   return 1;
}


//  present a popup menu for user to select a script file
//  run the given function using the selected script file
//  called by  m_run_script()  and  m_batch_script()
//
//  'runfunc' arg: void runfunc(GtkWidget *, ch *scriptname);

void select_script(cbFunc *runfunc)
{
   static ch         **scriptnames = 0;
   static GtkWidget  *scriptmenu = 0;
   static int        ns = 0;

   ch          buff[200], *pp;
   int         ii, kk;
   FILE        *fid;

   if (scriptnames)
   {
      for (ii = 0; ii < ns; ii++)                                                //  free prior memory
         zfree(scriptnames[ii]);
      zfree(scriptnames);
      scriptnames = 0;
   }

   if (scriptmenu) gtk_widget_destroy(scriptmenu);
   scriptmenu = 0;

   ns = zreaddir(scripts_folder,scriptnames);                                    //  get all script names
   if (ns < 1) {                                                                 //    from script file folder
      zmessageACK(Mwin,"no script files found");
      return;
   }

   scriptmenu = create_popmenu();                                                //  create popup menu for script names
   add_popmenu_item(scriptmenu,"Cancel",0,0,0);

   for (ii = kk = 0; ii < ns; ii++)
   {
      snprintf(scriptfile,200,"%s/%s",scripts_folder,scriptnames[ii]);           //  read script file 1st record
      fid = fopen(scriptfile,"r");
      if (! fid) continue;
      pp = fgets_trim(buff,200,fid,1);                                           //  read "script name: scriptname"
      if (pp && strmatch(pp+13,scriptnames[ii])) {                               //    must match file name
         add_popmenu_item(scriptmenu,scriptnames[ii],runfunc,0,0);               //  add to popup menu
         kk++;
      }
      fclose(fid);
   }

   if (kk) popup_menu(0,scriptmenu);                                             //  present menu to select and run
   else zmessageACK(Mwin,"no script files found");

   return;
}


//  execute a script file using the current image file

void run_script(GtkWidget *, ch *scriptname)
{
   ch       buff[200];
   ch       *pp, menuname[40];
   int      ii, err;

   if (! curr_file) {
      zmessageACK(Mwin,"no current file");
      return;
   }

   if (script_fid) Plog(0,"*** run_script(): script_fid not 0 \n");

   Funcbusy(+1);                                                                 //  enable user kill

   snprintf(scriptfile,200,"%s/%s",scripts_folder,scriptname);                   //  script file from script name

   Plog(1,"start script: %s \n",scriptfile);
   script_fid = fopen(scriptfile,"r");                                           //  open script file
   if (! script_fid) {
      zmessageACK(Mwin,"script error: %s \n %s",scriptfile,strerror(errno));
      goto badfile;
   }

   pp = fgets_trim(buff,200,script_fid,1);                                       //  read "script name: scriptname"
   if (! pp) goto badfile;
   if (! strmatch(pp+13,scriptname)) goto badfile;                               //  must match script name

   while (true)                                                                  //  process script file
   {
      if (Fescape) break;                                                        //  user kill

      Fscriptrun = 1;                                                            //  script file active

      pp = fgets_trim(buff,200,script_fid,1);                                    //  read "menu: menuname"
      if (! pp) goto badfile;
      if (! strmatchN(pp,"menu: ",6)) goto badfile;
      strncpy0(menuname,pp+6,40);
      if (strmatch(menuname,"end")) break;                                       //  end of script

      for (ii = 0; menutab[ii].menu; ii++)                                       //  convert menu name to menu function
         if (strmatch(menuname,menutab[ii].menu)) break;

      if (! menutab[ii].menu) {
         zmessageACK(Mwin,"unknown edit function: %s",menuname);
         goto badfile;
      }

      Plog(1,"start edit: %s for file: %s \n",menuname,curr_file);

      menutab[ii].func(0,menutab[ii].arg);                                       //  call the menu function
      zmainsleep(0.1);

      if (CEF && CEF->zd) {
         err = zdialog_load_widgets(CEF->zd,CEF->sd,CEF->menuname,script_fid);   //  read and load dialog settings
         if (err) {
            zmessageACK(Mwin,"load widgets failed: %s",menuname);
            goto badfile;
         }
         zdialog_send_event(CEF->zd,"apply");                                    //  finish edit
         if (CEF && CEF->threadfunc) thread_wait();                              //  insure complete
         if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"done");
         Plog(1,"finish edit \n");
      }
   }

   fclose(script_fid);                                                           //  close script file
   script_fid = 0;
   Fscriptrun = 0;                                                               //  script file not active
   Fescape = 0;
   Funcbusy(-1);
   return;

badfile:
   zmessageACK(Mwin,"script file format error: %s",scriptname);
   if (script_fid) fclose(script_fid);
   script_fid = 0;
   Fscriptrun = 0;
   Fescape = 0;
   Funcbusy(-1);
   return;
}


//  execute a script file using pre-selected image files

void batch_script(GtkWidget *, ch *scriptname)
{
   ch       *imagefile;
   ch       *newfilevers;
   int      ii, err;

   if (! SFcount) {                                                              //  preselected file list
      zmessageACK(Mwin,"no files selected");
      return;
   }

   Funcbusy(+1);                                                                 //  enable user kill

   for (ii = 0; ii < SFcount; ii++)                                              //  loop image files to process
   {
      if (Fescape) break;

      imagefile = SelFiles[ii];
      err = f_open(imagefile);                                                   //  open, current image file
      if (err) {
         zmessageACK(Mwin,"open failure: %s \n %s",imagefile,strerror(errno));
         break;
      }

      run_script(0,scriptname);                                                  //  run script for image file

      newfilevers = file_new_version(curr_file);                                 //  get next avail. file version name
      if (! newfilevers) break;

      if (strmatch(curr_file_type,"RAW")) {                                      //  if RAW, substitute tif-16
         strcpy(curr_file_type,"tif");
         curr_file_bpc = 16;
      }
      err = f_save(newfilevers,curr_file_type,curr_file_bpc,0,1);                //  save file
      zfree(newfilevers);
   }

   Fescape = 0;
   Funcbusy(-1);

   zmessage_post(Mwin,"20/20",3,"script complete");
   return;
}


//  menu function
//  select and run a script file using the current image file

void m_run_script(GtkWidget *, ch *menu)
{
   F1_help_topic = "script files";
   Plog(1,"m_run_script \n");
   select_script(run_script);
   return;
}


//  menu function
//  select and run a script file using multiple selected files

void m_batch_script(GtkWidget *, ch *menu)
{
   int  batch_script_dialog_event(zdialog *zd, ch *event);

   zdialog  *zd;
   ch       text[100];

   F1_help_topic = "script files";

   Plog(1,"m_batch_script \n");

/***
       _________________________________________
      |         Batch Script                    |
      |                                         |
      |  [Select Files]  NN files selected      |
      |  [Select Script]  script file to run    |
      |                                         |
      |                                     [X] |
      |_________________________________________|

***/

   zd = zdialog_new("Batch Script",Mwin," X ",null);

   zdialog_add_widget(zd,"hbox","hb1","dialog");
   zdialog_add_widget(zd,"button","select-files","hb1","Select Files","space=5");
   zdialog_add_widget(zd,"label","fcount","hb1","no files selected");

   zdialog_add_widget(zd,"hbox","hb2","dialog");
   zdialog_add_widget(zd,"button","select-script","hb2","Select Script","space=5");
   zdialog_add_widget(zd,"label","labscript","hb2","script file to run");

   snprintf(text,100,"%d image files selected",SFcount);                         //  show selected files count
   zdialog_stuff(zd,"fcount",text);

   zdialog_run(zd,batch_script_dialog_event,"parent");
   return;
}


//  dialog event and completion function

int batch_script_dialog_event(zdialog *zd, ch *event)
{
   ch       countmess[80];

   F1_help_topic = "script files";

   if (zd->zstat) {                                                              //  canceled
      zdialog_free(zd);
      return 1;
   }

   if (strmatch(event,"select-files"))
   {
      select_files(0,1);                                                         //  get new file list                     24.20

      if (SFcount) {
         snprintf(countmess,80,"%d image files selected",SFcount);               //  update dialog file count
         zdialog_stuff(zd,"fcount",countmess);
      }
      else zdialog_stuff(zd,"fcount","no files selected");
   }

   if (strmatch(event,"select-script")) {                                        //  select and run a script file
      if (! SFcount) zmessageACK(Mwin,"no files selected");
      else {
         select_script(batch_script);
         zdialog_free(zd);
      }
   }

   return 1;
}


/********************************************************************************/

//  Plugin menu functions

namespace plugins_names
{
   int         Nplugins;                                                         //  plugin menu items
   ch          **plugins = 0;
   GtkWidget   *popup_plugmenu = 0;
}


//  choose and run a plugin function or edit the plugins menu

void m_plugins(GtkWidget *, ch *)
{
   using namespace plugins_names;

   void  m_edit_plugins(GtkWidget *, ch *);
   void  m_run_plugin(GtkWidget *, ch *);

   ch          *pp, *tt;
   FILE        *fid;
   int         ii;

   F1_help_topic = "plugins";

   Plog(1,"m_plugins \n");

   if (! regfile(plugins_file)) {
      fid = fopen(plugins_file,"w");                                             //  not found, create default             24.30
      fprintf(fid,"Gimp = gimp %%s # edit current image using Gimp \n");
      fprintf(fid,"auto-gamma = mogrify -auto-gamma %%s # apply auto gamma curve \n");
      fclose(fid);
   }

   if (plugins) zreadfile_free(plugins);                                         //  read plugins file each time
   Nplugins = zreadfile(plugins_file,plugins);
   if (Nplugins < 1) return;

   popup_plugmenu = create_popmenu();                                            //  create popup menu for plugins

   for (ii = 0; ii < Nplugins; ii++)                                             //  add the plugin menu functions
   {
      pp = strstr(plugins[ii]," = ");                                            //  get plugin record:
      if (! pp) {                                                                //    xxxx = xxxxx  # tooltip
         Plog(0,"plugin bad format: %s \n",plugins[ii]);                         //         |        |
         continue;                                                               //         pp       tt
      }
      
      pp++;
      *pp = 0;
      
      tt = strchr(pp+1,'#');                                                     //  locate tool tip                       24.30
      if (tt) {
         *tt = 0;
         tt++;
      }
      
      add_popmenu_item(popup_plugmenu, plugins[ii], m_run_plugin,0,tt);          //  create menu, menu name and tooltip

      *pp = '=';                                                                 //  restore '=' 
   }

   add_popmenu_item(popup_plugmenu, "Edit Plugins",                              //  last entry is Edit Plugins
                     m_edit_plugins, 0, "Edit plugins menu");

   popup_menu(Mwin,popup_plugmenu);                                              //  popup the menu

   return;
}


/********************************************************************************/

//  edit plugins menu
//  edit the plugins file in /home/<user>/.fotocx/plugins

void m_edit_plugins(GtkWidget *, ch *)
{
   F1_help_topic = "plugins";

   Plog(1,"m_edit_plugins \n");
   if (FGM != 'F' && FGM != 'G') return;
   zdialog_edit_textfile(Mwin,plugins_file);                                     //  24.30
   return;
}


/********************************************************************************/

//  process plugin menu selection
//  execute corresponding command using current image file

editfunc    EFplugin;

void m_run_plugin(GtkWidget *, ch *menu)
{
   using namespace plugins_names;

   int         ii, jj, err;
   ch          *pp = 0, *pp1, *pp2;
   ch          plugcommand[400], temp[400];
   ch          menuname[100];
   ch          *plugfile = 0, *outfile = 0;
   zdialog     *zd = 0;
   double      basetime;

   F1_help_topic = "plugins";

   Plog(1,"run plugin: %s \n",menu);

   for (ii = 0; ii < Nplugins; ii++)                                             //  search plugins for menu name
   {
      pp = strchr(plugins[ii],'=');                                              //  match menu name to plugin command
      if (! pp) continue;                                                        //  menu name = command "%s"
      *pp = 0;
      jj = strmatch(plugins[ii],menu);
      *pp = '=';
      if (jj) break;
   }

   if (ii == Nplugins) {
      zmessageACK(Mwin,"plugin menu not found %s",menu);
      return;
   }

   strncpy0(plugcommand,pp+1,400);                                               //  corresp. command
   strTrim2(plugcommand);

   pp = strstr(plugcommand,"%s");                                                //  no file placeholder in command
   if (! pp) {
      zd = zmessage_post(Mwin,"20/20",0,"Plugin working ...");
      err = zshell("log ack",plugcommand);                                       //  execute non-file plugin command
      zd = zmessage_post(Mwin,"20/20",3,"Plugin exited");
      return;
   }

   if (! curr_file) {
      zmessageACK(Mwin,"no current file");
      return;
   }

   plugfile = zstrdup(curr_file,"run_plugin",50);
   pp1 = strrchr(plugfile,'/');                                                  //  plugfile: /.../curr_file.ext
   pp2 = strrchr(curr_file,'.');                                                 //                |         |
                                                                                 //                pp1       pp2
   if (! pp1 || ! pp2) {
      zmessageACK(Mwin,"cannot parse current file");
      return;
   }

   strcpy(pp1,"/fotocx-plugin-file");                                            //  plugfile: /.../fotocx-plugin-file.ext
   strcat(pp1,pp2);

   err = cp_copy(curr_file,plugfile);
   if (err) {
      zmessageACK(Mwin,"cannot copy current file");
      return;
   }

   if (! strstr(plugcommand,"\"%s\"")) {                                         //  insure plugin command "%s"
      repl_1str(plugcommand,temp,400,"%s","\"%s\"");                             //     is bracketed with quotes
      strcpy(plugcommand,temp);
   }

   pp = zescape_quotes(plugfile);                                                //  escape quotes in file name
   repl_1str(plugcommand,command,CCC,"%s",pp);                                   //  command = plugcommand "plugfile"
   zfree(pp);

   zd = zmessage_post(Mwin,"20/20",0,"Plugin working ...");
   basetime = get_seconds();                                                     //  basetime = NOW
   err = zshell("log ack",command);                                              //  execute plugin command, return
   zdialog_free(zd);                                                             //  kill 'working' message

   if (err) {
      zmessageACK(Mwin,"plugin command failed");
      return;
   }

   snprintf(menuname,100,"Plugin %s",menu);                                      //  make fotocx edit function
   pp = strchr(menuname,'=');                                                    //  Plugin progname = ...
   if (pp) pp[-1] = 0;
   EFplugin.menuname = zstrdup(menuname,"run_plugin");                           //  Plugin progname
   EFplugin.menufunc = m_run_plugin;
   EFplugin.Farea = 2;                                                           //  select area usable
   if (! edit_setup(EFplugin)) return;

   outfile = find_outfile(plugfile,basetime);                                    //  search for plugin output file
   if (! outfile) {                                                              //    with mod time > basetime
      zmessageACK(Mwin,"no plugin output file found");
      edit_cancel(0);
      return;
   }

   PXM_free(E3pxm);                                                              //  discard E3 image from edit_setup
   E3pxm = PXM_load(outfile,1);                                                  //  new E3 from plugin output file
   if (! E3pxm) {
      zmessageACK(Mwin,"cannot read pluging output file");
      edit_cancel(0);
      return;
   }

   Eww = E3pxm->ww;                                                              //  new E3 size
   Ehh = E3pxm->hh;

   if (sa_stat == sa_stat_fini) {                                                //  if select area, restore unselected 
      if (Eww != E1pxm->ww || Ehh != E1pxm->hh)
         zmessageACK(Mwin,"output file size change, cannot use select area");
      else sa_postfix();
   }

   CEF->Fmods++;                                                                 //  E3 modified
   CEF->Fsaved = 0;

   edit_done(0);
   
   remove(outfile);                                                              //  24.30

   return;
}


/********************************************************************************/

//  Find the output file from a plugin or other function which processes
//    an input file and creates an output file.
//  Searches for output file with root name match and modtime > basetime.
//  Returned filename is subject for zfree().
//  Note: only files < 1 hour old are checked, so user must return from
//    the plugin app to Fotocx within 1 hour after making the output file.

ch * find_outfile(ch *infile, double basetime)
{
   ch       *findcommand = "find %s -type f -cmin -60 -print";                   //  get files < 1 hour old
   ch       buff[XFCC];
   ch       outfile[XFCC];
   ch       findpatt[XFCC];
   ch       basename[200];
   ch       *pp, *pp1, *pp2;
   int      bcc;
   FILE     *fid;
   STATB    statB;
   double   modtime = basetime;
   double   modtimex;

   *outfile = 0;

   if (! regfile(infile,&statB)) return 0;

   pp = strrchr(infile,'/');                                                     //  get input file base name
   if (! pp) return 0;
   strncpy0(basename,pp,200);
   pp = strrchr(basename,'.');
   if (pp) *pp = 0;
   bcc = strlen(basename);

   repl_Nstrs(infile,findpatt,XFCC," ","\\ ","\"","\\\"","'","\\'",0);           //  escapes for 'find' command
   pp = strrchr(findpatt,'/');                                                   //  search folder
   if (! pp) return 0;
   pp[1] = 0;

   snprintf(command,XFCC,findcommand,findpatt);                                  //  search input file folder
   Plog(2,"%s\n",command);                                                       //    for recent regular files

   fid = popen(command,"r");
   if (! fid) return 0;

   while ((pp1 = fgets_trim(buff,XFCC,fid))) {                                   //  loop files found
      if (image_file_type(pp1) != IMAGE) continue;                               //  not image file type
      pp2 = strrchr(buff,'/');                                                   //  get file base name
      if (! pp2 || ! strmatchN(pp2,basename,bcc)) continue;                      //  no match
      modtimex = get_modtime(pp1);                                               //  get file mod time
      if (modtimex < modtime) continue;                                          //  not latest match
      strncpy0(outfile,pp1,XFCC);                                                //  save latest file found
      modtime = modtimex;
   }
   pclose(fid);

   Plog(1,"plugin output file: %s \n",outfile);
   if (*outfile) return zstrdup(outfile,"find_outfile");
   else return 0;
}