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

   Fotocx - edit photos and manage collections

   Copyright 2007-2026 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, *mAlbums, *mMeta, *mSelect;                     //  top menus
GtkWidget   *mEdit, *mRepair, *mRefine, *mEffects, *mWarp, *mComb;
GtkWidget   *mBatch, *mTools, *mHelp, *mDevelop;
GtkWidget   *popmenu_image, *popmenu_raw, *popmenu_mpo, *popmenu_video;                //  popup menus
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,5);                                     //  margin = 5                            25.1
   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,5);                                     //  margin = 5                            26.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);
   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(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 container
   
   Mhbox = gtk_frame_new(null);                                                        //  top container for internet map
   gtk_box_pack_start(GTK_BOX(MWvbox),Mhbox,1,1,0);
   
   //  menu popup text (tool tips) ----------------------------------------

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

   //  file menu
   ch * new_session_tip = TX("Open a parallel Fotocx session");
   ch * open_file_tip = TX("Select and view an image file");
   ch * cycle2files_tip = TX("Cycle 2 Prior Files");
   ch * cycle3files_tip = TX("Cycle 3 Prior Files");
   ch * view360_tip = TX("View 360 degree panorama image");
   ch * rename_tip = TX("Change file name");
   ch * blank_image_tip = TX("Create a blank image");
   ch * copy_move_tip = TX("Copy or Move image file to new location");
   ch * copyto_desktop_tip = TX("Copy image file to the desktop");
   ch * copyto_clipboard_tip = TX("Copy image file to the clipboard");
   ch * deltrash_tip = TX("Delete or trash an image file");
   ch * set_wallpaper_tip = TX("Set image file as desktop wallpaper");
   ch * print_image_tip = TX("Print the current image file");
   ch * print_calibrated_tip = TX("Print current image file with calibrated colors");
   ch * calib_printer_tip = TX("Color calibration tool for printer and paper type");
   ch * quit_tip = TX("Quit Fotocx");

   //  gallery menu
   ch * thumbview_tip = TX("Gallery view with thumbnails and file data");
   ch * metaview_tip = TX("Gallery view with thumbnails and basic metadata");
   ch * recentfiles_tip = TX("Gallery of recently viewed image files");
   ch * newest_files_tip = TX("Gallery of newest image files");
   ch * gallery_sort_tip = TX("Change gallery sort order");
   ch * gallery_filter_tip = TX("Select versions, ratings, keywords, filename text");
   ch * gallery_home_tip = TX("Jump to gallery beginning [home]");
   ch * gallery_end_tip = TX("Jump to gallery end [end]");
   ch * current_file_folder_tip = TX("Set gallery to folder of current file");
   ch * recent_folders_tip = TX("Set gallery from recent folders list");
   ch * search_results_tip = TX("Set gallery from latest search results");
   ch * folder_tree_tip = TX("Show folder hierarchy, click folder for gallery view");
   ch * select_files_tip = TX("Select input files for subsequent function");
   ch * bookmarks_tip = TX("Set and view bookmarks, select for gallery view");

   //  maps menu
   ch * show_on_map_tip = TX("Show map position of the current image file");           //  26.7

   //  albums menu                                                                     //  25.1
   ch * create_album_tip = TX("Create a new album (ordered set of image files)");
   ch * rename_album_tip = TX("Rename an existing album");
   ch * delete_album_tip = TX("Delete an album");
   ch * choose_album_tip = TX("Choose an album and show as gallery of images");
   ch * current_album_tip = TX("Show the current (last used) album");
   ch * gallery_to_album_tip = TX("Save current gallery as album");
   ch * update_albums_tip = TX("Update albums for new file versions");
   ch * album_mass_update_tip = TX("Mass update album files");
   ch * slideshow_tip = TX("Start a slide show");

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

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

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

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

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

   //  effects menu
   ch * outlines_tip = TX("Convert image into a line drawing");
   ch * sketch1_tip = TX("Convert image into a simulated sketch (1)");
   ch * sketch2_tip = TX("Convert image into a simulated sketch (2)");
   ch * cartoon_tip = TX("Convert image into a cartoon drawing");
   ch * emboss_tip = TX("Create an embossed or 3D appearance");
   ch * tiles1_tip = TX("Convert image into square tiles with 3D effect");
   ch * tiles2_tip = TX("Convert image into tiles matching feature contours");
   ch * painting_tip = TX("Convert image into a simulated painting");
   ch * texture_tip = TX("Add texture to an image");
   ch * fusion_tip = TX("Suppress fine details while retaining sharpness");
   ch * pattern_tip = TX("Tile image with a repeating pattern");
   ch * crosshatch_tip = TX("Convert image into a crosshatch sketch");
   ch * dither_tip = TX("Convert image into dithered dots");
   ch * engrave_tip = TX("Convert image into black/white lines");
   ch * addglare_tip = TX("Add glare around bright objects");
   ch * mosaic_tip = TX("Create a mosaic with tiles made from all images");
   ch * add_noise_tip = TX("Add random noise to an image");
   ch * set_colors_tip = TX("Set number of colors for each R/G/B or total");
   ch * shift_colors_tip = TX("Shift/convert image colors into other colors");
   ch * alien_colors_tip = TX("Change image colors using an algorithm");
   ch * anykernel_tip = TX("Process an image using a custom convolution kernel");

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

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

   //  batch menu
   ch * batch_convert_tip = TX("Rename/convert/rescale/move selected image or RAW files");
   ch * batch_copy_move_tip = TX("Copy/move selected image files to a new folder");
   ch * batch_upright_tip = TX("Upright rotated image files, selected set or ALL");
   ch * batch_deltrash_tip = TX("Delete or Trash selected image files");
   ch * batch_overlay_tip = TX("Add overlay image (e.g. copyright) to selected images");
   ch * batch_keywords_tip = TX("Add/remove keywords for selected image files");
   ch * batch_rename_keywords_tip = TX("Rename or delete keywords for all image files");
   ch * batch_purge_keywords_tip = TX("Purge unwanted keywords from all image files");
   ch * batch_photo_DT_tip = TX("Set or shift photo date/time for selected image files");
   ch * batch_change_meta_tip = TX("Add/change/delete metadata for selected image files");
   ch * batch_report_meta_tip = TX("Report selected metadata for selected image files");
   ch * batch_geotags_tip = TX("Add/revise location/geocoordinates for selected image files");
   ch * export_files_tip = TX("Export selected image files to another folder");

   //  tools menu
   ch * index_tip = TX("Index new image files and make thumbnails");
   ch * move_fotocx_home_tip = TX("Move Fotocx home folder to chosen folder");                                               //  26.2
   ch * settings_tip = TX("User preferences and settings");
   ch * KB_shortcuts_tip = TX("Show or make Keyboard Shortcuts");
   ch * RGB_hist_tip = TX("RGB brightness histogram graph");
   ch * magnify_tip = TX("Magnify image around the mouse position");
   ch * measure_image_tip = TX("Measure pixel distances within an image");
   ch * show_RGB_tip = TX("Show RGB levels at mouse position");
   ch * grid_settings_tip = TX("Set horizontal/vertical grid line counts");
   ch * toggle_grid_tip = TX("Toggle grid lines on and off");
   ch * line_color_tip = TX("Set foreground line color (crop, grid, select, warp)");
   ch * darkbrite_tip = TX("Highlight darkest and brightest pixels");
   ch * display_color_tip = TX("Chart to adjust display color");
   ch * duplicates_tip = TX("Search all image files and report duplicates");
   ch * resources_tip = TX("Show memory and CPU resources used");
   ch * translations_tip = "Modify a translation or add a new one";                                                          //  26.5

   //  help menu
   ch * user_guide_tip = TX("Read or search the user guide");
   ch * video_tutorial_tip = TX("Fotocx video tutorial on YouTube");
   ch * outboard_programs_tip = TX("List outboard programs and functions");
   ch * show_logfile_tip = TX("Show the current log file");                                                                  //  26.0
   ch * command_params_tip = TX("List Fotocx command line parameters");
   ch * changelog_tip = TX("Show Fotocx updates for recent releases");
   ch * copyright_tip = TX("Fotocx copyright notice");
   ch * privacy_tip = TX("Fotocx privacy policy");
   ch * about_tip = TX("Show Fotocx installed version and author contact");
   ch * homepage_tip = TX("Fotocx web site (information and downloads)");
   ch * uninstall_tip = TX("How to remove Fotocx application and user files");
   
   //  develop menu
   ch * zmalloc_report_tip = "report memory allocation by tag";
   ch * zmalloc_growth_tip = "report memory increases by tag";
   ch * mouse_events_tip = "toggle: show mouse events on screen";
   ch * zappcrash_test_tip = "test zappcrash backtrace dump";
   ch * edit_template_tip = "edit function development template";
   ch * capture_gui_tip = "capture translatable text from source files > gui_en";
   ch * slice_gui_tip = "slice gui_en into small pieces for AI translator";
   ch * trans_table_tip = "merge gui_en + gui_xx > gui_xx translation table";
   ch * audit_gui_tip = "check gui_xx for matching text pairs and format codes";
   ch * slice_ug_tip = "slice ug_en into small pieces for AI translator";
   ch * sync_ug_tip = "sync ug_xx translations with gui_xx translations";
   ch * audit_ug_tip = "check ug_xx - all topic references are present";


   //  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,    TX("New Session"), 0,            new_session_tip,              m_new_session, 0 );
   MENU(mFile,    TX("Open Image File"), 0,        open_file_tip,                m_open_file, 0 );
   MENU(mFile,    TX("Cycle 2 Files"), 0,          cycle2files_tip,              m_cycle2files, 0 );
   MENU(mFile,    TX("Cycle 3 Files"), 0,          cycle3files_tip,              m_cycle3files, 0 );
   MENU(mFile,    TX("View 360° Pano"), 0,         view360_tip,                  m_view360, 0);
   MENU(mFile,    TX("Rename"), 0,                 rename_tip,                   m_rename, 0 );
   MENU(mFile,    TX("Blank Image"), 0,            blank_image_tip,              m_blank_image, 0 );
   MENU(mFile,    TX("Copy/Move"), 0,              copy_move_tip,                m_copy_move, 0 );
   MENU(mFile,    TX("Copy to Desktop"), 0,        copyto_desktop_tip,           m_copyto_desktop, 0 );
   MENU(mFile,    TX("Copy to Clipboard"), 0,      copyto_clipboard_tip,         m_copyto_clip, 0 );
   MENU(mFile,    TX("Delete/Trash"), 0,           deltrash_tip,                 m_delete_trash, 0 );
   MENU(mFile,    TX("Set Wallpaper"), 0,          set_wallpaper_tip,            m_wallpaper, 0 );
   MENU(mFile,    TX("Print Image"), 0,            print_image_tip,              m_print_image, 0 );
   MENU(mFile,    TX("Print Calibrated"), 0,       print_calibrated_tip,         m_print_calibrated, 0 );
   MENU(mFile,    TX("Calibrate Printer"), 0,      calib_printer_tip,            m_calibrate_printer, 0 );
   MENU(mFile,    TX("Quit"), 0,                   quit_tip,                     m_quit, 0 );

   mGallery = create_popmenu();
   MENU(mGallery,  TX("Thumbnail View"), 0,        thumbview_tip,                m_thumbview, 0 );
   MENU(mGallery,  TX("Metadata View"), 0,         metaview_tip,                 m_metaview, 0 );
   MENU(mGallery,  TX("Recent Files"), 0,          recentfiles_tip,              m_recentfiles, 0 );
   MENU(mGallery,  TX("Newest Files"), 0,          newest_files_tip,             m_newest_files, 0 );
   MENU(mGallery,  TX("Gallery Sort"), 0,          gallery_sort_tip,             m_gallery_sort, 0);
   MENU(mGallery,  TX("Gallery Filter"), 0,        gallery_filter_tip,           m_gallery_filter, 0);
   MENU(mGallery,  TX("Gallery Home"), 0,          gallery_home_tip,             navi::menufuncx, "Home");
   MENU(mGallery,  TX("Gallery End"), 0,           gallery_end_tip,              navi::menufuncx, "End");
   MENU(mGallery,  TX("Current File Folder"), 0,   current_file_folder_tip,      m_current_file_folder, 0 );
   MENU(mGallery,  TX("Recent Folders"), 0,        recent_folders_tip,           m_recent_folders, 0 );
   MENU(mGallery,  TX("Search Results"), 0,        search_results_tip,           m_search_results, 0 );                      //  26.5
   MENU(mGallery,  TX("Folder Tree"), 0,           folder_tree_tip,              m_folder_tree, 0 );
   MENU(mGallery,  TX("Select Files"), 0,          select_files_tip,             m_select_files, 0 );
   MENU(mGallery,  TX("Bookmarks"), 0,             bookmarks_tip,                m_bookmarks, 0 );

   mMaps = create_popmenu();
   MENU(mMaps,     TX("Show on Map"), 0,         show_on_map_tip,              m_show_on_map,  0 );                          //  26.7

   mAlbums = create_popmenu();                                                                                               //  25.1
   MENU(mAlbums,   TX("Create Album"), 0,        create_album_tip,             m_album_create, 0 );
   MENU(mAlbums,   TX("Rename Album"), 0,        rename_album_tip,             m_album_rename, 0 );
   MENU(mAlbums,   TX("Delete Album"), 0,        delete_album_tip,             m_album_delete, 0 );
   MENU(mAlbums,   TX("Choose Album"), 0,        choose_album_tip,             m_album_choose, 0 );
   MENU(mAlbums,   TX("Current Album"), 0,       current_album_tip,            m_album_current, 0 );
   MENU(mAlbums,   TX("Gallery to Album"), 0,    gallery_to_album_tip,         m_gallery_to_album, 0 );
   MENU(mAlbums,   TX("Update Albums"), 0,       update_albums_tip,            m_update_albums, 0 );
   MENU(mAlbums,   TX("Album Mass Update"), 0,   album_mass_update_tip,        m_album_mass_update, 0 );
   MENU(mAlbums,   TX("Slide Show"), 0,          slideshow_tip,                m_slideshow, 0 );

   mMeta = create_popmenu();
   MENU(mMeta,   TX("View Main Meta"), 0,        meta_view_main_tip,           m_meta_view_main, 0 );
   MENU(mMeta,   TX("View All Meta"), 0,         meta_view_all_tip,            m_meta_view_all, 0 );
   MENU(mMeta,   TX("Edit Main Meta"), 0,        meta_edit_main_tip,           m_meta_edit_main, 0 );
   MENU(mMeta,   TX("Edit Any Meta"), 0,         meta_edit_any_tip,            m_meta_edit_any, 0 );
   MENU(mMeta,   TX("Delete Meta"), 0,           meta_delete_tip,              m_meta_delete, 0 );
   MENU(mMeta,   TX("Copy Meta"), 0,             meta_copy_tip,                m_meta_copy, 0 );
   MENU(mMeta,   TX("Fix Meta"), 0,              meta_fix_tip,                 m_meta_fix, 0 );
   MENU(mMeta,   TX("Manage Keywords"), 0,       meta_manage_keywords_tip,     m_meta_manage_keywords, 0 );
   MENU(mMeta,   TX("Choose Captions"), 0,       meta_choose_caps_tip,         m_meta_choose_caps, 0 );
   MENU(mMeta,   TX("Toggle Captions"), 0,       meta_toggle_caps_tip,         m_meta_toggle_caps, 0 );
   MENU(mMeta,   TX("Places/Dates"), 0,          meta_places_dates_tip,        m_meta_places_dates, 0 );
   MENU(mMeta,   TX("Timeline"), 0,              meta_timeline_tip,            m_meta_timeline, 0 );
   MENU(mMeta,   TX("Metadata Tags"), 0,         meta_tags_tip,                m_meta_tags, 0 );
   MENU(mMeta,   TX("Search"), 0,                search_images_tip,            m_search_images, 0 );

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

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

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

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

   mEffects = create_popmenu();
   MENU(mEffects,   TX("Outlines"), 0,              outlines_tip,              m_outlines, 0 );
   MENU(mEffects,   TX("Sketch1"), 0,               sketch1_tip,               m_sketch1, 0 );
   MENU(mEffects,   TX("Sketch2"), 0,               sketch2_tip,               m_sketch2, 0 );
   MENU(mEffects,   TX("Cartoon"), 0,               cartoon_tip,               m_cartoon, 0 );
   MENU(mEffects,   TX("Emboss"), 0,                emboss_tip,                m_emboss, 0 );
   MENU(mEffects,   TX("Tiles1"), 0,                tiles1_tip,                m_tiles1, 0 );
   MENU(mEffects,   TX("Tiles2"), 0,                tiles2_tip,                m_tiles2, 0 );
   MENU(mEffects,   TX("Painting"), 0,              painting_tip,              m_painting, 0 );
   MENU(mEffects,   TX("Texture"), 0,               texture_tip,               m_texture, 0 );
   MENU(mEffects,   TX("Fusion"), 0,                fusion_tip,                m_fusion, 0 );
   MENU(mEffects,   TX("Pattern"), 0,               pattern_tip,               m_pattern, 0 );
   MENU(mEffects,   TX("Crosshatch"), 0,            crosshatch_tip,            m_crosshatch, 0 );
   MENU(mEffects,   TX("Dither"), 0,                dither_tip,                m_dither, 0 );
   MENU(mEffects,   TX("Engrave"), 0,               engrave_tip,               m_engrave, 0 );
   MENU(mEffects,   TX("Add Glare"), 0,             addglare_tip,              m_addglare, 0 );
   MENU(mEffects,   TX("Mosaic"), 0,                mosaic_tip,                m_mosaic, 0 );
   MENU(mEffects,   TX("Add Noise"), 0,             add_noise_tip,             m_add_noise, 0 );
   MENU(mEffects,   TX("Set Colors"), 0,            set_colors_tip,            m_set_colors, 0 );
   MENU(mEffects,   TX("Shift Colors"), 0,          shift_colors_tip,          m_shift_colors, 0 );
   MENU(mEffects,   TX("Alien Colors"), 0,          alien_colors_tip,          m_alien_colors, 0 );
   MENU(mEffects,   TX("Custom Kernel"), 0,         anykernel_tip,             m_anykernel, 0 );

   mWarp = create_popmenu();
   MENU(mWarp,   TX("Unbend"), 0,                   unbend_tip,                m_unbend, 0 );
   MENU(mWarp,   TX("Perspective"), 0,              perspective_tip,           m_perspective, 0 );
   MENU(mWarp,   TX("Warp Area"), 0,                warp_area_tip,             m_warp_area, 0 );
   MENU(mWarp,   TX("Warp Curved"), 0,              warp_curved_tip,           m_warp_curved, 0 );
   MENU(mWarp,   TX("Warp Affine"), 0,              warp_affine_tip,           m_warp_affine, 0 );
   MENU(mWarp,   TX("Warp Radial"), 0,              warp_radial_tip,           m_warp_radial, 0);
   MENU(mWarp,   TX("Unwarp Closeup"), 0,           unwarp_closeup_tip,        m_unwarp_closeup, 0 );
   MENU(mWarp,   TX("Make Waves"), 0,               makewaves_tip,             m_makewaves, 0);
   MENU(mWarp,   TX("Twist"), 0,                    twist_tip,                 m_twist, 0);
   MENU(mWarp,   TX("Sphere"), 0,                   sphere_tip,                m_sphere, 0);
   MENU(mWarp,   TX("Inside-out"), 0,               inside_out_tip,            m_inside_out, 0);
   MENU(mWarp,   TX("Tiny Planet"), 0,              tiny_planet_tip,           m_tiny_planet, 0);
   MENU(mWarp,   TX("Escher Spiral"), 0,            escher_spiral_tip,         m_escher_spiral, 0);
   MENU(mWarp,   TX("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,   TX("Stack/Paint"), 0,              stack_paint_tip,           m_stack_paint, 0 );
   MENU(mComb,   TX("Stack/Noise"), 0,              stack_noise_tip,           m_stack_noise, 0 );
   MENU(mComb,   TX("Stack/Layers"), 0,             stack_layers_tip,          m_stack_layers, 0 );
   MENU(mComb,   TX("Panorama"), 0,                 panorama_tip,              m_panorama, 0 );
   MENU(mComb,   TX("Show CIM Files"), 0,           show_cim_files_tip,        m_cim_show_files, 0 );
   MENU(mComb,   TX("Mashup"), 0,                   mashup_tip,                m_mashup, 0 );
   MENU(mComb,   TX("Image Array"), 0,              image_array_tip,           m_image_array, 0 );

   mBatch = create_popmenu();
   MENU(mBatch,  TX("Batch Convert"), 0,            batch_convert_tip,         m_batch_convert, 0 );
   MENU(mBatch,  TX("Batch Copy/Move"), 0,          batch_copy_move_tip,       m_batch_copy_move, 0 );
   MENU(mBatch,  TX("Batch Upright"), 0,            batch_upright_tip,         m_batch_upright, 0 );
   MENU(mBatch,  TX("Batch Delete/Trash"), 0,       batch_deltrash_tip,        m_batch_deltrash, 0 );
   MENU(mBatch,  TX("Batch Overlay"), 0,            batch_overlay_tip,         m_batch_overlay, 0 );
   MENU(mBatch,  TX("Batch Keywords"), 0,           batch_keywords_tip,        m_batch_keywords, 0 );
   MENU(mBatch,  TX("Batch Rename Keywords"), 0,    batch_rename_keywords_tip, m_batch_rename_keywords, 0 );
   MENU(mBatch,  TX("Batch Purge Keywords"), 0,     batch_purge_keywords_tip,  m_batch_purge_keywords, 0 );
   MENU(mBatch,  TX("Batch Photo Date"), 0,         batch_photo_DT_tip,        m_batch_photo_date_time, 0 );
   MENU(mBatch,  TX("Batch Change Meta"), 0,        batch_change_meta_tip,     m_batch_change_meta, 0 );
   MENU(mBatch,  TX("Batch Report Meta"), 0,        batch_report_meta_tip,     m_batch_report_meta, 0 );
   MENU(mBatch,  TX("Batch Geotags"), 0,            batch_geotags_tip,         m_batch_geotags, 0 );
   MENU(mBatch,  TX("Export Files"), 0,             export_files_tip,          m_export_files, 0 );

   mTools = create_popmenu();
   MENU(mTools,   TX("Index Files"), 0,              index_tip,                 m_index, 0 );
   MENU(mTools,   TX("Settings"), 0,                 settings_tip,              m_settings, 0 );
   MENU(mTools,   TX("Keyboard Shortcuts"), 0,       KB_shortcuts_tip,          m_KB_shortcuts, 0 );
   MENU(mTools,   TX("RGB Histogram"), 0,            RGB_hist_tip,              m_RGB_hist, 0 );
   MENU(mTools,   TX("Magnify Image"), 0,            magnify_tip,               m_magnify, 0 );
   MENU(mTools,   TX("Measure Image"), 0,            measure_image_tip,         m_measure_image, 0 );
   MENU(mTools,   TX("Show RGB"), 0,                 show_RGB_tip,              m_show_RGB, 0 );
   MENU(mTools,   TX("Grid Settings"), 0,            grid_settings_tip,         m_grid_settings, 0 );
   MENU(mTools,   TX("Toggle Grid"), 0,              toggle_grid_tip,           m_toggle_grid, 0 );
   MENU(mTools,   TX("Line Color"), 0,               line_color_tip,            m_line_color, 0 );
   MENU(mTools,   TX("Dark/Bright Pixels"), 0,       darkbrite_tip,             m_darkbrite, 0 );
   MENU(mTools,   TX("Display Color"), 0,            display_color_tip,         m_display_color, 0 );
   MENU(mTools,   TX("Find Duplicates"), 0,          duplicates_tip,            m_duplicates, 0 );
   MENU(mTools,   TX("Move Fotocx Home"), 0,         move_fotocx_home_tip,      m_move_fotocx_home, 0);                      //  26.2
   MENU(mTools,   TX("Show Resources"), 0,           resources_tip,             m_resources, 0 );
   MENU(mTools,      "Translations", 0,              translations_tip,          m_translations, 0 );                         //  26.5

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

   //  main menu buttons - must be last

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

   //  show developer tools menu if required

   if (Fdevelop)
   {
      mDevelop = create_popmenu();
      MENU(0, "Develop", "develop.png", "Developer tools", (cbFunc *) popup_menu, (ch *) mDevelop);

      MENU(mDevelop, "zmalloc report",      0,     zmalloc_report_tip,     m_zmalloc_report,       0);
      MENU(mDevelop, "zmalloc growth",      0,     zmalloc_growth_tip,     m_zmalloc_growth,       0);
      MENU(mDevelop, "mouse events",        0,     mouse_events_tip,       m_mouse_events,         0);
      MENU(mDevelop, "zappcrash test",      0,     zappcrash_test_tip,     m_zappcrash_test,       0);
      MENU(mDevelop, "EditFunc Template",   0,     edit_template_tip,      m_editfunc_template,    0);
      MENU(mDevelop, "Capture GUI",         0,     capture_gui_tip,        m_capture_GUI,          0);                       //  26.5
      MENU(mDevelop, "Slice GUI",           0,     slice_gui_tip,          m_slice_GUI,            0);                       //  26.5
      MENU(mDevelop, "Transtab GUI",        0,     trans_table_tip,        m_transtab_GUI,         0);                       //  26.5
      MENU(mDevelop, "Audit GUI",           0,     audit_gui_tip,          m_audit_GUI,            0);                       //  26.5
      MENU(mDevelop, "Slice UG",            0,     slice_ug_tip,           m_slice_UG,             0);                       //  26.5
      MENU(mDevelop, "Sync UG",             0,     sync_ug_tip,            m_sync_UG,              0);                       //  26.5
      MENU(mDevelop, "Audit UG",            0,     audit_ug_tip,           m_audit_UG,             0);                       //  26.5
   }

   int   Vmenus = Nmenus;                                                              //  visible menus stop here

   //  internal functions not shown in menus - visible for scripting

   MENU(mDevelop,    "Copy From Image Slave", 0, 0,   m_copy_from_image_slave, 0 );
   MENU(mDevelop,    "Autosearch",            0, 0,   m_autosearch, 0);
   MENU(mRepair,     "Blur Normal",           0, 0,   m_blur_normal, 0 );
   MENU(mRepair,     "Blur Graduated",        0, 0,   m_blur_graduated, 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(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(TX("Adjust HSL"),            m_adjust_HSL,              0     );
   KBshort(TX("Adjust RGB"),            m_adjust_RGB,              0     );
   KBshort(TX("Amplify Contrast"),      m_amplifycon,              0     );
   KBshort(TX("Blur Normal"),           m_blur_normal,             0     );
   KBshort(TX("Bookmarks"),             m_bookmarks,               0     );
   KBshort(TX("Choose Captions"),       m_meta_choose_caps,        0     );
   KBshort(TX("Color Mode"),            m_color_mode,              0     );
   KBshort(TX("Copy/Move"),             m_copy_move,               0     );
   KBshort(TX("Copy to Clipboard"),     m_copyto_clip,             0     );
   KBshort(TX("Copy to Desktop"),       m_copyto_desktop,          0     );
   KBshort(TX("Crop"),                  m_crop,                    0     );
   KBshort(TX("Current Album"),         m_album_current,           0     );
   KBshort(TX("Current File Folder"),   m_current_file_folder,     0     );
   KBshort(TX("Cycle 2 Files"),         m_cycle2files,             0     );
   KBshort(TX("Cycle 3 Files"),         m_cycle3files,             0     );
   KBshort(TX("Delete Meta"),           m_meta_delete,             0     );
   KBshort(TX("Delete/Trash"),          m_delete_trash,            0     );
   KBshort(TX("Denoise"),               m_denoise,                 0     );
   KBshort(TX("Dither"),                m_dither,                  0     );
   KBshort(TX("Edit Any Meta"),         m_meta_edit_any,           0     );
   KBshort(TX("Edit Main Meta"),        m_meta_edit_main,          0     );
   KBshort(TX("File View"),             m_viewmode,               "F"    );
   KBshort(TX("Flatten Histogram"),     m_flat_hist,               0     );
   KBshort(TX("Folder Tree"),           m_folder_tree,             0     );
   KBshort(TX("Gallery View"),          m_viewmode,               "G"    );
   KBshort(TX("Global Retinex"),        m_gretinex,                0     );
   KBshort(TX("Grid Settings"),         m_grid_settings,           0     );
   KBshort(TX("Keyboard Shortcuts"),    m_KB_shortcuts,            0     );
   KBshort(TX("Line Color"),            m_line_color,              0     );
   KBshort(TX("Local Retinex"),         m_lretinex,                0     );
   KBshort(TX("Magnify Image"),         m_magnify,                 0     );
   KBshort(TX("Map View"),              m_viewmode,               "M"    );
   KBshort(TX("Markup"),                m_markup,                  0     );
   KBshort(TX("Metadata View"),         m_metaview,                0     );
   KBshort(TX("Newest"),                m_newest_files,            0     );
   KBshort(TX("New Session"),           m_new_session,             0     );
   KBshort(TX("New Version"),           m_file_save_version,       0     );
   KBshort(TX("Open Image File"),       m_open_file,               0     );
   KBshort(TX("Paint Edits"),           m_paint_edits,             0     );
   KBshort(TX("Perspective"),           m_perspective,             0     );
   KBshort(TX("Places/Dates"),          m_meta_places_dates,       0     );
   KBshort(TX("Print Calibrated"),      m_print_calibrated,        0     );
   KBshort(TX("Print Image"),           m_print_image,             0     );
   KBshort(TX("Quit"),                  m_quit,                    0     );
   KBshort(TX("Recent Files"),          m_recentfiles,             0     );
   KBshort(TX("Recent Folders"),        m_recent_folders,          0     );
   KBshort(TX("Red Eyes"),              m_redeyes ,                0     );
   KBshort(TX("Redo"),                  m_redo,                    0     );
   KBshort(TX("Rename"),                m_rename,                  0     );
   KBshort(TX("Replace"),               m_file_save_replace,       0     );
   KBshort(TX("Rescale"),               m_rescale,                 0     );
   KBshort(TX("Retouch"),               m_retouch,                 0     );
   KBshort(TX("RGB Histogram"),         m_RGB_hist,                0     );
   KBshort(TX("Rotate"),                m_rotate,                  0     );
   KBshort(TX("Save"),                  m_file_save,               0     );
   KBshort(TX("Search"),                m_search_images,           0     );
   KBshort(TX("Search Results"),        m_search_results,          0     );
   KBshort(TX("Select Area"),           m_select_area,             0     );
   KBshort(TX("Select Files"),          m_select_files,            0     );
   KBshort(TX("Set Colors"),            m_set_colors,              0     );
   KBshort(TX("Settings"),              m_settings,                0     );
   KBshort(TX("Sharpen"),               m_sharpen,                 0     );
   KBshort(TX("Show on Map"),           m_show_on_map,             0     );
   KBshort(TX("Show Resources"),        m_resources,               0     );
   KBshort(TX("Metadata Tags"),         m_meta_tags,               0     );
   KBshort(TX("Timeline"),              m_meta_timeline,           0     );
   KBshort(TX("Toggle Captions"),       m_meta_toggle_caps,        0     );
   KBshort(TX("Toggle Grid"),           m_toggle_grid,             0     );
   KBshort(TX("Undo"),                  m_undo,                    0     );
   KBshort(TX("Upright"),               m_upright,                 0     );
   KBshort(TX("View 360° Pano"),        m_view360,                 0     );
   KBshort(TX("View Main Meta"),        m_meta_view_main,          0     );
   KBshort(TX("Split-Screen"),          m_split_screen1,           0     );
   KBshort("zmalloc by tag",            m_zmalloc_report,          0     );
   KBshort("zmalloc growth",            m_zmalloc_growth,          0     );
   KBshort(TX("Zoom-in"),               m_zoom,                   "in"   );
   KBshort(TX("Zoom-out"),              m_zoom,                   "out"  );
   //  zdialog completion buttons that can have KB shortcuts assigned
   KBshort(TX("Apply"),                 0,                         0     );
   KBshort("X",                         0,                         0     );
   KBshort("OK",                        0,                         0     );
   KBshort(TX("Reset"),                 0,                         0     );

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

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

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

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

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

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

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

   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,"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_show_on_map(0,0);
   if (strmatch(menu,"add to selection")) add_file_to_selection(curr_file);
   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/N

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


void viewmode(ch fgm)                                                                  //  callable
{
   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';

      Cstate = 0;                                                                      //  no image drawing area
      Cdrawin = 0;
      Fgdkwin = 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 (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;
      Fgdkwin = gtk_widget_get_window(Fdrawin);                                        //  GDK window

      FGM = 'F';

      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 (fgm == 'G')                                                                     //  set G view mode for thumbnail gallery
   {
      gtk_widget_hide(Fhbox);
      gtk_widget_hide(Mhbox);
      gtk_widget_show_all(Ghbox);
      FGM = 'G';

      Cstate = 0;                                                                      //  no image drawing area
      Cdrawin = 0;
      Fgdkwin = 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')
   {
      if (CEF) return;                                                                 //  don't interrupt edit func.

      if (Xindexlev < 1) {
         index_rebuild(1,0);
         if (Nxxrec == 0) {
            zmessageACK(Mwin,TX("image index required"));
            return;
         }
      }

      gtk_widget_hide(Fhbox);
      gtk_widget_hide(Ghbox);
      gtk_widget_show_all(Mhbox);
      FGM = 'M';
      
      Cstate = 0;                                                                      //  no image drawing area
      Cdrawin = 0;
      Fgdkwin = 0;

      m_load_netmap(0,0);                                                              //  show internet map
   }

   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;
}


//  custom menu function

void m_custom_menu(GtkWidget *, ch *)
{
   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 = TX("CUSTOM MENU");

   printf("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 = TX("view album");

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

   add_popmenu(popmenu,TX("Edit Menu"),custom_menu_edit,0,TX("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)
{
   using namespace custom_menu_names;

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

   printf("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;                                  //  find menu function                    26.0
      if (strmatchcase(TX(text),menutab[ii].menu)) break;
      if (strmatchcase(text,TX(menutab[ii].menu))) break;
   }

   if (ii < Nmenus) menutab[ii].func(0,0);                                             //  found, call menu function
   else zmessageACK(Mwin,TX(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
   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 = TX("SCRIPT FILES");

   printf("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",TX("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",TX("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,TX("script already started"));
      return 0;
   }

   pp = zgetfile(TX("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,TX("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,TX("perform edits to include 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,TX("script file error"));
         return;
      }
   }

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


//  complete and save a script file under construction

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

   fprintf(script_fid,"menu: end");
   fclose(script_fid);
   script_fid = 0;
   Fscriptbuild = 0;
   zmessageACK(Mwin,TX("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,TX("no script files found"));
      return;
   }

   scriptmenu = create_popmenu();                                                      //  create popup menu for script names
   add_popmenu(scriptmenu,TX("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(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,TX("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,TX("no current file"));
      return;
   }

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

   Fbusy(+1);                                                                          //  enable user kill

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

   printf("start script: %s \n",scriptfile);
   script_fid = fopen(scriptfile,"r");                                                 //  open script file
   if (! script_fid) {
      zmessageACK(Mwin,TX("script error: %s, %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

   Fscriptrun = 1;                                                                     //  script file active

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

      zmainsleep(0.01);

      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;                               //  26.0
         if (strmatch(menuname,TX(menutab[ii].menu))) break;
         if (strmatch(TX(menuname),menutab[ii].menu)) break;
      }

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

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

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

      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,TX("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");
         printf("finish edit \n");
      }
   }

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

badfile:
   zmessageACK(Mwin,TX("script file format error: %s"),scriptname);
   if (script_fid) fclose(script_fid);
   script_fid = 0;
   Fscriptrun = 0;
   Fescape = 0;
   Fbusy(-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,TX("no files selected"));
      return;
   }

   Fbusy(+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;
   Fbusy(-1);

   panelmessage(1,3,TX("script complete"));                                            //  25.1
   return;
}


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

void m_run_script(GtkWidget *, ch *menu)
{
   F1_help_topic = TX("SCRIPT FILES");
   printf("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 = TX("SCRIPT FILES");

   printf("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",TX("Select Files"),"space=5");
   zdialog_add_widget(zd,"label","fcount","hb1",TX("no files selected"));

   zdialog_add_widget(zd,"hbox","hb2","dialog");
   zdialog_add_widget(zd,"button","select-script","hb2",TX("Select Script"),"space=5");
   zdialog_add_widget(zd,"label","labscript","hb2",TX("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 = TX("SCRIPT FILES");

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

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

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

   if (strmatch(event,"select-script")) {                                              //  select and run a script file
      if (! SFcount) zmessageACK(Mwin,TX("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 = TX("PLUGINS");

   printf("m_plugins \n");

   if (! regfile(plugins_file)) {
      fid = fopen(plugins_file,"w");                                                   //  not found, create default
      fprintf(fid,"Gimp = gimp %%s # edit current image using Gimp \n");
      fprintf(fid,"auto-gamma = mogrify -auto-gamma %%s # auto gamma \n");             //  imagemagick package
      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
         printf("*** plugin bad format: %s \n",plugins[ii]);                           //         |        |
         continue;                                                                     //         pp       tt
      }

      pp++;
      *pp = 0;

      tt = strchr(pp+1,'#');                                                           //  locate tool tip
      if (tt) {
         *tt = 0;
         tt++;
      }

      add_popmenu(popup_plugmenu, plugins[ii], m_run_plugin,0,tt);                     //  create menu, menu name and tooltip

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

   add_popmenu(popup_plugmenu, "Edit Plugins",                                         //  last entry is Edit Plugins
                     m_edit_plugins, 0, TX("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 = TX("PLUGINS");

   printf("m_edit_plugins \n");
   if (FGM != 'F' && FGM != 'G') return;
   zdialog_edit_textfile(Mwin,plugins_file);
   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;

   ch * find_outfile(ch *infile, uint basetime);

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

   F1_help_topic = TX("PLUGINS");

   printf("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,TX("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) {
      panelmessage(1,0,TX("Plugin working ..."));                                      //  25.1
      err = zshell("log ack thread",plugcommand);                                      //  execute non-file plugin command       25.1
      panelmessage(0);
      return;
   }

   if (! curr_file) {
      zmessageACK(Mwin,TX("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,TX("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,TX("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);

   panelmessage(1,0,TX("Plugin working ..."));                                         //  25.1
   Fblock("plugin");
   basetime = get_seconds();                                                           //  basetime = NOW
   err = zshell("log ack thread",command);                                             //  execute plugin command, return        25.1
   panelmessage(0);
   Fblock(0);

   if (err) {
      zmessageACK(Mwin,TX("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,TX("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,TX("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,TX("output file size change, cannot use select area"));
      else sa_postfix();
   }

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

   edit_done(0);

   remove(outfile);

   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, uint 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, err;
   FILE     *fid;
   STATB    statB;
   uint     modtime = basetime;
   uint     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," ","\\ ","\"","\\\"","'","\\'",null);              //  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
   printf("%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
      err = stat(pp1,&statB);                                                          //  26.0
      if (err) continue;
      modtimex = statB.st_mtim.tv_sec;                                                 //  file mod time
      if (modtimex < modtime) continue;                                                //  older than me
      strncpy0(outfile,pp1,XFCC);                                                      //  save latest file found
      modtime = modtimex;
   }
   pclose(fid);

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


