/*
 * $Id: menubar.cxx,v 4.7 2003/09/14 14:55:30 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  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 2 of the License, or
 *  (at your option) any later version.
 *  
 *  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.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 *  The menu portion of imView, an image viewer program for X11
 *  by Hugues Talbot    26 Oct 1997
 *
 * This program is available free of charge for anyone to use under no
 * guarantee of any kind, expressed or implied.
 *
 *-----------------------------------------------------------------------*/


#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_File_Chooser.H>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imview.hxx"
#include "imageIO.hxx"
#include "pointfile.hxx"
#include "imageViewer.hxx"
#include "menubar.hxx"

// components of the application
extern imageViewer   *mainViewer;
extern char           appName[];
extern imViewMenuBar *mainMenuBar;
extern imageIO       *IOBlackBox;
extern pointfile     *PtFileMngr;

// other global flags
extern int            debugIsOn;
extern int            stopDebug;
extern bool           lutWraparound;
extern volatile bool  syncDisplay;
extern bool           disableMainMenu;
extern int            makeImageCharIfFits;
extern int            RGBdisplaysRGB;
extern int            fitCharOverAllSamples;
extern int            fitCharOverAllSlices;
extern bool           hideMainMenu;
extern bool           fullScreen;
extern displaymode    displaymodepref;

// went the easy way on that one:
extern double         persistentGamma;

imViewMenuBar::imViewMenuBar(int x, int y, int w, int h, const char *label)
    : Fl_Menu_Bar(x,y,w,h,label)
{
    int i, menusize;
    Fl_Menu_Item startmenu[] = { // this menu is only temporary
        {"&File", 0, 0, 0, FL_SUBMENU},                                            
	    {"Open", FL_ALT+'o', open_cb},
            {CLOSE_ITEM, FL_ALT+'c', close_cb, 0, FL_PUP_GREY},
	    {SAVE_ITEM, FL_ALT+'s', save_cb, 0, FL_PUP_GREY},
	    {OVERLAY_SUBMENU, 0, 0, 0, FL_PUP_GREY | FL_SUBMENU | FL_MENU_DIVIDER},
	        {OPEN_OVERLAY_ITEM, FL_ALT+'v', openoverlay_cb, 0, 0},
	        {CLOSE_OVERLAY_ITEM, FL_ALT+FL_SHIFT+'v', closeoverlay_cb, 0, 0},
	        {0},
	    {PRINTPREFS_ITEM, FL_CTRL+FL_SHIFT+'p', printprefs_cb, 0, FL_PUP_GREY | FL_MENU_DIVIDER},
	    {"Quit", FL_ALT+'q', quit_cb},
            {0},
        {"&Edit", 0, 0, 0, FL_SUBMENU},
            {"Undo", 0, test_cb, 0, FL_PUP_GREY},
	     {"Quick &options", 0, 0, 0, FL_SUBMENU},
	        {"Display mode", 0, 0, 0, FL_SUBMENU},
	            {WIN_FIT_IMG_ITEM, 0, displaymode_cb, (void*)IMV_DISPLAY_WINDOW_FIT_IMG, FL_MENU_RADIO | (displaymodepref == IMV_DISPLAY_WINDOW_FIT_IMG) ? FL_MENU_VALUE:0},
	            {IMG_FIT_WIN_ITEM, 0, displaymode_cb, (void*)IMV_DISPLAY_IMG_FIT_WINDOW, FL_MENU_RADIO | (displaymodepref == IMV_DISPLAY_IMG_FIT_WINDOW) ? FL_MENU_VALUE:0},
	            {DECOUPLE_IMG_WIN_ITEM, 0, displaymode_cb, (void*)IMV_DISPLAY_DECOUPLE_WIN_IMG, FL_MENU_RADIO | FL_MENU_DIVIDER | (displaymodepref == IMV_DISPLAY_DECOUPLE_WIN_IMG) ? FL_MENU_VALUE:0},
	            {"Fullscreen", 0, preference_cb, (void *)PREF_FULLSCREEN, FL_PUP_BOX | (fullScreen ? FL_MENU_VALUE:0)},
	        {0},
                {"Hide main menu bar", FL_ALT+'m', preference_cb, (void *)PREF_HIDEMENU, FL_PUP_BOX | (hideMainMenu ? FL_MENU_VALUE:0)},
                {WRAPLUT_ITEM, 0, preference_cb, (void *)PREF_WRAPAROUND,  FL_PUP_BOX | (lutWraparound ? FL_MENU_VALUE:0)},
                {SYNCDISP_ITEM, 0, preference_cb, (void *)PREF_SYNCDISP,  FL_PUP_BOX | (syncDisplay ? FL_MENU_VALUE:0)},
                {"Cast to CHAR if possible", 0, preference_cb, (void *)PREF_MAKECHAR,  FL_PUP_BOX | (makeImageCharIfFits ? FL_MENU_VALUE:0)},
	        {"RGB images display as RGB", 0, preference_cb, (void *)PREF_RGBRGB,  FL_PUP_BOX | (RGBdisplaysRGB ? FL_MENU_VALUE:0) },
	        {"Fit to CHAR over all samples", 0, preference_cb, (void *)PREF_FITALL,  FL_PUP_BOX | (fitCharOverAllSamples ? FL_MENU_VALUE:0) },
	        {"Fit to CHAR over all slices (3D)", 0, preference_cb, (void *)PREF_FIT3D,  FL_PUP_BOX | (fitCharOverAllSlices ? FL_MENU_VALUE:0) | FL_MENU_DIVIDER }, 
//	        {"Smooth when zooming out", 0, preference_cb, (void *)PREF_SMOOTHUNZOOM, FL_PUP_BOX},
		{"Show warnings", FL_ALT+FL_SHIFT+'w', preference_cb, (void *)PREF_WARNING, 0},
                {"Enable debug messages", FL_CTRL+FL_SHIFT+'g', preference_cb, (void *)PREF_DEBUG, FL_PUP_BOX | (debugIsOn? FL_MENU_VALUE:0)},
	        {"Stop after debug messages", FL_CTRL+FL_SHIFT+'s', preference_cb, (void *)PREF_STOPDEBUG, FL_PUP_BOX | (stopDebug ? FL_MENU_VALUE:0)},
//                {"Keep points when switching images", FL_ALT+'K', preference_cb, (void *)PREF_KEEPPOINTS, FL_PUP_BOX | FL_MENU_DIVIDER},
//	        {"Change XOR value for lines...", 0, setxorvalue_cb, 0, 0},
	        {0},
	    {"&User preferences...", 0, userprefspanel_cb},
	    {0},
        {"&Transform", 0, 0, 0, FL_SUBMENU},
	    {"Toolbar...", FL_SHIFT+'t', toolbar_cb, 0, FL_MENU_DIVIDER}, 
            {COLOURMAP_ITEM, 0, 0, 0, FL_PUP_GREY | FL_SUBMENU},
                {CLUT_LIST_BEGIN, FL_ALT+FL_SHIFT+'c', noclut_cb, 0, 0}, 
	        /* rest of CLUT list comes here */
	        {0},
            {"Zoom", 0, 0, 0, FL_SUBMENU},
                {"Zoom in 100%", FL_ALT+'>',   zoomin_cb},
                {"Zoom in 10%", FL_ALT+'.',   smallzoomin_cb},
                {"Zoom out 100%", FL_ALT+'<',  zoomout_cb},
	        {"Zoom out 10%", FL_ALT+',',  smallzoomout_cb},
	        {"Set this zoom factor as default", FL_ALT+'\'', thiszoom_cb},
	        {"Select zoom factor...", FL_ALT+'z', selectzoom_cb},
	        {"Select default zoom factor...", FL_ALT+FL_SHIFT+'z', selectdefaultzoom_cb},
                {"Apply default zoom factor", FL_ALT+'n',  unzoom_cb},
                {0},
	    {"Rotate", 0, 0, 0, FL_SUBMENU},
	        {"Right 90 degree",  FL_ALT+'(', rotate90right_cb},
	        {"Left 90 degree", FL_ALT+')', rotate90left_cb},
	        {"180 degree", FL_ALT+'+', rotate180_cb},
                {ROTATE3DMENU_ITEM, 0, 0, 0, FL_SUBMENU|FL_PUP_INVISIBLE},
                    {"Up 90 degree", 0, rotate3dup_cb},
                    {"Down 90 degree", 0, rotate3ddown_cb},
                    {0},
	        {0},
	    {"Flip", 0, 0, 0, FL_SUBMENU},
	        {"Vertically",  FL_ALT+'|', flipv_cb},
	        {"Horizontally", FL_ALT+'_', fliph_cb},
	        {0},
	    {"Pointfile", 0, 0, 0, FL_SUBMENU},
	        {"Add point mode", FL_CTRL+'g', mode_cb, (void *)MODE_POINTFILE, FL_PUP_BOX | FL_MENU_DIVIDER},
	        {"Open existing pointfile...", FL_CTRL+'p', openpointfile_cb}, 
                {"New pointfile", FL_ALT+'p', newpointfile_cb},
                {"Save current pointfile", FL_ALT+FL_SHIFT+'p', closepointfile_cb},
                {"Delete all points", FL_ALT+FL_SHIFT+'d', deleteallpoints_cb},
                {"Delete last point", FL_ALT+'d', deletelastpoint_cb},
	        {0},
	    {"Histogram", 0, 0, 0, FL_SUBMENU},
	        {"Contrast-Brightness", FL_ALT+'b', transfer_cb},
	        {RGBTRANSFER_ITEM, FL_ALT+FL_SHIFT+'b', transferRGB_cb, 0, FL_PUP_INVISIBLE},
	        {BIVHIST_ITEM, FL_ALT+'L', showbivhist_cb, 0, FL_PUP_INVISIBLE},
	        {"Interactive thresholding", FL_ALT+'h', threshold_cb, 0, FL_PUP_GREY},
	        {0},
	    {0},   
        {"&Image", 0, 0, 0, FL_SUBMENU},
	    {"Information...",FL_SHIFT+'i', imageinfo_cb},
	    {"1-D profile...", '1', showprofile_cb, 0, FL_MENU_DIVIDER},
	    {"Server", 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER},
	        {"Progress", 0, showprogress_cb, 0, 0},
	        {"Start", 0, startserver_cb, 0,  FL_PUP_INVISIBLE},
	        {"Stop", 0, stopserver_cb, 0, FL_PUP_INVISIBLE},
	        {0},
	    {HYPERSPECTRAL_ITEM, FL_ALT+FL_SHIFT+'s', showspectrum_cb, 0, FL_PUP_INVISIBLE},
	    {NEXTCOMPONENT_ITEM, FL_Home, nextcomponent_cb, 0, FL_PUP_INVISIBLE},
	    {PREVIOUSCOMPONENT_ITEM, FL_End, previouscomponent_cb, 0, FL_PUP_INVISIBLE},
	    {SELECTCOMPONENT_ITEM, FL_Scroll_Lock, selectcomponent_cb, 0, FL_PUP_INVISIBLE | FL_MENU_DIVIDER},
	    {DEPTHPROFILE_ITEM, FL_ALT+FL_SHIFT+'d', showdepthprofile_cb, 0, FL_PUP_INVISIBLE},
            {NEXTPLANE_ITEM, FL_Insert, nextplane_cb, 0, FL_PUP_INVISIBLE},
	    {PREVIOUSPLANE_ITEM, FL_Delete, previousplane_cb, 0, FL_PUP_INVISIBLE},
	    {SELECTPLANE_ITEM, FL_Print, selectplane_cb, 0, FL_PUP_INVISIBLE | FL_MENU_DIVIDER},
	    {NEXTFRAME_ITEM, FL_Page_Up, nextframe_cb, 0, FL_PUP_INVISIBLE},
	    {PREVIOUSFRAME_ITEM, FL_Page_Down, previousframe_cb, 0, FL_PUP_INVISIBLE},
	    {SELECTFRAME_ITEM, FL_Pause, selectframe_cb, 0, FL_PUP_INVISIBLE | FL_MENU_DIVIDER},
	    {NEXTIMAGE_ITEM, ' ', nextimage_cb, 0, FL_PUP_GREY},
	    {PREVIOUSIMAGE_ITEM, FL_SHIFT+' ', previousimage_cb, 0, FL_PUP_GREY | FL_MENU_DIVIDER},
	    {IMAGE_LIST_BEGIN, 0, 0, 0, FL_PUP_GREY | FL_SUBMENU},
	        /* originally empty image list goes here */	
                {0},
            {0},
        {"&Help", 0, 0, 0, FL_SUBMENU},
	    {"About imview...", 0, whodunit_cb, 0, FL_MENU_DIVIDER},
	    {"Quick online help", '?', onlinehelp_cb, 0, 0},
            {"Full HTML documentation", FL_ALT+'?', fulldocument_cb, 0, FL_MENU_DIVIDER},
	    {"Licence...", 0, licence_cb, 0, 0},
	    {"(No) warranty...", 0, warranty_cb, 0, 0},
	    {0},
        {0}
    };

    
    dbgprintf("imViewMenuBar constructed\n");

    // set things up for the image list
    listName[IMAGE_LIST_ID] = IMAGE_LIST_BEGIN;
    listCallback[IMAGE_LIST_ID] = (void *)image_cb;
    // set things up for the colour LUT list
    listName[CLUT_LIST_ID] = CLUT_LIST_BEGIN;
    listCallback[CLUT_LIST_ID] = (void *)clut_cb;

    // Create the start menu
    menu(startmenu);
    // allocated the dynamic menu
    menusize = size();
    dbgprintf("Menu size = %d\n", menusize);
    dynamicMenu = new Fl_Menu_Item[menusize];
    for (i = 0 ; i < menusize ; i++) {
        dynamicMenu[i] = startmenu[i];
        if (disableMainMenu) {
            dynamicMenu[i].flags |= FL_MENU_INACTIVE;
        } 
    }
    menu(dynamicMenu); // from now on we can forget about the old menu
    nbImagesInList = 0;

    return;
}

imViewMenuBar::~imViewMenuBar()
{
    delete[] dynamicMenu;
    dbgprintf("Menu bar destructor called\n");
}


void imViewMenuBar::draw()
{
    //    if (hideMainMenu) 
    //    resize(x(),y(),w(),0); // ??
    //else
    //    resize(x(),y(),w(),MENUHEIGHT);

    Fl_Menu_Bar::draw();
}

// returns 1 if the item is effectively added to the list
// 0 otherwise (item already in item list or invalid)
int imViewMenuBar::addToItemList(const char *newImagePath, int listID)
{
    int i, j, res = 0;
    int newSize;
    const char    *shortname;
    Fl_Menu_Item *oldMenu;
    IMAGEPARM *itx;

    if ((newImagePath[0] != '\0') && (!isAlreadyInItemList(newImagePath,listID))) {
        oldMenu = dynamicMenu;
        dbgprintf("adding %s to the %s list\n", newImagePath, listName[listID]);
        newSize = size() + 1;
        dbgprintf("Menu will have %d items\n", newSize);
        dynamicMenu = new Fl_Menu_Item[newSize];
        for (i = 0, j = 0 ; i < newSize-1 ; i++, j++) {
            dynamicMenu[j] = oldMenu[i];
            if ((oldMenu[i].label() != 0) && (strcmp(oldMenu[i].label(), listName[listID]) == 0)) {
                // activate the current item 
                dynamicMenu[j].flags &= ~FL_MENU_INACTIVE;
		i++; j++; // go to the next field
		// look for the `0' finishing the menu
		for ( ; i < newSize-1 ; i++, j++) {
		    dynamicMenu[j] = oldMenu[i]; // keep filling the menu
		    if ((dynamicMenu[j].label() != 0) 
			&& (dynamicMenu[j].callback() == (Fl_Callback *)listCallback[listID])) {
			// uncheck the check box for those items
			dynamicMenu[j].flags &= ~FL_PUP_CHECK;
		    } else 
			break;
		}
                // fill the  new struct by hand
                itx = new IMAGEPARM;
                itx->itempath =  strdup(newImagePath);
                itx->clutpath = 0;
		itx->ovlpath = 0;
		itx->pfpath = 0;
                itx->gamma = persistentGamma; // may not be 1.0!
		itx->contrast = 0.5;
		itx->brightness = 0.5;
		itx->Rgamma = itx->Ggamma = itx->Bgamma = itx->gamma;
		itx->Rcontrast = itx->Gcontrast = itx->Bcontrast = itx->contrast;
		itx->Rbrightness = itx->Gbrightness = itx->Bbrightness = itx->brightness;
                itx->zslice = 0;
		itx->comp = 0;
		itx->frame = 0;
		itx->nbframes = 0;
		itx->angle = 0;
		itx->mirror = 0;
                itx->next = 0;
                shortname = strrchr(itx->itempath, '/'); // look for the last `/'
                if (shortname == NULL) 
                    shortname = itx->itempath; // revert to full name if name is local 
                else
                    shortname++; // go beyond the last `/'
		dynamicMenu[j+1] = oldMenu[i];
		dynamicMenu[j] = dynamicMenu[0]; // to reset all the fields
                dynamicMenu[j].label(shortname);
                dynamicMenu[j].shortcut(0);
                dynamicMenu[j].callback((Fl_Callback *)(listCallback[listID]));
		dynamicMenu[j].user_data((void *)itx);
                dynamicMenu[j].flags = (FL_PUP_BOX | FL_PUP_CHECK);
		// advance to the next one
		j++;
            } 
        }
        // specific issue for separate lists
        if (listID == IMAGE_LIST_ID) {
            // we have positively added an item to the image menu, therefore
            // the `close' item can be enabled
            setFlagsByName(CLOSE_ITEM, 0, dynamicMenu, newSize);
	    setFlagsByName(SAVE_ITEM, 0, dynamicMenu, newSize);
	    setFlagsByName(OVERLAY_SUBMENU, FL_SUBMENU | FL_MENU_DIVIDER, dynamicMenu, newSize);
	    setFlagsByName(PRINTPREFS_ITEM, FL_MENU_DIVIDER, dynamicMenu, newSize);
            // as well as the colour map button
            setFlagsByName(COLOURMAP_ITEM, FL_SUBMENU, dynamicMenu, newSize);
	    // increase the counter of images in the list
	    nbImagesInList++;
        }
        delete[] oldMenu;
        menu(dynamicMenu);
	int sz = size();
	dbgprintf("Menu size is now: %d\n", sz);
        redraw();
	res = 1; // yes, we have added an item
    } else { // isAlreadyInItemList(newImagePath,listID) is true
        // either the image is already in the image list: we only have to check the right item
        // or the newImagePath argument is the empty string. In this case
        // we want to unselect all the items.
	int sz = size();
        for (i = 0 ; i < sz  ; i++) {
            if ((dynamicMenu[i].label() != 0) 
		&& (dynamicMenu[i].callback() == (Fl_Callback *)listCallback[listID])) {
                dynamicMenu[i].flags &= ~FL_PUP_CHECK;
                if (((unsigned int)dynamicMenu[i].user_data() > LAST_INT_ARG)
		    && (strcmp((char*)((IMAGEPARM *)dynamicMenu[i].user_data())->itempath, newImagePath) == 0))
                    dynamicMenu[i].flags |= FL_PUP_CHECK;
            }
        }
    }
    return res;
}


void imViewMenuBar::removeFromItemList(const char *oldImagePath, int listID)
{
    int           i, j;
    int           newSize;
    Fl_Menu_Item *oldMenu;
    char         *to_be_freed_later = 0;
    
    if (isAlreadyInItemList(oldImagePath,listID)) {
        // this is fine, we can remove it from the list!
        oldMenu = dynamicMenu;
        dbgprintf("removing %s from the image list\n", oldImagePath);
        newSize = size() - 1 ;
        dbgprintf("Menu will have %d items\n", newSize);
        dynamicMenu = new Fl_Menu_Item[newSize];
        for (i = 0, j = 0 ; i <= newSize ; i++, j++) {
            if (((unsigned int)oldMenu[i].user_data() > LAST_INT_ARG)
                && (strcmp(((IMAGEPARM *)oldMenu[i].user_data())->itempath, oldImagePath) == 0)) {
                // now selects the closest image in the image list
                if (oldMenu[i+1].label() != 0) {
                    // the next image down the list gets selected
                    oldMenu[i+1].flags |= (FL_PUP_BOX | FL_PUP_CHECK); // copy to dynamicMenu will occur later
                } else if ((oldMenu[i-1].label() != 0) && (strcmp(oldMenu[i-1].label(), listName[listID]) != 0)) {
                    // the previous image up the list gets selected
                    dynamicMenu[i-1].flags |= (FL_PUP_BOX | FL_PUP_CHECK);
                } else {
                    // the image we remove was the last on the list, disable `Image' menu
                    dynamicMenu[i-1].flags |= (FL_PUP_GREY);
                    if (listID == IMAGE_LIST_ID) {
                        // disable the `close' item
                        setFlagsByName(CLOSE_ITEM, FL_PUP_GREY, dynamicMenu, newSize);
			setFlagsByName(SAVE_ITEM, FL_PUP_GREY, dynamicMenu, newSize);
			setFlagsByName(OVERLAY_SUBMENU, FL_PUP_GREY | FL_SUBMENU | FL_MENU_DIVIDER, dynamicMenu, newSize);
			setFlagsByName(PRINTPREFS_ITEM, FL_PUP_GREY  | FL_MENU_DIVIDER, dynamicMenu, newSize);
                        // and the Colourmap item
                        setFlagsByName(COLOURMAP_ITEM, FL_PUP_GREY | FL_SUBMENU, dynamicMenu, newSize);
                    }
                }
                // this had been strdup'ed
		IMAGEPARM *pp = (IMAGEPARM *)oldMenu[i].user_data();
		if (pp->itempath != oldImagePath) { // we need the old path a bit longer.
		    free(pp->itempath);
		    pp->itempath = 0;
		} else {
		    to_be_freed_later = pp->itempath; // man, isn't that dangerous?
		}
		if (pp->ovlpath) {
		    free(pp->ovlpath);
		    pp->ovlpath = 0;
		}
		if (pp->pfpath) {
		    free(pp->pfpath);
		    pp->pfpath = 0;
		}
                // this had been new'ed
                delete (IMAGEPARM *)oldMenu[i].user_data();
		//oldMenu[i].argument = 0; // otherwise FL will think it is still there...
		//oldMenu[i].text = 0; // this was a substring allocated in the argument
                // skip the name
                i++;
            }
            // business as usual
            dynamicMenu[j] = oldMenu[i];
        }
        delete[] oldMenu;
        menu(dynamicMenu);
	int sz = size();
	dbgprintf("Menu size after deletion is now: %d\n", sz);
	// one more dangerous thing to do
	if (to_be_freed_later != 0) {
	    free(to_be_freed_later);
	    to_be_freed_later = 0;
	}
        redraw();
    }
    // we've got nothing to do, the name in question is not in the list

    return;
}

