/* * A color chooser. The function GetColor() pops up a modal window * that lets a user interactively play with a color in either RGB or * HSV space and then returns the chosen value to your program. * * Written by Allen Martin (amartin@cs.wpi.edu) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "libsx.h" #ifdef __linux__ #define NeedFunctionPrototypes 1 #undef NeedWidePrototypes #endif #include <X11/Xaw/Scrollbar.h> #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) typedef struct { Widget creq_window; Widget red_label, red_string, red_scroll; Widget green_label, green_string, green_scroll; Widget blue_label, blue_string, blue_scroll; int color; int rgb; float r, g, b; float h, s, v; int cancelled; } CReqData; #define BOX_WIDTH 85 #define BOX_HEIGHT 85 static void color_cancel(Widget w, CReqData *cdata); static void color_ok(Widget w, CReqData *cdata); static void color_string(Widget w, char *string, CReqData *cdata); static void color_scroll(Widget w, float val, CReqData *cdata); static void color_redisplay(Widget w, int width, int height, CReqData *cdata); static void rgb_hsv(Widget w, CReqData *cdata); static void rgb2hsv(float r, float g, float b, float *h, float *s, float *v); static void hsv2rgb(float h, float s, float v, float *r, float *g, float *b); /* * GetColor() */ int GetColor(unsigned char *r, unsigned char *g, unsigned char *b) { CReqData cdata; Widget w[14]; char cvalue[4]; int width; static unsigned char black_bits[] = { 0xff }; /* initialize the color values */ cdata.r = (float)*r; cdata.g = (float)*g; cdata.b = (float)*b; rgb2hsv(cdata.r, cdata.g, cdata.b, &cdata.h, &cdata.s, &cdata.v); cdata.rgb=TRUE; cdata.creq_window = MakeWindow("Color Requestor", SAME_DISPLAY, EXCLUSIVE_WINDOW); w[0] = MakeButton("RGB/HSV", (void *)rgb_hsv, &cdata); /* determine the width to make the string widgets with */ width = TextWidth(GetWidgetFont(w[0]), "88888"); w[1] = MakeLabel("R"); sprintf(cvalue, "%d", *r); w[2] = MakeStringEntry(cvalue, width, (void *)color_string, &cdata); w[3] = MakeHorizScrollbar(250, (void *)color_scroll, &cdata); w[4] = MakeLabel("G"); sprintf(cvalue, "%d", *g); w[5] = MakeStringEntry(cvalue, width, (void *)color_string, &cdata); w[6] = MakeHorizScrollbar(250, (void *)color_scroll, &cdata); w[7] = MakeLabel("B"); sprintf(cvalue, "%d", *b); w[8] = MakeStringEntry(cvalue, width, (void *)color_string, &cdata); w[9] = MakeHorizScrollbar(250, (void *)color_scroll, &cdata); w[10] = MakeDrawArea(BOX_WIDTH, BOX_HEIGHT, (void *)color_redisplay, &cdata); w[11] = MakeButton("Ok", (void *)color_ok, &cdata); w[12] = MakeLabel("Please Edit the Color Above"); w[13] = MakeButton("Cancel", (void *)color_cancel, &cdata); SetWidgetPos(w[1], PLACE_UNDER, w[0], NO_CARE, NULL); SetWidgetPos(w[2], PLACE_UNDER, w[0], PLACE_RIGHT, w[1]); SetWidgetPos(w[3], PLACE_UNDER, w[0], PLACE_RIGHT, w[2]); SetWidgetPos(w[4], PLACE_UNDER, w[1], NO_CARE, NULL); SetWidgetPos(w[5], PLACE_UNDER, w[1], PLACE_RIGHT, w[4]); SetWidgetPos(w[6], PLACE_UNDER, w[1], PLACE_RIGHT, w[5]); SetWidgetPos(w[7], PLACE_UNDER, w[4], NO_CARE, NULL); SetWidgetPos(w[8], PLACE_UNDER, w[4], PLACE_RIGHT, w[7]); SetWidgetPos(w[9], PLACE_UNDER, w[4], PLACE_RIGHT, w[8]); SetWidgetPos(w[10], PLACE_RIGHT, w[3], NO_CARE, NULL); SetWidgetPos(w[11], PLACE_UNDER, w[7], NO_CARE, NULL); SetWidgetPos(w[12], PLACE_UNDER, w[7], PLACE_RIGHT, w[11]); SetWidgetPos(w[13], PLACE_UNDER, w[7], PLACE_RIGHT, w[12]); /* save important widgets */ cdata.red_label = w[1]; cdata.red_string = w[2]; cdata.red_scroll = w[3]; cdata.green_label = w[4]; cdata.green_string = w[5]; cdata.green_scroll = w[6]; cdata.blue_label = w[7]; cdata.blue_string = w[8]; cdata.blue_scroll = w[9]; ShowDisplay(); /* allocate the custom color */ cdata.color = GetPrivateColor(); SetPrivateColor(cdata.color, cdata.r, cdata.g, cdata.b); SetDrawArea(w[10]); SetColor(cdata.color); SetBgColor(w[3], RED); SetThumbBitmap(w[3], black_bits, 8, 1); SetScrollbar(w[3], (float)*r, 255.0, 1.0); SetBgColor(w[6], GREEN); SetThumbBitmap(w[6], black_bits, 8, 1); SetScrollbar(w[6], (float)*g, 255.0, 1.0); SetBgColor(w[9], BLUE); SetThumbBitmap(w[9], black_bits, 8, 1); SetScrollbar(w[9], (float)*b, 255.0, 1.0); MainLoop(); SetCurrentWindow(ORIGINAL_WINDOW); /* check for cancel */ if(cdata.cancelled) return(TRUE); *r = (unsigned char)cdata.r; *g = (unsigned char)cdata.g; *b = (unsigned char)cdata.b; return(FALSE); } /* * rgb_hsv() - Callback for the RGB/HSV button */ static void rgb_hsv(Widget w, CReqData *cdata) { char cvalue[4]; cdata->rgb = !cdata->rgb; if(cdata->rgb) { SetLabel(cdata->red_label, "R"); SetLabel(cdata->green_label, "G"); SetLabel(cdata->blue_label, "B"); sprintf(cvalue, "%d", (int)cdata->r); SetScrollbar(cdata->red_scroll, (float)cdata->r, 255.0, 1.0); SetStringEntry(cdata->red_string, cvalue); sprintf(cvalue, "%d", (int)cdata->g); SetScrollbar(cdata->green_scroll, (float)cdata->g, 255.0, 1.0); SetStringEntry(cdata->green_string, cvalue); sprintf(cvalue, "%d", (int)cdata->b); SetScrollbar(cdata->blue_scroll, (float)cdata->b, 255.0, 1.0); SetStringEntry(cdata->blue_string, cvalue); } else { SetLabel(cdata->red_label, "H"); SetLabel(cdata->green_label, "S"); SetLabel(cdata->blue_label, "V"); sprintf(cvalue, "%d", (int)cdata->h); SetScrollbar(cdata->red_scroll, (float)cdata->h, 360.0, 1.0); SetStringEntry(cdata->red_string, cvalue); sprintf(cvalue, "%d", (int)cdata->s); SetScrollbar(cdata->green_scroll, (float)cdata->s, 100.0, 1.0); SetStringEntry(cdata->green_string, cvalue); sprintf(cvalue, "%d", (int)cdata->v); SetScrollbar(cdata->blue_scroll, (float)cdata->v, 255.0, 1.0); SetStringEntry(cdata->blue_string, cvalue); } } /* * color_ok() - Callback for color requestor OK button */ static void color_ok(Widget w, CReqData *cdata) { cdata->cancelled = FALSE; SetCurrentWindow(cdata->creq_window); CloseWindow(); } /* * color_cancel() - Callback for color requestor CANCEL button */ static void color_cancel(Widget w, CReqData *cdata) { cdata->cancelled = TRUE; SetCurrentWindow(cdata->creq_window); CloseWindow(); } static void color_string(Widget w, char *string, CReqData *cdata) { char cvalue[4]; float val; sscanf(string, "%f", &val); val = MAX(0, val); if(cdata->rgb) { /* range the value */ val = MIN(255, val); sprintf(cvalue, "%d", (int)val); if(w==cdata->red_string) { SetScrollbar(cdata->red_scroll, val, 255.0, 1.0); SetStringEntry(cdata->red_string, cvalue); cdata->r = val; } else if(w==cdata->green_string) { SetScrollbar(cdata->green_scroll, val, 255.0, 1.0); SetStringEntry(cdata->green_string, cvalue); cdata->g = val; } else if(w==cdata->blue_string) { SetScrollbar(cdata->blue_scroll, val, 255.0, 1.0); SetStringEntry(cdata->blue_string, cvalue); cdata->b = val; } rgb2hsv(cdata->r, cdata->g, cdata->b, &cdata->h, &cdata->s, &cdata->v); } else { if(w==cdata->red_string) { val = MIN(360, val); sprintf(cvalue, "%d", (int)val); SetScrollbar(cdata->red_scroll, val, 360.0, 1.0); SetStringEntry(cdata->red_string, cvalue); cdata->h = val; } else if(w==cdata->green_string) { val = MIN(100, val); sprintf(cvalue, "%d", (int)val); SetScrollbar(cdata->green_scroll, val, 100.0, 1.0); SetStringEntry(cdata->green_string, cvalue); cdata->s = val; } else if(w==cdata->blue_string) { val = MIN(255, val); sprintf(cvalue, "%d", (int)val); SetScrollbar(cdata->blue_scroll, val, 255.0, 1.0); SetStringEntry(cdata->blue_string, cvalue); cdata->v = val; } hsv2rgb(cdata->h, cdata->s, cdata->v, &cdata->r, &cdata->g, &cdata->b); } SetPrivateColor(cdata->color, (int)cdata->r, (int)cdata->g, (int)cdata->b); } static void color_scroll(Widget w, float val, CReqData *cdata) { char cvalue[4]; sprintf(cvalue, "%d", (int)val); if(cdata->rgb) { if(w==cdata->red_scroll) { SetStringEntry(cdata->red_string, cvalue); cdata->r = val; } else if(w==cdata->green_scroll) { SetStringEntry(cdata->green_string, cvalue); cdata->g = val; } else if(w==cdata->blue_scroll) { SetStringEntry(cdata->blue_string, cvalue); cdata->b = val; } rgb2hsv(cdata->r, cdata->g, cdata->b, &cdata->h, &cdata->s, &cdata->v); } else { if(w==cdata->red_scroll) { SetStringEntry(cdata->red_string, cvalue); cdata->h = val; } else if(w==cdata->green_scroll) { SetStringEntry(cdata->green_string, cvalue); cdata->s = val; } else if(w==cdata->blue_scroll) { SetStringEntry(cdata->blue_string, cvalue); cdata->v = val; } hsv2rgb(cdata->h, cdata->s, cdata->v, &cdata->r, &cdata->g, &cdata->b); } SetPrivateColor(cdata->color, (int)cdata->r, (int)cdata->g, (int)cdata->b); } /* * color_redisplay() - Redisplay callback for the creq draw area */ static void color_redisplay(Widget w, int width, int height, CReqData *cdata) { DrawFilledBox(0, 0, width, height); } static void rgb2hsv(float r, float g, float b, float *h, float *s, float *v) { float max = MAX(r,MAX(g,b)); float min = MIN(r,MIN(g,b)); float delta; *v = max; if (max != 0.0) *s = (max - min) / max; else *s = 0.0; if (*s == 0) { *h = 0; } else { delta = max - min; if (r == max) *h = (g - b) / delta; else if (g == max) *h = 2 + (b - r) / delta; else if (b == max) *h = 4 + (r - g) / delta; *h *= 60; if (*h < 0.0) *h += 360; } *s *= 100.0; } static void hsv2rgb(float h, float _s, float v, float *r, float *g, float *b) { int i; float f,p,q,t; float s=_s; s /= 100.0; if (s == 0 && h == 0) { *r = *g = *b = v; } else { if (h >= 360.0) h = 0.0; h /= 60.0; i = h; f = h - i; p = v * (1 - s); q = v * (1 - (s * f)); t = v * (1 - (s * (1 - f))); switch (i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } } }