/*
 * $Id: transferRGBFunction.cxx,v 4.0 2003/04/28 14:40:15 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 long-awaited RGB contrast/brightness/gamma control panel
 *
 * Hugues Talbot	30 Oct 2001
 *      
 *-----------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <FL/math.h>
#include "imview.hxx"
#include "imageIO.hxx"
#include "transferFunction.hxx"
#include "transferRGBFunction.hxx"

extern imageIO *IOBlackBox;
extern transferRGB *transferRGBEditorPanel;
extern int applyTransferToAll;

extern double persistentGamma;

transferRGB::transferRGB()
{
    dbgprintf("RGB Transfer function dialog created\n");
    RGBtransferWindow = 0; // fluid depends on that.
    RGBtransferBox = 0;
    transferRGBHistoBox = 0;
    transferRGBFunctionBox = 0;
    return;
}

transferRGB::~transferRGB()
{
    if (transferRGBHistoBox != 0) {
	delete transferRGBHistoBox;
	transferRGBHistoBox = 0;
    }

    return;
}

void transferRGB::setDefaults()
{
    static char buff[100];
    
    static const Fl_Menu_Item displayMenu[] = {
	{"RGB Transfer function", 0, (Fl_Callback *)RGBchosendisplay_cb, (void *)TRANSFER_DSP},
	{"RGB Histogram", 0, (Fl_Callback *)RGBchosendisplay_cb, (void *)HISTOGRAM_DSP},
	{0}
    };

    dbgprintf("Setting up defaults for RGB transfer panel\n");
    displayChoice->menu(displayMenu);

    // set up sliders array (they've been allocated by now)
    contrastSliders[0] = RcontrastSlider;
    contrastSliders[1] = GcontrastSlider;
    contrastSliders[2] = BcontrastSlider;

    brightnessSliders[0] = RbrightnessSlider;
    brightnessSliders[1] = GbrightnessSlider;
    brightnessSliders[2] = BbrightnessSlider;

    gammaSliders[0] = RgammaSlider;
    gammaSliders[1] = GgammaSlider;
    gammaSliders[2] = BgammaSlider;

    // button array
    linkButtons[0] = linkRButton;
    linkButtons[1] = linkGButton;
    linkButtons[2] = linkBButton;

    // inputs
    topInputs[0] = RtopInput;
    topInputs[1] = GtopInput;
    topInputs[2] = BtopInput;
    bottomInputs[0] = RbottomInput;
    bottomInputs[1] = GbottomInput;
    bottomInputs[2] = BbottomInput;
    leftInputs[0] = RleftInput;
    leftInputs[1] = GleftInput;
    leftInputs[2] = BleftInput;
    rightInputs[0] = RrightInput;
    rightInputs[1] = GrightInput;
    rightInputs[2] = BrightInput;
    gammaInputs[0] = RgammaInput;
    gammaInputs[1] = GgammaInput;
    gammaInputs[2] = BgammaInput;
    

    // set range, etc, for sliders...
    RcontrastSlider->minimum(-1.05);
    RcontrastSlider->maximum(1.0);
    RcontrastSlider->value(0.5);
    RcontrastSlider->step(0.005);

    GcontrastSlider->minimum(-1.05);
    GcontrastSlider->maximum(1.0);
    GcontrastSlider->value(0.5);
    GcontrastSlider->step(0.005);

    BcontrastSlider->minimum(-1.05);
    BcontrastSlider->maximum(1.0);
    BcontrastSlider->value(0.5);
    BcontrastSlider->step(0.005);

    //
    RbrightnessSlider->minimum(1.0);
    RbrightnessSlider->maximum(0);
    RbrightnessSlider->value(0.5);
    RbrightnessSlider->step(0.005);
    
    GbrightnessSlider->minimum(1.0);
    GbrightnessSlider->maximum(0);
    GbrightnessSlider->value(0.5);
    GbrightnessSlider->step(0.005);

    BbrightnessSlider->minimum(1.0);
    BbrightnessSlider->maximum(0);
    BbrightnessSlider->value(0.5);
    BbrightnessSlider->step(0.005);

    //
    RgammaSlider->minimum(1.0);
    RgammaSlider->maximum(-1.0);
    RgammaSlider->value(log(persistentGamma));  // this is what I mean by persistent
    RgammaSlider->step(0.01);
    
    GgammaSlider->minimum(1.0);
    GgammaSlider->maximum(-1.0);
    GgammaSlider->value(log(persistentGamma));  // this is what I mean by persistent
    GgammaSlider->step(0.01);
    
    BgammaSlider->minimum(1.0);
    BgammaSlider->maximum(-1.0);
    BgammaSlider->value(log(persistentGamma));  // this is what I mean by persistent
    BgammaSlider->step(0.01);

    // writing default gamma
    sprintf(buff, "%g", persistentGamma);
    RgammaInput->value(buff);
    GgammaInput->value(buff);
    BgammaInput->value(buff);
    // writing default parameters
    sprintf(buff, "255");
    // top
    RtopInput->value(buff);
    GtopInput->value(buff);
    BtopInput->value(buff);
    // right
    RrightInput->value(buff);
    GrightInput->value(buff);
    BrightInput->value(buff);

    sprintf(buff, "0");
    // bottom
    RbottomInput->value(buff);
    GbottomInput->value(buff);
    BbottomInput->value(buff);
    // left
    RleftInput->value(buff);
    GleftInput->value(buff);
    BleftInput->value(buff);

    // link all sliders by default
    linkRButton->set();
    linkGButton->set();
    linkBButton->set();

    // allocate and set the parameters of the histobox;
    if (transferRGBHistoBox == 0) {
	int x,y,w,h;
	x = RGBtransferBox->x();
	y = RGBtransferBox->y();
	w = RGBtransferBox->w();
	h = RGBtransferBox->h();
	// same dimensions
	transferRGBHistoBox = new myTransferRGBHistoBox(x,y,w,h);
	// same box
	transferRGBHistoBox->box(RGBtransferBox->box());
	// same colour
	transferRGBHistoBox->color(RGBtransferBox->color());
	// same user data
	transferRGBHistoBox->user_data((void *)this);
    }

    if (transferRGBFunctionBox == 0) {
	int x,y,w,h;
	x = RGBtransferBox->x();
	y = RGBtransferBox->y();
	w = RGBtransferBox->w();
	h = RGBtransferBox->h();
	// same dimensions
	transferRGBFunctionBox = new myTransferRGBFunctionBox(x,y,w,h);
	// same box
	transferRGBFunctionBox->box(RGBtransferBox->box());
	// same colour
	transferRGBFunctionBox->color(RGBtransferBox->color());
	// same user data
	transferRGBFunctionBox->user_data((void *)this);
    }

    // replace the generic transferBox by the one we want
    displayBoxGroup->remove(RGBtransferBox);
    displayBoxGroup->add(transferRGBFunctionBox);
    RGBmemoryBox = RGBtransferBox; // the one allocated by fluid, we don't want it.
    // but we can't delete it...
    RGBtransferBox = transferRGBFunctionBox;
    
    setDrawingParms();

    if (persistentGamma != 1.0) {
	dbgprintf("Forcing the recalculation of the transfer map \n");
	RGBtransferBox->forceBuildMap();
	dbgprintf("Forcing redisplay of the main image \n");
	RGBtransferBox->causeMainWindowRedraw();
	// force the recalculation of the map LUT
    }
    
    return;
}

void transferRGB::setTransfer()
{
    if (RGBtransferBox == transferRGBHistoBox) {
	displayBoxGroup->remove(transferRGBHistoBox);
	displayBoxGroup->add(transferRGBFunctionBox);
	RGBtransferBox = transferRGBFunctionBox;
    }
    // copy the changes in parameters that may have
    // occured with the other type of display...
    setDrawingParms();
    RGBtransferWindow->redraw();
}

void transferRGB::setHisto()
{
    if (RGBtransferBox == transferRGBFunctionBox) {
	displayBoxGroup->remove(transferRGBFunctionBox);
	displayBoxGroup->add(transferRGBHistoBox);
	RGBtransferBox = transferRGBHistoBox;
    }
    // copy the changes in parameters that may have
    // occured with the other type of display...
    setDrawingParms(); 
    transferRGBHistoBox->makeHisto();
    RGBtransferWindow->redraw();
}

// compute the drawing parms from the Input (top,bottom, etc) values.
void transferRGB::computeDrawingParms()
{
    int topv, bottomv, rightv, leftv;
    double newbrightness = 0.5, newcontrast = 0.5;

    for (int i = 0 ; i < 3 ; ++i) {
	topv = atoi(topInputs[i]->value());
	bottomv = atoi(bottomInputs[i]->value());
	rightv = atoi(rightInputs[i]->value());
	leftv = atoi(leftInputs[i]->value());
	if (topv < 0) {
	    topv = 0;
	    topInputs[i]->value("0");
	}
	if (topv > 255) {
	    topv = 255;
	    topInputs[i]->value("255");
	}
	if (bottomv < 0) {
	    bottomv = 0;
	    bottomInputs[i]->value("0");
	}
	if (bottomv > 255) {
	    bottomv = 255;
	    bottomInputs[i]->value("255");
	}
	if (leftv < 0) {
	    leftv = 0;
	    leftInputs[i]->value("0");
	}
	if (leftv > 255) {
	    leftv = 255;
	    leftInputs[i]->value("255");
	}
	if (rightv < 0) {
	    rightv = 0;
	    rightInputs[i]->value("0");
	}
	if (rightv > 255) {
	    rightv = 255;
	    rightInputs[i]->value("255");
	}

	if ((leftv == 0) && (rightv == 255)) {
	    if (topv > bottomv) {
		newcontrast = atan(255.0/((double)topv-bottomv))*2.0/M_PI;
		newbrightness = ((double)topv+bottomv)/(2*255.0);
	    } 
	} else if ((leftv == 255) && (rightv == 0)) {
	    if ( topv > bottomv) {
		newcontrast = atan(-255.0/((double)topv-bottomv))*2.0/M_PI;
		newbrightness = ((double)topv+bottomv)/(2*255.0);
	    }
	} else {
	    newcontrast = atan((double)(rightv-leftv)/(255.0))*2.0/M_PI;
	    if (rightv > leftv)
		newbrightness = (255.0 - 2*leftv)/(2*((double)rightv - leftv));
	    else if (leftv > rightv)
		newbrightness = (255.0 - 2*leftv)/(2*((double)leftv -rightv));
	    else
		newbrightness = 0.5; // doesnt' matter.
	}

	//newcontrast = floor(newcontrast*200.0)/200.0; // to get the expected precision
	//newbrightness = floor(newbrightness*200.0)/200.0;
	dbgprintf("%d: Brightness: %g, Contrast: %g\n", i, newbrightness, newcontrast);

	contrastSliders[i]->value(newcontrast);
	brightnessSliders[i]->value(newbrightness);
    }

    setDrawingParms();
    RGBtransferWindow->redraw();

    // this doesn't seem to work. Why?
    // ensureImageRedraw(true);
    
    return;
}
    
void transferRGB::setDrawingParms()
{
    double c[3], b[3], g[3];
    
    c[0] = RcontrastSlider->value();
    c[1] = GcontrastSlider->value();
    c[2] = BcontrastSlider->value();
    
    b[0] = RbrightnessSlider->value();
    b[1] = GbrightnessSlider->value();
    b[2] = BbrightnessSlider->value();

    g[0] = atof(RgammaInput->value());
    g[1] = atof(GgammaInput->value());
    g[2] = atof(BgammaInput->value());

    RGBtransferBox->setRGBParms(c,b,g);

    return;
}

void transferRGB::redrawWindowIfNeeded()
{
    if (RGBtransferWindow->visible()) {
	dbgprintf("Forcing the recalculation of the map LUT\n");
	RGBtransferBox->forceBuildMap();
        RGBtransferWindow->redraw();
	// force the recalculation of the map LUT
    }

    return;
}

void transferRGB::show()
{
    RGBtransferWindow->show();
}

void transferRGB::hide()
{
    RGBtransferWindow->hide();
}


void transferRGB::setTopValue(int t[3])
{
    char cval[10];
    
    dbgprintf("Top values being set to %d,%d,%d\n", 
	      t[0],t[1],t[2]);
    sprintf(cval, "%d", t[0]);
    RtopInput->value(cval);
    sprintf(cval, "%d", t[1]);
    GtopInput->value(cval);
    sprintf(cval, "%d", t[2]);
    BtopInput->value(cval);

    return;
}

void transferRGB::setBottomValue(int t[3])
{
    char cval[10];
    dbgprintf("Bottom values being set to %d,%d,%d\n", 
	      t[0],t[1],t[2]);
    sprintf(cval, "%d", t[0]);
    RbottomInput->value(cval);
    sprintf(cval, "%d", t[1]);
    GbottomInput->value(cval);
    sprintf(cval, "%d", t[2]);
    BbottomInput->value(cval);

    return;
}

void transferRGB::setLeftValue(int t[3])
{
    char cval[10];
    dbgprintf("Left values being set to %d,%d,%d\n", 
	      t[0],t[1],t[2]);

    sprintf(cval, "%d", t[0]);
    RleftInput->value(cval);
    sprintf(cval, "%d", t[1]);
    GleftInput->value(cval);
    sprintf(cval, "%d", t[2]);
    BleftInput->value(cval);

    return;
}

void transferRGB::setRightValue(int t[3])
{
    char cval[10];
    dbgprintf("Right values being set to %d,%d,%d\n", 
	      t[0],t[1],t[2]);
    
    sprintf(cval, "%d", t[0]);
    RrightInput->value(cval);
    sprintf(cval, "%d", t[1]);
    GrightInput->value(cval);
    sprintf(cval, "%d", t[2]);
    BrightInput->value(cval);

    return;
}



// returns the index of the slider argument (0 for Red, 1 for green, etc)
int transferRGB::identifySlider(Fl_Slider *aSlider)
{
    int i;

    for (i = 0 ; i < 3 ; ++i) {
	if ((aSlider == contrastSliders[i])
	    || (aSlider == brightnessSliders[i])
	    || (aSlider == gammaSliders[i]))
	    break;
    }
    assert(i < 3);
    return i;
}

// same thing for inputs
int transferRGB::identifyInput(Fl_Input *anInput)
{
    int i;

    for (i = 0 ; i < 3 ; ++i) {
	if ((anInput == gammaInputs[i])
	    || (anInput == topInputs[i])
	    || (anInput == bottomInputs[i])
	    || (anInput == leftInputs[i])
	    || (anInput == rightInputs[i]))
	    break;
    }
    assert(i < 3);
    return i;
}

// link generic sliders
void transferRGB::linkSliders(Fl_Slider *sliderKind[3], int withId, double v)
{
    if (linkButtons[withId]->value()) {
	for (int i = 1 ; i <= 2 ; ++i) {
	    int nextId = (withId + i) % 3;
	    if (linkButtons[nextId]->value())
		sliderKind[nextId]->value(v); // adjust value
	}
    }
}

// link generic inputs
void transferRGB::linkInputs(Fl_Input *inputKind[3], int withId, char *v)
{
    if (linkButtons[withId]->value()) {
	for (int i = 1 ; i <= 2 ; ++i) {
	    int nextId = (withId + i) % 3;
	    if (linkButtons[nextId]->value())
		inputKind[nextId]->value(v); // adjust value
	}
    }
}



// callbacks associated with objects on the dialog
void RGBchosendisplay_cb(Fl_Menu_ *, void *value)
{
    long val = (long)value;

    switch (val) {
      case TRANSFER_DSP:
	transferRGBEditorPanel->setTransfer();
	break;
      case HISTOGRAM_DSP:
	transferRGBEditorPanel->setHisto();
	break;
      default:
	errprintf("Unknown value from choice menu: %d\n",
		  val);
	break;
    }
    return;
}

// callbacks associated with this dialog
void brightnessslider_cb(Fl_Slider *theSlider, transferRGB *panel)
{
    dbgprintf("Brightness slider callback\n");

    // link sliders
    double v = theSlider->value();
    int sliderId = panel->identifySlider(theSlider);
    panel->linkBrightnessSliders(sliderId, v);

    if (Fl::pushed() == 0) {
	dbgprintf("Button Released!\n");
	panel->ensureImageRedraw(true);
    }
    
    panel->setDrawingParms();

    return;
}

void contrastslider_cb(Fl_Slider *theSlider, transferRGB *panel)
{
    dbgprintf("Contrast slider callback\n");

    // link sliders
    double v = theSlider->value();
    int sliderId = panel->identifySlider(theSlider);
    panel->linkContrastSliders(sliderId, v);

    if (Fl::pushed() == 0) {
	dbgprintf("Button Released!\n");
	panel->ensureImageRedraw(true);
    }

    panel->setDrawingParms();

    return;
}

void displaychoice_cb(Fl_Choice*, transferRGB*)
{
    dbgprintf("Display choice  callback\n");
}

void gammainput_cb(Fl_Float_Input *theInput, transferRGB *panel)
{
    double eval, val;
    const char  *cval;

    dbgprintf("Gamma input callback\n");
    
    int inputId = panel->identifyInput(theInput);

    cval = theInput->value();
    eval = atof(cval);
    if (eval > 0) {
	val = log(eval);
    } else {
	char cval[10];
	val = -1;
	sprintf(cval,"%1.4g", exp(-1));
	switch(inputId) {
	case 0:
	    panel->setRGammaInputValue((const char *)cval);
	    break;
	case 1:
	    panel->setGGammaInputValue((const char *)cval);
	    break;
	case 3:
	    panel->setRGammaInputValue((const char *)cval);
	    break;
	}
    }
    
    switch (inputId) {
    case 0:
	panel->setRGammaSliderValue((float)val);
	break;
    case 1:
	panel->setGGammaSliderValue((float)val);
	break;
    case 2:
	panel->setBGammaSliderValue((float)val);
	break;
    }

    panel->ensureImageRedraw(true);
    panel->setDrawingParms();
    
    return;
}

void gammaslider_cb(Fl_Slider *theSlider, transferRGB *panel)
{
    double val, eval;
    char  cval[20];

    dbgprintf("Gamma slider callback\n");
    
    if (Fl::pushed() == 0) {
	dbgprintf("Button Released!\n");
	panel->ensureImageRedraw(true);
    }

    // link sliders
    val = theSlider->value();
    int sliderId = panel->identifySlider(theSlider);

    eval = exp(val);
    sprintf(cval, "%1.4g", eval); 

    // link the sliders
    panel->linkGammaSliders(sliderId, val);

    // the slider ID and the input ID should be the same
    panel->setGammaInputValue(sliderId, cval);
    panel->linkGammaInputs(sliderId, cval); 

    panel->setDrawingParms();
    
    return;
}

void bottominput_cb(Fl_Int_Input *theInput, transferRGB *panel)
{
    panel->ensureImageRedraw(true);
    panel->computeDrawingParms();
    return;
}

void topinput_cb(Fl_Int_Input *theInput, transferRGB *panel)
{
    dbgprintf("Top input callback\n");
    panel->ensureImageRedraw(true);
    panel->computeDrawingParms();
    return;
}

void leftinput_cb(Fl_Int_Input *theInput, transferRGB *panel)
{
    panel->ensureImageRedraw(true);
    panel->computeDrawingParms();
    return;
}

void rightinput_cb(Fl_Int_Input *theInput, transferRGB *panel)
{
    panel->ensureImageRedraw(true);
    panel->computeDrawingParms();
    return;
}

void selectchannel_cb(Fl_Button *, transferRGB *panel)
{
    panel->redrawBox();
    return;
}

void resetbutton_cb(Fl_Button*, transferRGB *panel)
{
    char buf[100];
    int  resetR, resetG, resetB;
    // this is very simple...
    dbgprintf("Reset button pressed\n");

    // asks which channels to affect
    panel->affectChannels(resetR, resetG, resetB);
    panel->ensureImageRedraw(true); // ensures a redraw

    sprintf(buf, "%g", persistentGamma);
    
    if (resetR) {
	panel->setRGammaInputValue(buf);
	panel->setRGammaSliderValue(0);
	panel->setRContrastSliderValue(0.5);
	panel->setRBrightnessSliderValue(0.5);
    }

    if (resetG) {
	panel->setGGammaInputValue(buf);
	panel->setGGammaSliderValue(0);
	panel->setGContrastSliderValue(0.5);
	panel->setGBrightnessSliderValue(0.5);
    }

    if (resetB) {
	panel->setBGammaInputValue(buf);
	panel->setBGammaSliderValue(0);
	panel->setBContrastSliderValue(0.5);
	panel->setBBrightnessSliderValue(0.5);
    }

    panel->setDrawingParms();     // compute input values from  slider values 
    panel->computeDrawingParms();
    
    return;
}

void normalisebutton_cb(Fl_Button*, transferRGB *panel)
{
    int             spp, val, minval, maxval;
    long            nbpix;
    unsigned char  *p, *end;
    double          slope, startp;
    int             normR, normG, normB;
    char            buf[100];
    
    // asks which channels to affect
    panel->affectChannels(normR, normG, normB);
    panel->ensureImageRedraw(true); // we want the result to be shown on the image
    
    nbpix = IOBlackBox->imageWidth() * IOBlackBox->imageHeight();
    spp = IOBlackBox->imageDepth();

    maxval = 0;
    minval = 255;
    
    if (spp == 1) {
	p = IOBlackBox->imageData();
	end = p + nbpix;
	
	while (p != end) {
	    if (*p > maxval)
		maxval = *p;
	    if (*p < minval)
		minval = *p;
	    p++;
	}
    } else if (spp == 3) {
	p = IOBlackBox->imageData();
	end = p + spp * nbpix;
	// we only include in the calculation the channels
	// to be normalized
	while (p != end) {
	    if (normR) {
		val = *p++;
		if (val > maxval)
		    maxval = val;
		if (val < maxval)
		    minval = val;
	    } else {
		p++; // red pixels ignored in calculation
	    }
	    
	    if (normG) {
		val = *p++;
		if (val > maxval)
		    maxval = val;
		if (val < maxval)
		    minval = val;
	    } else {
		p++; // green pixels ignored
	    }

	    if (normB) {
		val = *p++;
		if (val > maxval)
		    maxval = val;
		if (val < maxval)
		    minval = val;
	    } else {
		p++; // blue pixels ignored
	    }
	}
    }

    dbgprintf("Min val:%d, max val: %d\n", minval, maxval);

    // now compute the slope parameters, etc
    if (maxval != minval)
	slope = 2*atan(255.0/(maxval-minval))/M_PI;
    else
	slope = 1;
    
    startp = ((double)maxval+minval)/(512);

    // this is now pretty simple...

    sprintf(buf, "%g", persistentGamma);
    if (normR) {
	panel->setRGammaInputValue(buf);
	panel->setRGammaSliderValue(0);
	panel->setRContrastSliderValue(slope);
	panel->setRBrightnessSliderValue(startp);
    }

    if (normG) {
	panel->setGGammaInputValue(buf);
	panel->setGGammaSliderValue(0);
	panel->setGContrastSliderValue(slope);
	panel->setGBrightnessSliderValue(startp);
    }

    if (normB) {
	panel->setBGammaInputValue(buf);
	panel->setBGammaSliderValue(0);
	panel->setBContrastSliderValue(slope);
	panel->setBBrightnessSliderValue(startp);
    }
    
    panel->setDrawingParms();
    panel->computeDrawingParms();

    return;
}

void applytoallbutton_cb(Fl_Check_Button *b, transferRGB *panel)
{
    applyTransferToAll = b->value();
    switch (applyTransferToAll) {
      case 0:
	dbgprintf("Will apply transfer function only to currently displayed image\n");
	break;
      default:
	dbgprintf("Will apply transfer function to all image/components, etc\n");
	break;
    }
    return;
}

void okbutton_cb(Fl_Return_Button*, transferRGB *panel)
{
    // this is very simple...
    panel->hide();
}