int imViewMenuBar::isAlreadyInItemList(const char *newImagePath, int listID)
{
    int res = 0;
    int i;

    dbgprintf("Checking if new name already in %s\n", listName[listID]);

    if (newImagePath) { // check that a name was actually given...
        for (i = 0 ; i < size() ; i++) 
            if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
                i++;
                break;
            }

        if (i != size()) {
            for ( ; (unsigned int)dynamicMenu[i].user_data() > LAST_INT_ARG ; i++) {
                if (strcmp(((IMAGEPARM *)dynamicMenu[i].user_data())->itempath, newImagePath) == 0) {
		    dbgprintf("Name %s is already in list at position %d\n",
			      newImagePath, i);
                    res = 1; // the new name is already in the list
                    break;
                }
            }
        }
    }
    return res;
}

// return the first item matching the given label
void *imViewMenuBar::getItemByLabel(const char *givenLbl, int listID)
{
    void *res = 0;
    int i;
    
    dbgprintf("Looking for %s in list %s\n", givenLbl, listName[listID]);

    if (givenLbl) { // check that a name was actually given...
        for (i = 0 ; i < size() ; i++) 
            if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
                i++;
                break;
            }

        if (i != size()) {
            for ( ; (unsigned int)dynamicMenu[i].user_data() > LAST_INT_ARG ; i++) {
                if (strcmp(dynamicMenu[i].label(), givenLbl) == 0) {
		    dbgprintf("Found %s in list at position %d\n",
			      givenLbl, i);
                    res = (void*)dynamicMenu[i].user_data(); // the label was found, first item returned.
                    break;
                }
            }
        }
    }
    return res;
}

char *imViewMenuBar::getItemListContent(int listID, int &nbitems)
{
    int   i, j, outlength, sz;
    char *res = 0;

    nbitems = 0;
    dbgprintf("Saving the content of list #%d to a string\n", listID);

    sz = size();
    for (i = 0 ; i < sz ; i++)
	if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
                i++;
                break;
            }

    if (i != size()) {
	for (j = i, outlength = 0 ; (unsigned int)dynamicMenu[j].user_data() > LAST_INT_ARG ; j++)
	    outlength += strlen(((IMAGEPARM *)dynamicMenu[j].user_data())->itempath);

	if (outlength > 0) {
	    res = new char[outlength+j+1];
	    res[0] = '\0';
	    for (j = i ; (unsigned int)dynamicMenu[j].user_data() > LAST_INT_ARG ; j++) {
		strcat(res, ((IMAGEPARM *)dynamicMenu[j].user_data())->itempath);
		strcat(res, "\n");
		nbitems++;
	    }
	}
    }

    return res;
}

void *imViewMenuBar::getSelectedItemArgument(int listID)
{
    void *res = 0;
    int i, sz;
    
    dbgprintf("Looking for path of image being currently selected\n");

    sz = size();
    // look for where the image list begins
    for (i = 0 ; i < sz; i++) {
        if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
            i++;
            break;
        }
    }
	
    if (i != sz) {
        for ( ; dynamicMenu[i].label() != 0 ; i++) {
            if (dynamicMenu[i].flags == (FL_PUP_BOX | FL_PUP_CHECK)) {
                res = (void *)dynamicMenu[i].user_data(); // the new name is already in the list
                break;
            }
        }
    }
    
    return res;
}

Fl_Menu_Item *imViewMenuBar::getSelectedMenuItem(int listID)
{
    int i;
    Fl_Menu_Item *res = 0;

    dbgprintf("Looking for menu item currently selected in list %s\n", listName[listID]);
    
    // look for where the image list begins
    for (i = 0 ; i < size(); i++)
        if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
            i++;
            break;
        }

    if (i != size()) {
        for ( ; dynamicMenu[i].label() != 0 ; i++) {
            if (dynamicMenu[i].flags == (FL_PUP_BOX | FL_PUP_CHECK)) {
                res = dynamicMenu+i; // the new name is already in the list
                break;
            }
        }
    }
    
    return res;

}

// returns the argument to the next image in the image list if possible
// else returns the argument to the first image, and otherwise returns NULL
void *imViewMenuBar::getNextItemInList(int listID)
{
    void *res = 0;
    int i, startimage;
    
    // look for where the image list begins
    for (i = 0 ; i < size(); i++)
        if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
            i++;
            break;
        }

    startimage = i;
    
    if (i != size()) {
        for ( ; dynamicMenu[i].label() != 0 ; i++) {
            // look for the image name that is currently checked
            if (dynamicMenu[i].flags == (FL_PUP_BOX | FL_PUP_CHECK)) {
                if (dynamicMenu[i+1].label() != 0)
                    res =  (void *)dynamicMenu[i+1].user_data(); // open next one on the list
                else if (dynamicMenu[startimage].label() != 0)
                    res =  (void *)dynamicMenu[startimage].user_data(); // open first image on the list
                break;
            }
        }
    }

    return res;
}

