/* 
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: ColorM1.c /main/8 1995/07/13 18:34:42 drk $"
#endif
#endif
/*
*  (c) Copyright 1989, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */
#include <testlib.h>
#include "ColorM1.h"
#include <varargs.h>

static char toggle_flag = 'F';
static unsigned long pixels_return2[5];
static unsigned long plane_masks_return2[1];
static MrmCode	 class ;
static Widget color_main;           
static char  *global_current_file;   

static void default_colors ();
static void initialize_coords();

static void create_colorform(char *resourcestring, char *valuestring, 
                             int item_to_adjust);
static void destroy_colorform(Widget widget, XtPointer client_data, 
			      XtPointer call_data);
static void color_selection_made(Widget widget, XtPointer client_data, 
				 XtPointer call_data);
static void colorlist_selection_made(Widget widget, XtPointer client_data, 
				 XtPointer call_data);
static void scale_value_changed(Widget widget, XtPointer client_data, 
				XtPointer call_data);
static void load_rgb_text(Widget widget, XtPointer client_data, 
			  XtPointer call_data);
static void setcolor_button_pressed(Widget widget, XtPointer client_data, 
				    XtPointer call_data);
static void toggle_button_pressed(Widget widget, XtPointer client_data, 
				  XtPointer call_data);
static void exit_color(Widget widget, XtPointer client_data, 
		       XtPointer call_data);
static void setcolor_colorform(Widget form, char *valuestring);
static char *stringdup(const char *s);
static char *extract_first_xms_segment(XmString cs);
static void fetch(char *widget_index_string, Widget *widgetptr);

static char		*uid_files[]={"ColorM1.uid"};
static int num_uid_files = sizeof(uid_files) / sizeof(char *);

static MrmRegisterArg	callbackvec[] = {
{"setcolor_button_pressed",(caddr_t)setcolor_button_pressed},
{"toggle_button_pressed",(caddr_t)toggle_button_pressed},
{"color_selection_made",(caddr_t)color_selection_made},
{"create_colorform",(caddr_t)create_colorform},
{"destroy_colorform",(caddr_t)destroy_colorform},
{"scale_value_changed",(caddr_t)scale_value_changed},
{"exit_color",(caddr_t)exit_color},
{"load_rgb_text",(caddr_t)load_rgb_text}
};

static MrmCount callbacknum = sizeof(callbackvec) / sizeof(MrmRegisterArg);

static XtResource resources[] = {
{ XtNrgbTextFile, XtCRgbTextFile, XtRString, sizeof(String),
 XtOffset(ApplicationDataPtr,rgb_text_file),XtRString, "/usr/lib/X11/rgb.txt"}
};

Widget fetched;

typedef struct {
  int    item_to_adjust;
  char   colorname[40];
  char   redname[10];
  char   greenname[10];
  char   bluename[10];
  XColor color; 
  unsigned long fg_pixel;/* foreground   */
  unsigned long bg_pixel;/* background   */
  unsigned long ts_pixel;/* topshadow    */
  unsigned long bs_pixel;/* bottomshadow */
  unsigned long arm_pixel;/* arm color */
} ColorData, *ColorDataPtr;


static void create_colorform(char *resourcestring, char *valuestring, 
                             int item_to_adjust)

{
    ColorDataPtr colordata;
    ColorDataPtr colordata2;
    Arg arg[5];
    unsigned long plane_masks_return[1];
    unsigned long pixels_return[4];
    Status status;
    Boolean false = 0;
    XColor color;
    XColor color2;

    fetched = (Widget) 0;
    colordata = (ColorDataPtr) XtCalloc(1,sizeof(ColorData));
    colordata2 = (ColorDataPtr) XtCalloc(1,sizeof(ColorData));
    colordata->item_to_adjust = item_to_adjust;
    colordata2->item_to_adjust = item_to_adjust;
    status = XAllocColorCells(
			  dpy,
			  cmap,
			  false,
			  plane_masks_return,
			  1,
			  pixels_return,
			  4);
    if(!status){
      no_colors_available = 1;
      return;
    }

    /* Allocate colors for color change P.B. */

    status = XAllocColorCells(
			  dpy,
			  cmap,
			  false,
			  plane_masks_return2,
			  1,
			  pixels_return2,
			  5);
    if(!status){
      no_colors_available = 1;
      return;
      }

    colordata->color.pixel = pixels_return[0];
    colordata->color.flags = DoRed | DoGreen | DoBlue;
    colordata->fg_pixel = pixels_return[0];
    colordata->bg_pixel = pixels_return[1];
    colordata->ts_pixel = pixels_return[2];
    colordata->bs_pixel = pixels_return[3];

    initialize_coords();

    fetch("color_form",&fetched);

    /* store userData */
	if ( fetched == NULL ) {
		exit(1);
	} else {
    XtSetArg(arg[0],XmNuserData,colordata);
    XtSetValues(fetched,arg,1);
    setcolor_colorform(fetched,valuestring);
	}

    /* set the background (and other fields) of the color patch */
    /* to the allocated color and associated colors */

    color.pixel = pixels_return[0];
    XQueryColor(dpy,cmap,&color);
    color2.pixel = pixels_return[0];
    XQueryColor(dpy,cmap,&color2);
    color.pixel = pixels_return[2];
    XStoreColor(dpy,cmap,&color);
    color.pixel = pixels_return[3];
    XStoreColor(dpy,cmap,&color);

    /* note that foreground is initialized to contrast with background */
    color.red = 65535 - color.red;
    color.green = 65535 - color.green;
    color.blue = 65535 - color.blue;
    color.pixel = pixels_return[1];
    XStoreColor(dpy,cmap,&color);

    color2.red = 0;
    color2.green = 0;
    color2.blue = 0;
    color2.pixel = pixels_return2[1];
    XStoreColor(dpy,cmap,&color2);

    color2.red = 0;
    color2.green = 0;
    color2.blue = 0;
    color2.pixel = pixels_return2[2];
    XStoreColor(dpy,cmap,&color2);

    color2.red = 0;
    color2.green = 0;
    color2.blue = 0;
    color2.pixel = pixels_return2[3];
    XStoreColor(dpy,cmap,&color2);

    color2.red = 0;
    color2.green = 0;
    color2.blue = 0;
    color2.pixel = pixels_return2[4];
    XStoreColor(dpy,cmap,&color2);

    color2.red = 65535;
    color2.green = 65535;
    color2.blue = 65535;
    color2.pixel = pixels_return2[0];
    XStoreColor(dpy,cmap,&color2);

    XtSetArg(arg[0],XmNbackground,pixels_return[0]);
    XtSetArg(arg[1],XmNforeground,pixels_return[1]);
    XtSetArg(arg[2],XmNtopShadowColor,pixels_return[2]);
    XtSetArg(arg[3],XmNbottomShadowColor,pixels_return[3]);
    XtSetValues(XtNameToWidget(fetched,"color_patch"),arg,4);

    XtSetArg(arg[0],XmNbackground,pixels_return2[0]);
    XtSetArg(arg[1],XmNforeground,pixels_return2[1]);
    XtSetArg(arg[2],XmNtopShadowColor,pixels_return2[2]);
    XtSetArg(arg[3],XmNbottomShadowColor,pixels_return2[3]);
    XtSetArg(arg[4],XmNarmColor,pixels_return2[4]);
    XtSetValues(XtNameToWidget(fetched,"color_change_BB.color_change"),arg,5);

    XtSetArg(arg[0],XmNbackground,pixels_return2[0]);
    XtSetValues(XtNameToWidget(fetched,"color_change_BB"),arg,1);

    XtManageChild(fetched);
}


static void destroy_colorform(Widget widget, XtPointer client_data, 
			      XtPointer call_data)
{
  Arg arg[1];
  ColorDataPtr userdata;

  /* get the userdata and free it*/
  XtSetArg(arg[0],XmNuserData,&userdata);
  XtGetValues(widget,arg,1);
  XtFree((XtPointer) userdata);
}


/* callback notified when selection is made */
static void color_selection_made(Widget widget, XtPointer client_data, 
				 XtPointer call_data)
{
  char *color_string;
  XmSelectionBoxCallbackStruct *callback_data;

  callback_data = (XmSelectionBoxCallbackStruct *) call_data;

  color_string = extract_first_xms_segment(callback_data->value);
  setcolor_colorform(XtParent(widget),color_string);
}


/* callback notified when selection is made */
static void colorlist_selection_made(Widget widget, XtPointer client_data, 
				     XtPointer call_data)
{
  char *color_string;
  XmListCallbackStruct *callback_data;

  callback_data  = (XmListCallbackStruct *) call_data;

  color_string = extract_first_xms_segment(callback_data->item);
  /* the following code will fail if the list is not a descendant of a form */
  while(!XtIsSubclass(widget,xmFormWidgetClass))
    widget = XtParent(widget);
  setcolor_colorform(widget,color_string);
}


static void setcolor_colorform(Widget form, char *valuestring)
{
  Arg arg[1];
  ColorDataPtr colordata;
  Widget scale;
  Widget text;

  XtSetArg(arg[0],XmNuserData,&colordata);
  XtGetValues(form,arg,1);
  /* set the color cell to valuestring */
  if(*valuestring=='#'){
    XParseColor(dpy,cmap,valuestring,&(colordata->color));
    XStoreColor(dpy,cmap,&(colordata->color));
  }
  else 
    XStoreNamedColor(dpy,cmap,valuestring,
		     colordata->color.pixel,
		     colordata->color.flags);
  /* and fill the XColor struct with RGB values for scales */
  XQueryColor(dpy,cmap,&(colordata->color));

  /* based on the values in the color fields, set the slider values */
  scale = XtNameToWidget(form,"slider_box.scale1");
  XtSetArg(arg[0],XmNvalue,(int)(colordata->color.red/COLOR_PCT_MULTIPLIER));
  XtSetValues(scale,arg,1);
  sprintf(colordata->redname,"%4.4x",colordata->color.red);

  scale = XtNameToWidget(form,"slider_box.scale2");
  XtSetArg(arg[0],XmNvalue,(int)(colordata->color.green/COLOR_PCT_MULTIPLIER));
  XtSetValues(scale,arg,1);
  sprintf(colordata->greenname,"%4.4x",colordata->color.green);

  scale = XtNameToWidget(form,"slider_box.scale3");
  XtSetArg(arg[0],XmNvalue,(int)(colordata->color.blue/COLOR_PCT_MULTIPLIER));
  XtSetValues(scale,arg,1);
  sprintf(colordata->bluename,"%4.4x",colordata->color.blue);
    
  sprintf(colordata->colorname,valuestring);
  text = XmSelectionBoxGetChild(
	    XtNameToWidget(form,"color_sb"),
	    XmDIALOG_TEXT);
  XmTextSetString(text,valuestring);
}

static void scale_value_changed (Widget widget, XtPointer client_data,
				 XtPointer call_data)

{
  Widget form;
  Widget patch_widget;
  Widget text_widget;
  ColorDataPtr colordata;
  Arg    arg[2];
  XmScaleCallbackStruct *callback_data;
  char *tag;

  callback_data = (XmScaleCallbackStruct *) call_data;
  tag = (char *) client_data;

  form = XtParent(XtParent(widget));
  patch_widget = XtNameToWidget(form,"color_patch");
  text_widget = XmSelectionBoxGetChild(
	    XtNameToWidget(form,"color_sb"),
	    XmDIALOG_TEXT);

  XtSetArg(arg[0],XmNuserData,&colordata);
  XtGetValues(form,arg,1);

  /* based on the tag, set either the red,green, or blue static variables, */
  /* then set color of label0 */

  if(*tag == 'r'){
    colordata->color.red = callback_data->value * COLOR_PCT_MULTIPLIER;
    sprintf(colordata->redname,"%4.4x",colordata->color.red);
  }
  else if(*tag == 'g'){
    colordata->color.green = callback_data->value * COLOR_PCT_MULTIPLIER;
    sprintf(colordata->greenname,"%4.4x",colordata->color.green);
  }
  else if(*tag == 'b'){
    colordata->color.blue = callback_data->value * COLOR_PCT_MULTIPLIER;
    sprintf(colordata->bluename,"%4.4x",colordata->color.blue);
  }

  /* update the color cell */
  XStoreColor(dpy,cmap,&(colordata->color));

  /* assemble complete hex-string and set editable text to it */
  strcpy(colordata->colorname,"#");
  strcat(colordata->colorname,colordata->redname);
  strcat(colordata->colorname,colordata->greenname);
  strcat(colordata->colorname,colordata->bluename);

  XmTextSetString(text_widget,colordata->colorname);
}

static void toggle_button_pressed(Widget widget, XtPointer client_data, 
				  XtPointer call_data)
{
    XmToggleButtonCallbackStruct *callback_data;

    callback_data = (XmToggleButtonCallbackStruct *) call_data;

    if (callback_data->set == XmSET)
	toggle_flag = * (char *)client_data;
}

static void setcolor_button_pressed(Widget widget, XtPointer client_data, 
				  XtPointer call_data)
{
  Widget parent;
  Widget change_widget;
  XColor color;
  ColorDataPtr colordata;
  Arg arg[1];

  change_widget = XtNameToWidget(fetched,"color_change_BB.color_change");
  parent = XtParent(XtParent(change_widget));

  XtSetArg(arg[0],XmNuserData,&colordata);
  XtGetValues(parent,arg,1);

  /* store rgb values from foreground into appropriate field */
  color.red = colordata->color.red;
  color.green = colordata->color.green;
  color.blue = colordata->color.blue;
  color.flags = colordata->color.flags;

  if(toggle_flag == 'F'){
    XtSetArg(arg[0],XmNforeground,&(color.pixel));
    XtGetValues(change_widget,arg,1);
  }
  else if(toggle_flag == 'B'){
    XtSetArg(arg[0],XmNbackground,&(color.pixel));
    XtGetValues(change_widget,arg,1);
    XtSetArg(arg[0], XmNbackground, color.pixel);
    XtSetValues(XtParent(change_widget), arg, 1);
  }
  else if(toggle_flag == 'X'){
    XtSetArg(arg[0],XmNbottomShadowColor,&(color.pixel));
    XtGetValues(change_widget,arg,1);
  }
  else if(toggle_flag == 'T'){
    XtSetArg(arg[0],XmNtopShadowColor,&(color.pixel));
    XtGetValues(change_widget,arg,1);
  }
  else if(toggle_flag == 'A'){
    XtSetArg(arg[0],XmNarmColor,&(color.pixel));
    XtGetValues(change_widget,arg,1);
  }
  else if(toggle_flag == 'D'){
    default_colors();
    return;
  }
  else return;

  XStoreColor(dpy,cmap,&color);
}


/* this routine is called when the color list is created */
#define MAX_DEFINED_COLORS 500
static void load_rgb_text(Widget widget, XtPointer client_data, 
			  XtPointer call_data)
{
  Arg arg[2];
  FILE *rgb_text;
  int item_count;
  XmString xms[MAX_DEFINED_COLORS]; 
  char buf[360];

  if(!(rgb_text=fopen(data.rgb_text_file,"r"))) {
    return;
  }

  for(item_count=0; (item_count<MAX_DEFINED_COLORS) &&
                    fgets(buf,sizeof(buf),rgb_text); item_count++) {
      char *name;
      /* get correct (4th) field of rgb.txt lines */
      strtok(buf," \t\n");
      strtok(NULL," \t\n");
      strtok(NULL," \t\n");
      name = strtok(NULL,"\t\n");
	  while (isspace(*name) && name != NULL && *name != '\0')
		  name++;
      /* if you don't set the array item, counteract the autoincrement */
      if(name)
	xms[item_count] = XmStringDefCreate(name);
      else item_count--;
  }

  fclose(rgb_text);

  XtSetArg(arg[0],XmNlistItems,xms);
  XtSetArg(arg[1],XmNlistItemCount,item_count);
  XtSetValues(widget,arg,2);

  while(--item_count > 0)
      XmStringFree(xms[item_count]);

  widget = XmSelectionBoxGetChild(widget, XmDIALOG_LIST);
  XtAddCallback(widget,
		XmNsingleSelectionCallback,colorlist_selection_made,NULL);
  XtAddCallback(widget,
		XmNbrowseSelectionCallback,colorlist_selection_made,NULL);
  XtAddCallback(widget,
		XmNdefaultActionCallback,colorlist_selection_made,NULL);

}


static void default_colors()
{
     Arg args[5];
     Pixel background, foreground, top_shadow, bottom_shadow, arm_color;
     Pixel r_foreground, r_top_shadow, r_bottom_shadow, r_arm_color;
     Widget widget;
     int n = 0;
     XColor color;

     widget = XtNameToWidget(fetched,"color_change_BB.color_change");
     XtSetArg(args[n], XmNbackground, &background);		n++;
     XtGetValues(widget, args, n);

     XmGetColors(XtScreen(widget), cmap, background, &r_foreground,
			     &r_top_shadow, &r_bottom_shadow, &r_arm_color);

     XtSetArg(args[n], XmNforeground, &foreground); 		n++; 
     XtSetArg(args[n], XmNtopShadowColor, &top_shadow);		n++;
     XtSetArg(args[n], XmNbottomShadowColor, &bottom_shadow);	n++;
     XtSetArg(args[n], XmNarmColor, &arm_color);		n++;
     XtGetValues(widget, args, n);

     color.pixel = r_foreground;
     XQueryColor(dpy,cmap,&color);
     color.pixel = foreground;
     XStoreColor(dpy, cmap, &color);

     color.pixel = background;
     XQueryColor(dpy,cmap,&color);
     color.pixel = background;
     XStoreColor(dpy, cmap, &color);

     color.pixel = r_top_shadow;
     XQueryColor(dpy,cmap,&color);
     color.pixel = top_shadow;
     XStoreColor(dpy, cmap, &color);

     color.pixel = r_bottom_shadow;
     XQueryColor(dpy,cmap,&color);
     color.pixel = bottom_shadow;
     XStoreColor(dpy, cmap, &color);

     color.pixel = r_arm_color;
     XQueryColor(dpy,cmap,&color);
     color.pixel = arm_color;
     XStoreColor(dpy, cmap, &color);
}


/*
 *  Main program
 */
int main (int argc, char **argv)
{

    Arg arg[1] ;

    MrmInitialize ();

    /*
     *  Initialize the toolkit.  This call returns the id of a "shell,"
     *  whose only child should be the main window of the application.
     */

    CommonTestInit(argc, argv);

    XtSetArg (arg[0], XtNallowShellResize, TRUE) ;
    XtSetValues (Shell1, arg, 1) ;

    if(argc>1 && argv[1]){global_current_file=stringdup(argv[1]);}

    dpy = XtDisplay(Shell1);
    cmap = XDefaultColormap(dpy,0);

    XtGetApplicationResources(Shell1,
			      &data,
			      resources,
			      XtNumber(resources),
			      NULL,
			      0);

    /*
     *  Define the Mrm.hierarchy 
     */

    if (MrmOpenHierarchy (num_uid_files,	            /* number of files	    */
			uid_files, 	     	    /* files     	    */
			NULL,			    /* os_ext_list (null)   */
			&s_MrmHierarchy)	    /* ptr to returned id   */
			!= MrmSUCCESS) {
	printf ("Color: cannot open UID hierarchy.\n\
     Check UIDPATH environment variable\n\
     Goodbye.");
	return(0);
     }

    /*
     * 	Register callback routines 
     */

    if (MrmRegisterNames (callbackvec, callbacknum)
			!= MrmSUCCESS)
			    printf("can't register callback names\n");


    if (MrmFetchWidget (s_MrmHierarchy,
			"color_main",
			Shell1,
			&color_main,
			&class)
			!= MrmSUCCESS)
			    printf("can't fetch main window\n");


    /*
     *  Make the Shell1 widget "manage" the main window.
     *  It will not be "realized" until the Shell1 widget is "realized"
     */

    XtManageChild(color_main);
    
    /*
     *  Realize the Shell1 widget.  This will cause the entire "managed"
     *  widget hierarchy to be displayed.
     */

    XtRealizeWidget(Shell1);

  /* load non-UIL bitmaps, if internalPixmaps resource is true */

    create_colorform(XmNforeground, "white", 0);

    CommonPause();

    XtAppMainLoop(app_context);

    /* UNREACHABLE */
    return (0);
}

static void fetch(char *widget_index_string, Widget *widgetptr)
{
  MrmType class;
  *widgetptr = NULL;
  if(MrmFetchWidget(s_MrmHierarchy,
                widget_index_string,
                Shell1,
                widgetptr,
                &class)!=MrmSUCCESS)
                  printf("fail_cant_fetch\n");
}

static char *extract_first_xms_segment(XmString cs)
{
  XmStringContext context;
  XmStringCharSet charset;
  XmStringDirection direction;
  Boolean separator;
  char *primitive_string;
  XmStringInitContext(&context,cs);
  XmStringGetNextSegment(context,&primitive_string,
           &charset,&direction,&separator);
  XmStringFreeContext(context);
  return(primitive_string);
}


static void initialize_coords()
{
  MrmRegisterArg arg[2];
  static Position x,y;
  /* init_red/green/blue are identifiers in the uil module */
  arg[0].name = "stagger_x";
  arg[1].name = "stagger_y";
  if(!x)
    XtTranslateCoords(Shell1,50,50,&x,&y);
  else {
    x+=50;
    y+=50;
  }
 
  arg[0].value = (XtPointer)(long)(int)x;
  arg[1].value = (XtPointer)(long)(int)y;
  if (MrmRegisterNames (arg, 2)
                        != MrmSUCCESS)
                            printf("can't register identifier names\n");

}

static void exit_color(Widget widget, XtPointer client_data, 
		       XtPointer call_data)
{
	XFreeColors(dpy, cmap, pixels_return2, 5, plane_masks_return2[0]);
	printf("Exiting Color Program ....\n");
	exit(0);
}


/* return newly allocated duplicate copy of an asciiz string */
static char *stringdup(const char *s)
{
  char *dup;
  dup = (char *) XtCalloc(strlen(s)+1,sizeof(char));
  strcpy(dup,s);
  return(dup);
}