// returns the path to the next image in the image list if possible
// else returns the path to the first image, and otherwise returns NULL
void *imViewMenuBar::getPreviousItemInList(int listID)
{
    void *res = 0;
    int i, lastimage, checkedimage;
    
    // look for where the image list begins
    for (i = 0 ; i < size(); i++)
        if ((dynamicMenu[i].label() != 0) && (strcmp(dynamicMenu[i].label(), listName[listID]) == 0)) {
            i++;
            break;
        }

    checkedimage = 0;
    // look for the last image
    for ( ; dynamicMenu[i].label() != 0 ; i++) {
        if (dynamicMenu[i].flags == (FL_PUP_BOX | FL_PUP_CHECK)) {
            checkedimage = i;
        }
    }
        
    lastimage = i-1;

    if (checkedimage != 0) {
        if ((dynamicMenu[checkedimage-1].label() != 0) && (strcmp(dynamicMenu[checkedimage-1].label(), listName[listID]) != 0))
            res = (void *)dynamicMenu[checkedimage-1].user_data(); // open previous one on the list
        else if (dynamicMenu[lastimage].label() != 0)
            res = (void *)dynamicMenu[lastimage].user_data(); // open last image on the list
        else
            res = 0;
    }
    
    return res;
}

// this functions hunts for a named menu element and returns its flags
int imViewMenuBar::getFlagsByName(const char *theName, Fl_Menu_Item *currentMenu, int menuSize)
{
    int i, theFlags = -1;

    if (currentMenu == 0)
        currentMenu = dynamicMenu;
    if (menuSize == 0)
        menuSize = size();

    for (i = 0 ; i < menuSize ; i++)
        if ((currentMenu[i].label() != 0) && (strcmp(currentMenu[i].label(), (char *)theName) == 0)) {
            theFlags = currentMenu[i].flags;
            break; // only change the first occurence... Normally no two menu items have the same name
        }
    
    return theFlags;
}

// this functions hunts for a named menu element and changes its flags
void imViewMenuBar::setFlagsByName(const char *theName, int theFlags, Fl_Menu_Item *currentMenu, int menuSize)
{
    int i;

    if (currentMenu == 0)
        currentMenu = dynamicMenu;
    if (menuSize == 0)
        menuSize = size();
    
    for (i = 0 ; i < menuSize ; i++)
        if ((currentMenu[i].label() != 0) && (strcmp(currentMenu[i].label(), (char *)theName) == 0)) {
            currentMenu[i].flags = theFlags;
            break; // only change the first occurence... Normally no two menu items have the same name
        }
    
    return;
}

