/*ScianColors.c Color management routines for scian Eric Pepke March 15, 1990 */ /* This file is patched to fix some of the problems with the way SciAn version 0.42 allocates colors and figures out how to deal with the bitplanes. It also enhances SciAn to recognize several environment variables: SCIAN_VETO_RGB If in the environment, causes SciAn to veto RGB mode regardless of the machine configuration. SCIAN_FORCE_RGB If in the environment, causes SciAn to force RGB mode regardless of the machine configuration. SCIAN_VETO_CMAP If in the environment, causes SciAn to veto color map mode regardless of the machine configuration. SCIAN_FORCE_CMAP If in the environment, causes SciAn to force color map mode regardless of the machine configuration. SCIAN_VETO_DOUBLE If in the environment, causes SciAn to veto double buffering regardless of the machine configuration. SCIAN_FORCE_DOUBLE If in the environment, causes SciAn to force double buffering regardless of the machine configuration. SCIAN_COLOR_BEG If in the environment with an ASCII number value, causes SciAn to use the given number as the first color in SciAn's portion of the color map. SCIAN_N_COLORS If in the environment with an ASCII number value, causes SciAn to use the given number as the number of colors allocated. */ #include "Scian.h" #include "ScianTypes.h" #include "ScianIDs.h" #include "ScianArrays.h" #include "ScianWindows.h" #include "ScianObjWindows.h" #include "ScianButtons.h" #include "ScianColors.h" #include "ScianEvents.h" #include "ScianErrors.h" #include "ScianScripts.h" #include "ScianPictures.h" #include "ScianControls.h" #include "ScianDialogs.h" #include "ScianSliders.h" #include "ScianDatasets.h" #include "ScianStyle.h" #include "ScianTitleBoxes.h" #include "ScianTextBoxes.h" #include "ScianLists.h" #include "ScianMethods.h" #include "ScianDraw.h" #include "ScianIcons.h" #ifndef GL4D #include "gamtables.h" #endif #ifdef GL4D /*No gamma correction on the 4d*/ #define CVAL(k) k #else /*3000's need gammacorrection*/ #define CVAL(k) LinToGamma[k] #endif /*Simple palette functions*/ #define PF_RAMP 1 /*Interpolate a ramp*/ #define PF_REVERSE 2 /*Reverse range of colors*/ #define PF_RUFFLE 3 /*Ruffle range of colors*/ #define PF_SMOOTH 4 /*Smooth range of colors*/ #define PF_SHARPEN 5 /*Sharpen range of colors*/ /*Color models*/ #define CM_RGB 0 /*RGB color model*/ #define CM_YIQ 1 #define CM_HSV 2 #define CM_HLS 3 #define NCOLORMODELS 4 /*Palette tools*/ #define PT_FREEFORM 0 /*Free form drawing*/ #define PT_SINE 1 /*Sine function*/ #define PT_TRIANGLE 2 /*Triangle function*/ #define PT_SAWTOOTH 3 /*Sawtooth function*/ #define PT_TOOTHSAW 4 /*Toothsaw function*/ #define PT_SQUARE 5 /*Square wave function*/ char *toolNames[6] = { "free form", "sine wave", "triangle wave", "sawtooth wave", "reverse sawtooth wave", "square wave" }; char *componentNames[NCOLORMODELS][3] = { {"red", "green", "blue"}, {"\"Y\"", "\"I\"", "\"Q\""}, {"hue", "saturation", "value"}, {"hue", "lightness", "saturation"} }; char *shortComponentNames[NCOLORMODELS][3] = { {"R", "G", "B"}, {"Y", "I", "Q"}, {"H", "S", "V"}, {"H", "L", "S"} }; real RGB2YIQMat[3][3] = {{ 0.30, 0.59, 0.11}, { 0.60, -0.28, -0.32}, { 0.21, -0.52, 0.31}}; real YIQ2RGBMat[3][3] = {{ 1.0000, 0.9483, 0.6240}, { 1.0000, -0.2761, -0.6398}, { 1.0000, -1.1055, 1.7299}}; Bool hasRGB; /*True iff has RGB*/ Bool hasCmap; /*True iff has color map mode*/ Bool hasDouble; /*True iff has double buffer mode*/ Bool hasZbuf; /*True iff has z buffer mode*/ Bool hasTransparency; /*True iff has transparency*/ int paletteSerialNum = 0; /*Serial num for palettes*/ static int ColorToPixel(ObjPtr, int); static int PixelToColor(ObjPtr, int); typedef struct cr { struct cr *next; /*Next color range*/ int beg, end; /*Beginning and end (+ 1)*/ } ColorRange; ColorRange *colorRanges; /*The available color ranges*/ PPtr activePalettes = 0; /*The active palettes*/ /*Start of UI colors*/ int uiColorBeg; #define COLORWHEELBORDER 6 /*Border around HS control*/ #define COLORWHEELSPOTSIZE 4 /*Size of spot in HS control*/ short uiColors[NUICOLORS][3]; /*Stuff for the UI colors*/ PPtr curPalette; /*Current palette*/ int curNColors; /*Current number of colors*/ real curMin, curMax; /*Current min and max values*/ int curBeg; real diffMult; /*Amount to multiply to get difference*/ short3 *curColors; ObjPtr paletteClass; /*Class for a color palette*/ ObjPtr paletteDisplayClass; /*Class for a palette display*/ ObjPtr colorControlClass; ObjPtr colorWheelClass; ObjPtr colorBarClass; #define COLORFAILTIMEOUT 60 /*Color failure timeout in seconds*/ long colorFailTime = 0; /*Time of last color failure*/ #define COLORWHEELHEIGHT 4 /*Height of a color wheel*/ #ifdef PROTO static void SetColorComponent(PPtr palette, int whichColor, int comp, int cc); static int GetColorComponent(PPtr palette, int whichColor, int comp); #endif #ifdef PROTO void MapPalette(ObjPtr p) #else void MapPalette(p) ObjPtr p; #endif /*Maps palette p*/ { #ifdef GRAPHICS int k; if (hasCmap == false) return; if (((PPtr) p) -> beg < 0) return; for (k = 0; k < ((PPtr) p) -> nColors; ++k) { mapcolor(((PPtr) p) -> beg + k, ((PPtr) p) -> colors[k][0], ((PPtr) p) -> colors[k][1], ((PPtr) p) -> colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void MapPaletteColors(PPtr p, int start, int end) #else void MapPaletteColors(p, start, end) PPtr p; int start; int end; #endif /*Maps color from start to end in palette p*/ { #ifdef GRAPHICS int k; if (hasCmap == false) return; if (((PPtr) p) -> beg < 0) return; for (k = start; k < MAX(((PPtr) p) -> nColors, end + 1); ++k) { mapcolor(((PPtr) p) -> beg + k, ((PPtr) p) -> colors[k][0], ((PPtr) p) -> colors[k][1], ((PPtr) p) -> colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void CopyColorsToComponents(PPtr p, int start, int finish) #else void CopyColorsToComponents(p, start, finish) PPtr p; int start; int finish; #endif /*Copies the colors to components based on color model*/ { ObjPtr var; int cm, k; short3 *colors, *components; real r, g, b, h, s, v, l, y, i, q; var = GetIntVar("CopyColorsToComponents", (ObjPtr) p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } colors = p -> colors; components = p -> components; for (k = start; k <= finish; ++k) { switch (cm) { case CM_RGB: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; case CM_HSV: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2HSV(&h, &s, &v, r, g, b); components[k][0] = h * 255.0 + 0.5; components[k][1] = s * 255.0 + 0.5; components[k][2] = v * 255.0 + 0.5; break; case CM_HLS: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2HLS(&h, &l, &s, r, g, b); components[k][0] = h * 255.0 + 0.5; components[k][1] = l * 255.0 + 0.5; components[k][2] = s * 255.0 + 0.5; break; case CM_YIQ: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2YIQ(&y, &i, &q, r, g, b); components[k][0] = y * 255.0 + 0.5; components[k][1] = i * 255.0 + 0.5; components[k][2] = q * 255.0 + 0.5; break; default: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; } } } #ifdef PROTO void CopyComponentsToColors(PPtr p, int start, int finish) #else void CopyComponentsToColors(p, start, finish) PPtr p; int start; int finish; #endif /*Copies the colors to components based on color model*/ { ObjPtr var; int cm, k; short3 *colors, *components; real r, g, b, h, s, v, l, y, i, q; var = GetIntVar("CopyComponentsToColors", (ObjPtr) p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } colors = p -> colors; components = p -> components; for (k = start; k <= finish; ++k) { switch (cm) { case CM_RGB: colors[k][0] = components[k][0]; colors[k][1] = components[k][1]; colors[k][2] = components[k][2]; break; case CM_HSV: h = ((real) components[k][0]) / 255.0; s = ((real) components[k][1]) / 255.0; v = ((real) components[k][2]) / 255.0; HSV2RGB(&r, &g, &b, h, s, v); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; case CM_HLS: h = ((real) components[k][0]) / 255.0; l = ((real) components[k][1]) / 255.0; s = ((real) components[k][2]) / 255.0; HLS2RGB(&r, &g, &b, h, l, s); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; case CM_YIQ: y = ((real) components[k][0]) / 255.0; i = ((real) components[k][1]) / 255.0; q = ((real) components[k][2]) / 255.0; YIQ2RGB(&r, &g, &b, y, i, q); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; default: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; } } } void CopyColorsToPalette(p, colors) ObjPtr p; short3 *colors; /*Copies the colors into palette p*/ { int k; for (k = 0; k < ((PPtr) p) -> nColors; ++k) { ((PPtr) p) -> colors[k][0] = colors[k][0]; ((PPtr) p) -> colors[k][1] = colors[k][1]; ((PPtr) p) -> colors[k][2] = colors[k][2]; } CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); } ObjPtr MakePaletteName(palette) ObjPtr palette; /*Makes a name for a palette*/ { if (GetVar(palette, NAME)) { return ObjFalse; } else { sprintf(tempStr, "Palette %ld", ++paletteSerialNum); SetVar(palette, NAME, NewString(tempStr)); return ObjTrue; } } void AlertColorFailure() /*Alerts the user that a color allocation has failed*/ { WinInfoPtr errWindow; errWindow = AlertUser(UIRED, (WinInfoPtr) 0, "SciAn has run out of color table entries. It will continue to try to find enough \ colors to run normally. Until it does, you may see some unusual colors in \ some windows.", 0, 0, "Oh well"); SetVar((ObjPtr) errWindow, HELPSTRING, NewString("All the windows of SciAn, as well as the windows of other \ processes, share the same color table. When there are several visualizations \ on the screen, SciAn must share the color table between windows. It tries to \ allocate and deallocate chunks of the color table according to need, but \ sometimes the number of visualizations grows so large that there are simply not \ enough colors to go around.\n\ \n\ SciAn will continue to try to allocate colors. You can reduce the number of \ colors you are using by a number of ways. If your computer can do 24-bit RGB, \ you can set some of the visualization windows to Full Color by clicking on the \ Full Color button at the bottom right of the visualization window. You can close \ visualization windows that you are not using. You can color some of the \ visualizations white or increase visualizations colored by datasets to full \ brightness.")); } void SetPalette(p) ObjPtr p; /*Sets the current palette to p*/ { PPtr tp; tp = (PPtr) p; curPalette = tp; curNColors = tp -> nColors; curMin = tp -> min; curMax = tp -> max; if ((tp -> beg < 0) && (false == rgbp)) { /*Allocate some colors on demand*/ tp -> beg = AllocColors(curNColors); if (tp -> beg >= 0) { /*Allocation succeeded*/ MapPalette(p); curBeg = tp -> beg + 2; } else { /*Allocation failed*/ struct tms buffer; long curTime; curTime = times(&buffer) / HZ; if (curTime > colorFailTime + COLORFAILTIMEOUT) { colorFailTime = curTime; DoUniqueTask(AlertColorFailure); } curNColors = 7; curBeg = uiColorBeg + 2; } } else { curBeg = tp -> beg + 2; } curColors = tp -> colors + 2; diffMult = ((real) curNColors - 4) / (curMax - curMin); } #ifdef PROTO void SetPaletteMinMax(ObjPtr p, real min, real max) #else void SetPaletteMinMax(p, min, max) ObjPtr p; real min, max; #endif /*Sets the min and max of palette p to min and max*/ { ((PPtr) p) -> min = min; ((PPtr) p) -> max = max; SetVar(p, CHANGED, ObjTrue); } static void CompactColors() /*Compacts all the colors*/ { ColorRange *runner; if (colorRanges == 0) { ReportError("CompactColors", "No color ranges"); return; } runner = colorRanges; while (runner && runner -> next) { if (runner -> end >= runner -> next -> beg) { /*Compact two adjacent colors*/ ColorRange *next; runner -> end = runner -> next -> end; next = runner -> next -> next; free(runner -> next); runner -> next = next; } else { runner = runner -> next; } } } static int AllocColors(n) int n; /*Allocates n contiguous colors, returns their start or -1*/ { ColorRange **runner, **bestFit; int fit; /*Fit of best fit so far*/ if (colorRanges == 0) { ReportError("AllocColors", "No color ranges"); return -1; } /*Compact the colors*/ CompactColors(); /*Search for best fit*/ fit = 32767; bestFit = (ColorRange **) 0; runner = &colorRanges; while (*runner) { int nAvailable; nAvailable = (*runner) -> end - (*runner) -> beg; if (nAvailable >= n) { if (nAvailable - n < fit) { fit = nAvailable - n; bestFit = runner; } } runner = &((*runner) -> next); } if (bestFit) { int retVal; retVal = (*bestFit) -> beg; if (fit == 0) { /*Must delete this fit*/ ColorRange *thisFit; thisFit = (*bestFit); free(thisFit); (*bestFit) = (*bestFit) -> next; } else { /*Just need to adjust it*/ (*bestFit) -> beg += n; } return retVal; } else { /*Allocation failed*/ return -1; } } static void FreeColors(start, n) int start, n; /*Frees n contiguous colors at start*/ { ColorRange **runner, *next; if (colorRanges == 0) { ReportError("FreeColors", "No color ranges"); return; } /*Add a new color range at the appropriate point*/ runner = &colorRanges; while (*runner && (*runner) -> beg < start + n) { runner = &((*runner) -> next); } next = *runner; *runner = new(ColorRange); (*runner) -> beg = start; (*runner) -> end = start + n; (*runner) -> next = next; } static void MakeUIColor(whichColor, r, g, b) int whichColor; short r, g, b; /*Makes UI color whichColor to r, g, b*/ { #ifdef GRAPHICS if (hasCmap) { mapcolor(uiColorBeg + whichColor, CVAL(r), CVAL(g), CVAL(b)); } uiColors[whichColor][0] = CVAL(r); uiColors[whichColor][1] = CVAL(g); uiColors[whichColor][2] = CVAL(b); TinyDelay(); #endif } #ifdef PROTO int ClosestUIColor(float clr[3]) #else int ClosestUIColor(clr) float clr[3]; #endif /*Returns the closest UI color to clr*/ { int k; short r, g, b; short bestError; short best; r = clr[0] * 256.0; g = clr[1] * 256.0; b = clr[2] * 256.0; bestError = 5000; /*Big*/ for (k = 0; k < NUICOLORS; ++k) { short error; error = ABS(uiColors[k][0] - r) + ABS(uiColors[k][1] - g) + ABS(uiColors[k][2] - b); if (error < bestError) { bestError = error; best = k; } } return best + uiColorBeg; } static ObjPtr DrawColorWheel(object) ObjPtr object; /*Draws an HS control*/ { #ifdef GRAPHICS int left, right, bottom, top; int cx, cy; int width, height, radius; ObjPtr backColor; /*Color of the background*/ FuncTyp drawContents; /*Routine to draw the contents*/ ObjPtr valueArray; real value[2]; Get2DIntBounds(object, &left, &right, &bottom, &top); /*Draw the control frame*/ DrawButtonFrame(left, right - 1, bottom + 1, top, COLORWHEELHEIGHT, UIGRAY50); /*Draw the color background*/ cx = (left + right) / 2; cy = (bottom + top) / 2; width = right - left; height = top - bottom; if (width > height) { radius = height / 2 - COLORWHEELBORDER; } else { radius = width / 2 - COLORWHEELBORDER; } /*Draw the color wedges*/ SetUIColor(UIRED); arcfi(cx, cy, radius, -300, 300); SetUIColor(UIYELLOW); arcfi(cx, cy, radius, 300, 900); SetUIColor(UIGREEN); arcfi(cx, cy, radius, 900, 1500); SetUIColor(UICYAN); arcfi(cx, cy, radius, 1500, 2100); SetUIColor(UIBLUE); arcfi(cx, cy, radius, 2100, 2700); SetUIColor(UIMAGENTA); arcfi(cx, cy, radius, 2700, 3300); SetUIColor(UIWHITE); setpattern(GREYPAT); circfi(cx, cy, radius * 2 / 3); setpattern(SOLIDPAT); circfi(cx, cy, radius / 3); /*Draw the spot*/ valueArray = GetVar(object, VALUE); if (valueArray) { Array2CArray(value, valueArray); SetUIColor(UIBLACK); cx += radius * value[1] * cos(2.0 * M_PI * value[0]); cy += radius * value[1] * sin(2.0 * M_PI * value[0]); DrawUILine(cx - COLORWHEELSPOTSIZE, cy, cx + COLORWHEELSPOTSIZE, cy, UIBLACK); DrawUILine(cx, cy - COLORWHEELSPOTSIZE, cx, cy + COLORWHEELSPOTSIZE, UIBLACK); } if (!GetPredicate(object, ACTIVATED)) { FillUIGauzeRect(left, right, bottom, top, UIBACKGROUND); } #endif return ObjTrue; } #ifdef PROTO void RGB2YIQ(real *y, real *i, real*q, real r, real g, real b) #else void RGB2YIQ(y, i, q, r, g, b) real *y, *i, *q, r, g, b; #endif /*Converts r, g, b, into y, i, q*/ { *y = RGB2YIQMat[0][0] * r + RGB2YIQMat[0][1] * g + RGB2YIQMat[0][2] * b; *i = RGB2YIQMat[1][0] * r + RGB2YIQMat[1][1] * g + RGB2YIQMat[1][2] * b; *q = RGB2YIQMat[2][0] * r + RGB2YIQMat[2][1] * g + RGB2YIQMat[2][2] * b; *i = (*i + 0.6) / 1.2; *q = (*q + 0.52) / 1.04; if (*y < 0.0) *y = 0.0; if (*y > 1.0) *y = 1.0; if (*i < 0.0) *i = 0.0; if (*i > 1.0) *i = 1.0; if (*q < 0.0) *q = 0.0; if (*q > 1.0) *q = 1.0; } #ifdef PROTO void YIQ2RGB(real *r, real *g, real *b, real y, real i, real q) #else void YIQ2RGB(r, g, b, y, i, q) real y, i, q, *r, *g, *b; #endif /*Converts y, i, q, into r, g, b*/ { i = i * 1.2 - 0.6; q = q * 1.04 - 0.52; *r = YIQ2RGBMat[0][0] * y + YIQ2RGBMat[0][1] * i + YIQ2RGBMat[0][2] * q; *g = YIQ2RGBMat[1][0] * y + YIQ2RGBMat[1][1] * i + YIQ2RGBMat[1][2] * q; *b = YIQ2RGBMat[2][0] * y + YIQ2RGBMat[2][1] * i + YIQ2RGBMat[2][2] * q; if (*r < 0.0) *r = 0.0; if (*r > 1.0) *r = 1.0; if (*g < 0.0) *g = 0.0; if (*g > 1.0) *g = 1.0; if (*b < 0.0) *b = 0.0; if (*b > 1.0) *b = 1.0; } #ifdef PROTO void HSV2RGB(real *r, real *g, real *b, real h, real s, real v) #else void HSV2RGB(r, g, b, h, s, v) real *r, *g, *b, h, s, v; #endif /*Converts h s v into r g b. All within range 0..1 Adapted from Foley & VanDam*/ { int i; real f; real p, q, t; while (h < 0.0) h += 1.0; while (h > 1.0) h -= 1.0; h *= 6; /*h from 0 to 6*/ i = h; f = h - i; /*fractional part of i*/ i %= 6; /*i from 0 to 5*/ p = v * (1.0 - s); q = v * (1.0 - (s * f)); t = v * (1.0 - (s * (1.0 - 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; } } #ifdef PROTO real HLSValue(real n1, real n2, real h) #else real HLSValue(n1, n2, h) real n1; real n2; real h; #endif { while (h < 0.0) h += 1.0; while (h > 1.0) h -= 1.0; if (h < 1.0 / 6.0) { return n1 + (n2 - n1) * h * 6.0; } else if (h < 0.5) { return n2; } else if (h < 4.0 / 6.0) { return n1 + (n2 - n1) * (4.0 / 6.0 - h) * 6.0; } else { return n1; } } #ifdef PROTO void HLS2RGB(real *r, real *g, real *b, real h, real l, real s) #else void HLS2RGB(r, g, b, h, l, s) real *r, *g, *b, h, s, l; #endif /*Converts h l s into r g b. All within range 0..1 Adapted from Foley & VanDam*/ { real m1, m2; if (l <= 0.5) { m2 = l * (1.0 + s); } else { m2 = l + s - l * s; } m1 = 2 * l - m2; if (s == 0) { *r = *g = *b = 1.0; } else { *r = HLSValue(m1, m2, h + 1.0 / 3.0); *g = HLSValue(m1, m2, h); *b = HLSValue(m1, m2, h - 1.0 / 3.0); } } #ifdef PROTO void RGB2HSV(real *h, real *s, real *v, real r, real g, real b) #else void RGB2HSV(h, s, v, r, g, b) real r, g, b, *h, *s, *v; #endif /*Converts rgb to hsv. All numbers within range 0 to 1.*/ { real max, min; max = MAX(r, MAX(g, b)); min = MIN(r, MIN(g, b)); *v = max; if (max > 0.0) { *s = (max - min) / max; } else { *s = 0; } if (*s > 0.0) { real rc, gc, bc; rc = (max - r) / (max - min); gc = (max - g) / (max - min); bc = (max - b) / (max - min); if (r == max) { *h = (bc - gc) / 6.0; } else if (g == max) { *h = (2.0 + rc - bc) / 6.0; } else { *h = (4.0 + gc - rc) / 6.0; } } else { *h = 0.0; } if (*h < 0.0) *h += 1.0; } #ifdef PROTO void RGB2HLS(real *h, real *l, real *s, real r, real g, real b) #else void RGB2HLS(h, l, s, r, g, b) real r, g, b, *h, *s, *l; #endif /*Converts rgb to hls. All numbers within range 0 to 1.*/ { real max, min; max = MAX(r, MAX(g, b)); min = MIN(r, MIN(g, b)); *l = (max + min) * 0.5; if (max == min) { *s = 0.0; *h = 0.0; } else { real rc, gc, bc; if (*l <= 0.5) { *s = (max - min) / (max + min); } else { *s = (max - min) / (2 - max - min); } rc = (max - r) / (max - min); gc = (max - g) / (max - min); bc = (max - b) / (max - min); if (r == max) { *h = (bc - gc) / 6.0; } else if (g == max) { *h = (2.0 + rc - bc) / 6.0; } else { *h = (4.0 + gc - rc) / 6.0; } } } static ObjPtr TrackColorWheel(object, mouseX, mouseY, flags) ObjPtr object; int mouseX, mouseY; int flags; /*Track a click in an HS control. Double-click snaps to closest pure hue*/ { int left, right, bottom, top; int cx, cy; int width, height, radius; ObjPtr backColor; /*Color of the background*/ FuncTyp drawContents; /*Routine to draw the contents*/ ObjPtr valueArray; real value[2]; int lastX, lastY; /*Last X and Y mouse position*/ int sX, sY; /*Shifted x and y for calculation*/ Bool dontTrack; /*True iff don't track*/ Get2DIntBounds(object, &left, &right, &bottom, &top); if (mouseX < left || mouseX > right || mouseY < bottom || mouseY > top) { return ObjFalse; } if (TOOL(flags) == T_HELP) { ContextHelp(object); return ObjTrue; } if (!GetPredicate(object, ACTIVATED)) return ObjTrue; cx = (left + right) / 2; cy = (bottom + top) / 2; width = right - left; height = top - bottom; if (width > height) { radius = height / 2 - COLORWHEELBORDER; } else { radius = width / 2 - COLORWHEELBORDER; } /*Get the current value of the control*/ valueArray = GetFixedArrayVar("TrackColorWheel", object, VALUE, 1, 2L); if (!valueArray) { return ObjFalse; } Array2CArray(value, valueArray); /*Make laxtX and lastY correspond to value*/ lastX = cx + value[1] * cos(2.0 * M_PI * value[0]); lastY = cy + value[1] * sin(2.0 * M_PI * value[0]); if (flags & F_DOUBLECLICK) { /*Snap current value to closest pure hue*/ if (value[1] < 0.33) { /*White*/ value[1] = 0.0; } else { int testo; /*50 % or 100% saturated something*/ if (value[1] > 0.66) { value[1] = 1.0; } else { value[1] = 0.5; } testo = value[0] * 6.0 + 0.5; value[0] = ((real) testo) / 6.0; } valueArray = NewRealArray(1, 2L); CArray2Array(valueArray, value); SetVar(object, VALUE, valueArray); DrawMe(object); UpdateDrawing(); ChangedValue(object); if (logging) { LogControl(object); } return ObjTrue; } dontTrack = GetPredicate(object, TRACKNOT); InhibitLogging(true); while (Mouse(&mouseX, &mouseY)) { if (mouseX != lastX || mouseY != lastY) { real hue, saturation; /*Mouse has moved. Update.*/ sX = mouseX - cx; sY = mouseY - cy; if (sX == 0 && sY == 0) { /*It's at the origin, so choose 0 for h and s*/ hue = 0.0; saturation = 0.0; } else { /*Hue is angle*/ hue = atan2(((double) sY) / ((double) radius), ((double) sX) / ((double) radius)) / (2.0 * M_PI); while (hue < 0.0) hue += 1.0; /*Saturation is radius, clipped*/ saturation = sqrt(((double) sY) * ((double) sY) + ((double) sX) * ((double) sX)) / ((double) radius); if (saturation > 1.0) saturation = 1.0; if (flags & F_SHIFTDOWN) { if (saturation > 0.66) { saturation = 1.0; } else if (saturation > 0.33) { saturation = 0.5; } else { saturation = 0.0; } } } value[0] = hue; value[1] = saturation; valueArray = NewRealArray(1, 2L); CArray2Array(valueArray, value); SetVar(object, VALUE, valueArray); DrawMe(object); UpdateDrawing(); if (!dontTrack) { ChangedValue(object); } } } if (dontTrack) { ChangedValue(object); } InhibitLogging(false); if (logging) { LogControl(object); } return ObjTrue; } ObjPtr SetColorWheelVal(object, value) ObjPtr object; ObjPtr value; /*Sets the value of the object to value*/ { if (value == NULLOBJ || (IsArray(value) && RANK(value) == 1 && DIMS(value)[0] == 2)) { SetVar(object, VALUE, value); ImInvalid(object); ChangedValue(object); if (logging) { LogControl(object); } return ObjTrue; } else { return ObjFalse; } } static ObjPtr CleanupPalette(palette) ObjPtr palette; /*Cleans up the palette before deleting*/ { PPtr *runner; if (((PPtr) palette) -> beg > 0 && ((PPtr) palette) -> nColors > 0) { /*There are some colors*/ FreeColors(((PPtr) palette) -> beg, ((PPtr) palette) -> nColors); } if (((PPtr) palette) -> colors) { free(((PPtr) palette) -> colors); ((PPtr) palette) -> colors = 0; } if (((PPtr) palette) -> components) { free(((PPtr) palette) -> components); ((PPtr) palette) -> components = 0; } runner = &activePalettes; while (*runner) { if (*runner == (PPtr) palette) { *runner = (*runner) -> next; } else { runner = &((*runner) -> next); } } return ObjTrue; } ObjPtr NewPalette(nColors) int nColors; /*Returns a new palette of nColors, initially set to a grey ramp. Returns 0 if it can't.*/ { int k, colorBeg; PPtr retVal; short3 *colors, *components; colors = (short3 *) malloc(sizeof(short3) * nColors); if (!colors) { OMErr(); return NULLOBJ; } components = (short3 *) malloc(sizeof(short3) * nColors); if (!components) { free(colors); OMErr(); return NULLOBJ; } retVal = (PPtr) NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return (ObjPtr) retVal; } retVal -> next = activePalettes; activePalettes = retVal -> next; retVal -> thing . flags = PALETTE; retVal -> colors = colors; retVal -> components = components; retVal -> beg = -1; retVal -> nColors = nColors; retVal -> min = -1.0; retVal -> max = 1.0; for (k = 0; k < nColors; ++k) { retVal -> colors[k][0] = retVal -> colors[k][1] = retVal -> colors[k][2] = (k + 1) * 255 / nColors; } CopyColorsToComponents(retVal, k, nColors - 1); return (ObjPtr) retVal; } void CopyPalette(d, s) ObjPtr d, s; /*Copies palette s to d*/ { int k; /*Free the colors*/ if (((PPtr) d) -> beg > 0) { FreeColors(((PPtr) d) -> beg, ((PPtr) d) -> nColors); ((PPtr) d) -> beg = -1; } if (((PPtr) d) -> nColors != ((PPtr) s) -> nColors) { SetVar(d, CHANGED, ObjTrue); free(((PPtr) d) -> colors); free(((PPtr) d) -> components); ((PPtr) d) -> colors = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> components = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> nColors = ((PPtr) s) -> nColors; } ((PPtr) d) -> min = ((PPtr) s) -> min; ((PPtr) d) -> max = ((PPtr) s) -> max; for (k = 0; k < ((PPtr) d) -> nColors; ++k) { ((PPtr) d) -> colors[k][0] = ((PPtr) s) -> colors[k][0]; ((PPtr) d) -> colors[k][1] = ((PPtr) s) -> colors[k][1]; ((PPtr) d) -> colors[k][2] = ((PPtr) s) -> colors[k][2]; ((PPtr) d) -> components[k][0] = ((PPtr) s) -> components[k][0]; ((PPtr) d) -> components[k][1] = ((PPtr) s) -> components[k][1]; ((PPtr) d) -> components[k][2] = ((PPtr) s) -> components[k][2]; } SetVar(d, COLORMODEL, GetVar(s, COLORMODEL)); SetVar(d, JUSTCOLORCHANGE, ObjTrue); MapPalette(d); } void SetPaletteNColors(p, nColors) ObjPtr p; int nColors; /*Sets palette to be a nColors palette, doing any necessary resampling.*/ { short3 *oldColors, *colors; short3 *oldComponents, *components; real beg, end, increment; int s1, s2, i, k, comp; int temp; /*Free the colors*/ if (((PPtr) p) -> beg > 0) { FreeColors(((PPtr) p) -> beg, ((PPtr) p) -> nColors); ((PPtr) p) -> beg = -1; } /*Make a new set of colors*/ oldColors = ((PPtr) p) -> colors; colors = (short3 *) malloc(nColors * sizeof(short3)); /*And a new set of components*/ oldComponents = ((PPtr) p) -> components; components = (short3 *) malloc(nColors * sizeof(short3)); /*Copy ov, und, missing*/ colors[0][0] = oldColors[0][0]; colors[0][1] = oldColors[0][1]; colors[0][2] = oldColors[0][2]; colors[1][0] = oldColors[1][0]; colors[1][1] = oldColors[1][1]; colors[1][2] = oldColors[1][2]; colors[nColors - 1][0] = oldColors[((PPtr) p) -> nColors][0]; colors[nColors - 1][1] = oldColors[((PPtr) p) -> nColors][1]; colors[nColors - 1][2] = oldColors[((PPtr) p) -> nColors][2]; increment = ((real) ((PPtr) p) -> nColors - 3) / ((real) nColors - 3); for (k = 0; k < nColors - 2; ++k) { beg = k * increment; end = beg + increment; for (comp = 0; comp < 3; ++comp) { s1 = beg; s2 = end; if (s1 == s2) { /*Chunk of just one color*/ colors[k + 2][comp] = oldColors[s1 + 2][comp]; } else { /*Chunk of more than one color*/ real cum; /*First one*/ cum = (1.0 - (beg - s1)) * oldColors[s1 + 2][comp]; /*Intermediate ones*/ for (i = s1 + 3; i < s2 + 2; ++i) { cum += oldColors[i][comp]; } /*Last one*/ cum += (end - s2) * oldColors[s2 + 2][comp]; cum /= (end - beg); temp = cum + 0.5; if (temp < 0) temp = 0; else if (temp > 255) temp = 255; colors[k + 2][comp] = temp; } } } /*Update nColors*/ ((PPtr) p) -> nColors = nColors; ((PPtr) p) -> colors = colors; ((PPtr) p) -> components = components; /*Free the old colors*/ free(oldColors); free(oldComponents); CopyColorsToComponents((PPtr) p, 0, nColors - 1); SetVar(p, CHANGED, ObjTrue); } #ifdef PROTO void CopyAttenuatedPalette(ObjPtr d, ObjPtr s, real atten) #else void CopyAttenuatedPalette(d, s, atten) ObjPtr d, s; real atten; #endif /*Copies palette s to d, attenuated by d*/ { int k; /*Free the colors*/ if (((PPtr) d) -> beg > 0) { FreeColors(((PPtr) d) -> beg, ((PPtr) d) -> nColors); ((PPtr) d) -> beg = -1; } if (((PPtr) d) -> nColors != ((PPtr) s) -> nColors) { SetVar(d, CHANGED, ObjTrue); free(((PPtr) d) -> colors); ((PPtr) d) -> colors = malloc(sizeof(short3) * ((PPtr) s) -> nColors); free(((PPtr) d) -> components); ((PPtr) d) -> components = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> nColors = ((PPtr) s) -> nColors; } ((PPtr) d) -> min = ((PPtr) s) -> min; ((PPtr) d) -> max = ((PPtr) s) -> max; for (k = 0; k < ((PPtr) d) -> nColors; ++k) { ((PPtr) d) -> colors[k][0] = ((PPtr) s) -> colors[k][0] * atten; ((PPtr) d) -> colors[k][1] = ((PPtr) s) -> colors[k][1] * atten; ((PPtr) d) -> colors[k][2] = ((PPtr) s) -> colors[k][2] * atten; } SetVar(d, JUSTCOLORCHANGE, ObjTrue); CopyColorsToComponents((PPtr) d, 0, ((PPtr) d) -> nColors - 1); MapPalette(d); } ObjPtr ClonePalette(oldPalette) ObjPtr oldPalette; /*Clones a new palette*/ { PPtr retVal; short3 *colors, *components; colors = (short3 *) malloc(sizeof(short3) * ((PPtr) oldPalette) -> nColors); if (!colors) { OMErr(); return oldPalette; } components = (short3 *) malloc(sizeof(short3) * ((PPtr) oldPalette) -> nColors); if (!components) { OMErr(); return oldPalette; } retVal = (PPtr) NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return (ObjPtr) retVal; } retVal -> next = activePalettes; activePalettes = retVal -> next; retVal -> thing . flags = PALETTE; retVal -> colors = colors; retVal -> components = components; retVal -> beg = -1; retVal -> nColors = ((PPtr) oldPalette) -> nColors; CopyPalette((ObjPtr) retVal, oldPalette); return (ObjPtr) retVal; } void InterpPalette(palette, r1, g1, b1, r2, g2, b2) ObjPtr palette; int r1, g1, b1, r2, g2, b2; /*Makes palette be an interpolation between r1, g1, b1, and r2, g2, b2*/ { int k; int n; n = ((PPtr) palette) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { ((PPtr) palette) -> colors[k + 2][0] = (k + 1) * r2 / n + (n - k) * r1 / n; ((PPtr) palette) -> colors[k + 2][1] = (k + 1) * g2 / n + (n - k) * g1 / n; ((PPtr) palette) -> colors[k + 2][2] = (k + 1) * b2 / n + (n - k) * b1 / n; } /*Fill in missing*/ ((PPtr) palette) -> colors[0][0] = 64; ((PPtr) palette) -> colors[0][1] = 64; ((PPtr) palette) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) palette) -> colors[1][0] = ((PPtr) palette) -> colors[2][0]; ((PPtr) palette) -> colors[1][1] = ((PPtr) palette) -> colors[2][1]; ((PPtr) palette) -> colors[1][2] = ((PPtr) palette) -> colors[2][2]; /*Fill in max*/ ((PPtr) palette) -> colors[n + 2][0] = ((PPtr) palette) -> colors[n + 1][0]; ((PPtr) palette) -> colors[n + 2][1] = ((PPtr) palette) -> colors[n + 1][1]; ((PPtr) palette) -> colors[n + 2][2] = ((PPtr) palette) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) palette, 0, ((PPtr) palette) -> nColors - 1); MapPalette(palette); } void BlueToRedPalette(p) ObjPtr p; /*Makes a blue to red palette in p*/ { int k; real hue, r, g, b; int n; n = ((PPtr) p) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { real v = 1.0; /* hue = (((real)(n - k)) / (real) n) * 1.15 - 0.2; */ /* hue = (((real)(n - k)) / (real) n) * 0.8; */ hue = (((real)(n - k)) / (real) n) * 0.9 - 0.1; if (hue < 0.0) {v = 1.0 + (hue * 3.0); hue = 0.0;} HSV2RGB(&r, &g, &b, hue, 1.0, v); ((PPtr) p) -> colors[k + 2][0] = r * 255; ((PPtr) p) -> colors[k + 2][1] = g * 255; ((PPtr) p) -> colors[k + 2][2] = b * 255; } /*Fill in missing*/ ((PPtr) p) -> colors[0][0] = 64; ((PPtr) p) -> colors[0][1] = 64; ((PPtr) p) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) p) -> colors[1][0] = ((PPtr) p) -> colors[2][0]; ((PPtr) p) -> colors[1][1] = ((PPtr) p) -> colors[2][1]; ((PPtr) p) -> colors[1][2] = ((PPtr) p) -> colors[2][2]; /*Fill in max*/ ((PPtr) p) -> colors[n + 2][0] = ((PPtr) p) -> colors[n + 1][0]; ((PPtr) p) -> colors[n + 2][1] = ((PPtr) p) -> colors[n + 1][1]; ((PPtr) p) -> colors[n + 2][2] = ((PPtr) p) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); MapPalette(p); } void GreenToRedPalette(p) ObjPtr p; /*Makes a green to red palette in p*/ { int k; real hue, r, g, b; int n; n = ((PPtr) p) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { hue = ((real)(n - k)) / (real) n * 0.35; HSV2RGB(&r, &g, &b, hue, 1.0, 1.0); ((PPtr) p) -> colors[k + 2][0] = r * 255; ((PPtr) p) -> colors[k + 2][1] = g * 255; ((PPtr) p) -> colors[k + 2][2] = b * 255; } /*Fill in missing*/ ((PPtr) p) -> colors[0][0] = 64; ((PPtr) p) -> colors[0][1] = 64; ((PPtr) p) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) p) -> colors[1][0] = ((PPtr) p) -> colors[2][0]; ((PPtr) p) -> colors[1][1] = ((PPtr) p) -> colors[2][1]; ((PPtr) p) -> colors[1][2] = ((PPtr) p) -> colors[2][2]; /*Fill in max*/ ((PPtr) p) -> colors[n + 2][0] = ((PPtr) p) -> colors[n + 1][0]; ((PPtr) p) -> colors[n + 2][1] = ((PPtr) p) -> colors[n + 1][1]; ((PPtr) p) -> colors[n + 2][2] = ((PPtr) p) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); MapPalette(p); } void DisposePalette(palette) ObjPtr palette; /*Disposes of palette*/ { free(palette); } void SetUIColor(c) int c; /*Sets the current drawing color to user interface color c, regardless of whether the current window is RGB or colormap*/ { #ifdef GRAPHICS if (rgbp) { /*It's an RGB window*/ lmcolor(LMC_COLOR); c3s(uiColors[c]); } else { /*It's a cmap window*/ color(uiColorBeg + c); } #endif } ObjPtr NewColorWheel(left, right, bottom, top, name) int left, right, bottom, top; char *name; /*Makes a new hue/saturation control in left, right, bottom, top*/ { real value[2]; ObjPtr valueArray; ObjPtr retVal; value[0] = 0.0; value[1] = 0.0; valueArray = NewRealArray(1, (long) 2); if (valueArray) { CArray2Array(valueArray, value); retVal = NewObject(colorWheelClass, 0); Set2DIntBounds(retVal, left, right, bottom, top); SetVar(retVal, VALUE, valueArray); SetVar(retVal, NAME, NewString(name)); return retVal; } else { return NULLOBJ; } } static int ColorToPixel(colorBar, clr) ObjPtr colorBar; int clr; /*Returns the horizontal pixel for the color value in clr*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (clr == 0) { /*Missing*/ return left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2; } else if (clr == 1) { /*Underflow*/ return left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2; } else if (clr == nColors - 1) { /*Overflow*/ return right - CBRBORDER - CBBOXWIDTH / 2; } else { /*In the center*/ int r, l; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; return ((clr - 2) * (r - l) + (r - l) / 2) / (nColors - 3) + l; } } static Bool ColorToPixels(int *, int *, ObjPtr, int); static Bool ColorToPixels(lPix, rPix, colorBar, clr) ObjPtr colorBar; int clr; int *lPix, *rPix; /*Returns the horizontal pixelx around the color value in clr*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return false; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (clr == 0) { /*Missing*/ *lPix = left + CBLBORDER + CBLTEXTSPACE + 1; *rPix = left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1; return true; } else if (clr == 1) { /*Underflow*/ *lPix = left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1; *rPix = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1; return true; } else if (clr == nColors - 1) { /*Overflow*/ *lPix = right - CBRBORDER - CBBOXWIDTH + 1; *rPix = right - CBRBORDER - 1; return true; } else { /*In the center*/ int r, l; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; if (clr == 2) { *lPix = l; } else { *lPix = l + (clr - 2) * (r - l) / (nColors - 3) + 1; } *rPix = l + (clr - 1) * (r - l) / (nColors - 3); return true; } } static int PixelToColor(colorBar, pix) ObjPtr colorBar; int pix; /*Returns the color for the horizontal pixel pixel*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (pix < left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP / 2) { /*Missing*/ return 0; } else if (pix < left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP) { /*Underflow*/ return 1; } else if (pix > right - CBRBORDER - CBBOXWIDTH) { /*Overflow*/ return nColors - 1; } else { /*In the center*/ int r, l, retVal; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; retVal = ((pix - l) * (nColors - 3) + (nColors - 3) / 2) / (r - l) + 2; if (retVal >= nColors - 1) { retVal = nColors - 2; } if (retVal < 2) { retVal = 2; } return retVal; } } #undef CEDGE #define CEDGE 3 #ifdef PROTO static void DrawFullButton(int left, int right, int bottom, int top, Bool highlight) #else static void DrawFullButton(left, right, bottom, top, highlight) int left, right, bottom, top; Bool highlight; #endif { #ifdef GRAPHICS Coord v[4][2]; /* bottom */ v[0][0] = left + CEDGE; v[0][1] = bottom + CEDGE; v[1][0] = right - CEDGE; v[1][1] = bottom + CEDGE; v[2][0] = right; v[2][1] = bottom; v[3][0] = left; v[3][1] = bottom; SetUIColor(UIBOTTOMEDGE); polf2(4, v); /* left */ v[0][0] = left; v[0][1] = top; v[1][0] = left + CEDGE; v[1][1] = top - CEDGE; v[2][0] = left + CEDGE; v[2][1] = bottom + CEDGE; v[3][0] = left; v[3][1] = bottom; SetUIColor(UILEFTEDGE); polf2(4,v); /* right */ v[0][0] = right - CEDGE; v[0][1] = top - CEDGE; v[1][0] = right; v[1][1] = top; v[2][0] = right; v[2][1] = bottom; v[3][0] = right - CEDGE; v[3][1] = bottom + CEDGE; SetUIColor(UIRIGHTEDGE); polf2(4,v); /* top */ v[0][0] = left; v[0][1] = top; v[1][0] = right; v[1][1] = top; v[2][0] = right - CEDGE; v[2][1] = top - CEDGE; v[3][0] = left + CEDGE; v[3][1] = top - CEDGE; SetUIColor(UITOPEDGE); polf2(4,v); /* left face of control */ v[0][0] = left + CEDGE; v[0][1] = bottom + CEDGE; v[1][0] = (right + left) / 2; v[1][1] = bottom + CEDGE; v[2][0] = (right + left) / 2; v[2][1] = top - CEDGE; v[3][0] = left + CEDGE; v[3][1] = top - CEDGE; SetUIColor((highlight & 1) ? UIHIBACKGROUND : UIBACKGROUND); polf2(4,v); /* right face of control */ v[0][0] = (right + left) / 2 + 1; v[0][1] = bottom + CEDGE; v[1][0] = right - CEDGE; v[1][1] = bottom + CEDGE; v[2][0] = right - CEDGE; v[2][1] = top - CEDGE; v[3][0] = (right + left) / 2 + 1; v[3][1] = top - CEDGE; SetUIColor((highlight & 2) ? UIHIBACKGROUND : UIBACKGROUND); polf2(4,v); /*Score line*/ DrawUILine((left + right) / 2, top - CEDGE, (left + right) / 2, bottom + CEDGE, UIGRAY25); DrawUILine((left + right) / 2 + 1, top - CEDGE, (left + right) / 2 + 1, bottom + CEDGE, UIWHITE); #endif } #ifdef PROTO static void DrawLeftButton(int left, int right, int bottom, int top, Bool highlight) #else static void DrawLeftButton(left, right, bottom, top, highlight) int left, right, bottom, top; Bool highlight; #endif { #ifdef GRAPHICS Coord v[4][2]; /* bottom */ v[0][0] = left + CEDGE; v[0][1] = bottom + CEDGE; v[1][0] = (right + left) / 2; v[1][1] = bottom + CEDGE; v[2][0] = (right + left) / 2; v[2][1] = bottom; v[3][0] = left; v[3][1] = bottom; SetUIColor(UIBOTTOMEDGE); polf2(4, v); /* left */ v[0][0] = left; v[0][1] = top; v[1][0] = left + CEDGE; v[1][1] = top - CEDGE; v[2][0] = left + CEDGE; v[2][1] = bottom + CEDGE; v[3][0] = left; v[3][1] = bottom; SetUIColor(UILEFTEDGE); polf2(4,v); /* top */ v[0][0] = left; v[0][1] = top; v[1][0] = (right + left) / 2; v[1][1] = top; v[2][0] = (right + left) / 2; v[2][1] = top - CEDGE; v[3][0] = left + CEDGE; v[3][1] = top - CEDGE; SetUIColor(UITOPEDGE); polf2(4,v); /* face of control */ v[0][0] = left + CEDGE; v[0][1] = bottom + CEDGE; v[1][0] = (right + left) / 2; v[1][1] = bottom + CEDGE; v[2][0] = (right + left) / 2; v[2][1] = top - CEDGE; v[3][0] = left + CEDGE; v[3][1] = top - CEDGE; SetUIColor(highlight ? UIHIBACKGROUND : UIBACKGROUND); polf2(4,v); /*Score line*/ DrawUILine((left + right) / 2 + 1, top, (left + right) / 2 + 1, bottom, UIGRAY25); #endif } #ifdef PROTO static void DrawRightButton(int left, int right, int bottom, int top, Bool highlight) #else static void DrawRightButton(left, right, bottom, top, highlight) int left, right, bottom, top; Bool highlight; #endif { #ifdef GRAPHICS Coord v[4][2]; /* bottom */ v[0][0] = (left + right) / 2; v[0][1] = bottom + CEDGE; v[1][0] = right - CEDGE; v[1][1] = bottom + CEDGE; v[2][0] = right; v[2][1] = bottom; v[3][0] = (left + right) / 2; v[3][1] = bottom; SetUIColor(UIBOTTOMEDGE); polf2(4, v); /* right */ v[0][0] = right - CEDGE; v[0][1] = top - CEDGE; v[1][0] = right; v[1][1] = top; v[2][0] = right; v[2][1] = bottom; v[3][0] = right - CEDGE; v[3][1] = bottom + CEDGE; SetUIColor(UIRIGHTEDGE); polf2(4,v); /* top */ v[0][0] = (left + right) / 2; v[0][1] = top; v[1][0] = right; v[1][1] = top; v[2][0] = right - CEDGE; v[2][1] = top - CEDGE; v[3][0] = (left + right) / 2; v[3][1] = top - CEDGE; SetUIColor(UITOPEDGE); polf2(4,v); /* face of control */ v[0][0] = (left + right) / 2; v[0][1] = bottom + CEDGE; v[1][0] = right - CEDGE; v[1][1] = bottom + CEDGE; v[2][0] = right - CEDGE; v[2][1] = top - CEDGE; v[3][0] = (left + right) / 2; v[3][1] = top - CEDGE; SetUIColor(highlight ? UIHIBACKGROUND : UIBACKGROUND); polf2(4,v); /*Score line*/ DrawUILine((left + right) / 2, top, (left + right) / 2, bottom, UIWHITE); #endif } #ifdef PROTO void CalcGoodSteps(double diff, int pixWidth, int minMajorPix, double *majorWidth, int *nMinorSteps) #else void CalcGoodSteps(diff, pixWidth, minMajorPix, majorWidth, nMinorSteps) double diff; int pixWidth; int minMajorPix; double *majorWidth; int *nMinorSteps; #endif /*Calculates good steps for a 10-base scale diff is the difference between minimum and max pixWidth is the width in pixels between minimum and max minMajorPix is the minimum number of pixels between major tics *majorWidth will be the width of a major step *nMinorTics will be the number of minor steps */ { long deltaLog; /*Log of the delta at minimum*/ double minDelta; /*Minimum delta between major tics*/ if (diff <= 0.0) { *majorWidth = 0.0; nMinorSteps = 0; } minDelta = diff * minMajorPix / pixWidth; deltaLog = ((long) (1000.0 + log10((double) minDelta))) - 1000; *majorWidth = pow((double) 10.0, (double) deltaLog); *nMinorSteps = 0; while (*majorWidth < minDelta) { if (*majorWidth < minDelta) { /*Try 2*/ *majorWidth *= 2.0; *nMinorSteps = 2; } if (*majorWidth < minDelta) { /*Try 5*/ *majorWidth *= 2.5; *nMinorSteps = 5; } if (*majorWidth < minDelta) { /*Try 10*/ *majorWidth *= 2.0; *nMinorSteps = 10; } } } void ResetColorBarTools(colorBar) ObjPtr colorBar; /*Resets the tools associated with a color bar*/ { ObjPtr radio, freeFormButton; InhibitLogging(true); freeFormButton = GetVar(colorBar, FREEFORMBUTTON); radio = GetVar(colorBar, TOOLGROUP); if (radio) { /***UPDATE For some reason, this doesn't work properly.*/ SetValue(radio, NewInt(freeFormButton ? (GetPredicate(freeFormButton, ACTIVATED) ? PT_FREEFORM : -1) : PT_FREEFORM)); } InhibitLogging(false); } ObjPtr SetColorBarVal(object, value) ObjPtr object; ObjPtr value; /*Sets the value of the object to value*/ { if (IsArray(value) && RANK(value) == 1 && DIMS(value)[0] == 3) { ObjPtr radio; PPtr repObj; real *elements; elements = ELEMENTS(value); if (elements[0] < 0.0 || elements[0] > 3.0 || elements[1] < 0.0 || elements[2] < 0.0) { ReportError("SetColorBarVal", "Value error"); return ObjFalse; } repObj = (PPtr) GetPaletteVar("SetColorBarVal", object, REPOBJ); if (repObj) { if (elements[1] >= ((real) repObj -> nColors) - 0.5 || elements[2] >= ((real) repObj -> nColors) - 0.5) { ReportError("SetColorBarVal", "Value error"); return ObjFalse; } } SetVar(object, VALUE, value); ImInvalid(object); ChangedValue(object); if (logging) { LogControl(object); } /*Set the edit tool to 0*/ ResetColorBarTools(object); return ObjTrue; } else { ReportError("SetColorBarVal", "Bad value for color bar"); return ObjFalse; } } static ObjPtr ReinitColorBar(colorBar) ObjPtr colorBar; /*Reinitializes a color bar*/ { return ObjTrue; } real GetColorValue(palette, color) ObjPtr palette; int color; /*Gets a field value for center of color color. Ignores missing*/ { return ((PPtr) palette) -> min + (color - 2) * (((PPtr) palette) -> max - ((PPtr) palette) -> min) / (((PPtr) palette) -> nColors - 4); } static int hueColors[7] = { UIRED, UIYELLOW, UIGREEN, UICYAN, UIBLUE, UIMAGENTA, UIRED }; #ifdef PROTO static void ColorModelRect(int left, int right, int bottom, int top, int cm, int k) #else static void ColorModelRect(left, right, bottom, top, cm, k) int left; int right; int bottom; int top; int cm; int k; #endif /*Fills a rectangle within the bounds for color model cm in field k*/ { switch (cm) { case CM_RGB: FillUIRect(left, right, bottom, top, k == 1 ? UIBLUE : k == 2 ? UIGREEN : UIRED); break; case CM_HSV: case CM_HLS: shademodel(GOURAUD); if (k == 3) { /*Hue*/ int c; long v[2]; bgnpolygon(); SetUIColor(UIRED); v[1] = bottom; v[0] = left; v2i(v); v[0] = right + 1; v2i(v); for (c = 1; c < 5; ++c) { SetUIColor(hueColors[c]); v[1] = bottom + (top - bottom) * c / 6; v[0] = right + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v2i(v); v[0] = right + 1; v2i(v); } SetUIColor(hueColors[c]); v[1] = top + 1; v[0] = right + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if ((cm == CM_HSV && k == 2) || (cm == CM_HLS && k == 1)) { /*Saturation*/ long v[2]; bgnpolygon(); SetUIColor(UIWHITE); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if (cm == CM_HSV) { /*Must be value*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else { /*Must be lightness*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = (top + bottom) / 2; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v[0] = left; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIWHITE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } shademodel(FLAT); break; case CM_YIQ: shademodel(GOURAUD); if (k == 3) { /*Must be y*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = (top + bottom) / 2; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v[0] = left; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIWHITE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if (k == 2) { /*i, cyan/orange index*/ long v[2]; bgnpolygon(); SetUIColor(UICYAN); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIORANGE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else { /*q, green/magenta axis*/ long v[2]; bgnpolygon(); SetUIColor(UIGREEN); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIMAGENTA); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } shademodel(FLAT); break; } } static ObjPtr DrawColorBar(colorBar) ObjPtr colorBar; /*Draws a color bar*/ { int left, right, bottom, top; int l, r, b, t; int start, diff, comp; PPtr palette; int nColors; short3 *colors; ObjPtr value; /*Value of the control*/ real *elements; ObjPtr var; int highlighted; int k; double majorWidth, minorWidth; /*Width of a major step*/ double ddiff; /*Data difference*/ int nTics; /*Number of minor tics*/ long temp; double halfSpace; int pixel; /*Temporary pixel*/ double curValue; /*Current value for making tics*/ int cm; /*Color model in use*/ #ifdef GRAPHICS Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the palette*/ palette = (PPtr) GetPaletteVar("DrawColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*Get the stuff from the palette*/ nColors = palette -> nColors; colors = palette -> colors; /*Draw the bump and plateau*/ DrawBumpEdge(left, right, bottom, top); FillUIRect(left + 3, right - 3, bottom + 3, top - 3, UIBACKGROUND); /*Draw the legends and tic marks and stuff at the bottom*/ SetUIColor(UIBLACK); SetupFont(CBTEXTFONT, CBTEXTSIZE); b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; DrawString( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2 - StrWidth("Missing") / 2, bottom + CBBORDER + CBTEXTUP, "Missing"); DrawUILine( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); DrawString( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2 - StrWidth("Under") / 2, bottom + CBBORDER + CBTEXTUP, "Under"); DrawUILine( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); /*Draw all the tics in the middle*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = palette -> min / majorWidth; curValue = temp * majorWidth; while (curValue > palette -> min) { curValue -= majorWidth; } k = 0; while (curValue < palette -> min) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= palette -> max + ddiff * 1.0E-6) { pixel = l + (curValue - palette -> min) * (r - l) / (ddiff); if (k == 0) { /*Major tic*/ DrawUILine(pixel, b, pixel, b - CBMAJORTICLEN, UIBLACK); sprintf(tempStr, "%lg", curValue); DrawString(pixel - StrWidth(tempStr) / 2, b - CBTEXTSEP, tempStr); } else { /*Minor tic*/ DrawUILine(pixel, b, pixel, b - CBMAJORTICLEN / 2, UIBLACK); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } DrawString( right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2 - StrWidth("Over") / 2, bottom + CBBORDER + CBTEXTUP, "Over"); DrawUILine( right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2, b, right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); /*Get the color model*/ var = GetIntVar("DrawColorBar", (ObjPtr) palette, COLORMODEL); if (!var) { return ObjFalse; } cm = GetInt(var); /*Draw the boxes*/ b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; SetupFont(CBBIGTEXTFONT, CBBIGTEXTSIZE); for (k = 0; k < 4; ++k) { t = b + CBCOMPHEIGHT; /*Draw the box outlines*/ /*Draw the missing data box*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH, b, t, UIBLACK); /*Now the underflow box*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP, b, t, UIBLACK); /*Now the middle bit*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP, right - CBRBORDER - CBBOXWIDTH - CBHGAP, b, t, UIBLACK); /*Now the overflow box*/ FrameUIRect(right - CBRBORDER - CBBOXWIDTH, right - CBRBORDER, b, t, UIBLACK); /*Draw the background of the boxex*/ /*Draw the missing data box*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, b + 1, t - 1, cm, k); /*Now the underflow box*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, b + 1, t - 1, cm, k); /*Now the middle bit*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1, right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1, b + 1, t - 1, cm, k); /*Now the overflow box*/ ColorModelRect(right - CBRBORDER - CBBOXWIDTH + 1, right - CBRBORDER - 1, b + 1, t - 1, cm, k); /*Now the component names*/ if (k) { SetUIColor(UIBLACK); DrawString(left + CBLBORDER, (b + t) / 2 - CBCOMPTEXTDOWN, shortComponentNames[cm][3 - k]); } b = t + CBVGAP; } /*Now the expanded readout*/ FrameUIRect(left + CBLBORDER, right - CBRBORDER, b, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, UIBLACK); b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 1; t = b + CBCOMPHEIGHT - 2; /*Now draw the colors*/ if (rgbp) { /*It's in RGB mode, so we don't have to set the palette*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; /*Do missing data box*/ c3s(colors[0]); rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t); /*Do underflow data box*/ c3s(colors[1]); rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, b, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t); /*Do the colors in the center*/ diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; c3s(colors[k]); rectfi(l, b, r, t); l = r + 1; } /*Do overflow data box*/ c3s(colors[nColors - 1]); rectfi( right - CBRBORDER - CBBOXWIDTH + 1, b, right - CBRBORDER - 1, t); } else { /*It's a color map window, have to set the colors*/ int beg; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; SetPalette((ObjPtr) palette); beg = palette -> beg; /*Do missing data box*/ color(beg); rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t); /*Do underflow data box*/ color(beg + 1); rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, b, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t); /*Do the colors in the center*/ diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; color(beg + k); rectfi(l, b, r, t); l = r + 1; } /*Do overflow data box*/ color(beg + nColors - 1); rectfi( right - CBRBORDER - CBBOXWIDTH + 1, b, right - CBRBORDER - 1, t); } b = t + CBVGAP + 2; t = b + CBCOMPHEIGHT - 1; /*Do 3 components*/ for (comp = 2; comp >= 0; --comp) { int height; SetUIColor(UIGRAY62); /*Do missing data box*/ height = GetColorComponent(palette, 0, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, t - CBCOMPHEIGHT + height + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t - 1); } /*Do underflow data box*/ height = GetColorComponent(palette, 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, t - CBCOMPHEIGHT + height + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t - 1); } /*Do the colors in the center*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; height = GetColorComponent(palette, k, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi(l, t - CBCOMPHEIGHT + height + 1, r, t - 1); } l = r + 1; } /*Overflow*/ height = GetColorComponent(palette, nColors - 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi(right - CBRBORDER - CBBOXWIDTH + 1, t - CBCOMPHEIGHT + height + 1, right - CBRBORDER - 1, t - 1); } b = t + CBVGAP + 1; t = b + CBCOMPHEIGHT - 1; } /*Now deal with the value*/ value = GetValue(colorBar); if (!value) { /*Have to give it a value*/ value = NewRealArray(1, 3L); elements = ELEMENTS(value); elements[0] = 0.0; elements[1] = 0.0; elements[2] = 0.0; } else { elements = ELEMENTS(value); } if (elements[0] >= 0.5) { /*Draw the selection in the magnified area*/ int dummy; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + ((int) (elements[0] - 0.5)) * (CBVGAP + CBCOMPHEIGHT); t = b + CBCOMPHEIGHT; ColorToPixels(&l, &dummy, colorBar, (int) (elements[1] + 0.5)); ColorToPixels(&dummy, &r, colorBar, (int) (elements[2] + 0.5)); FrameUIRect(l - 1, r + 3, b - 2, t, UIBLACK); FrameUIRect(l - 2, r + 1, b, t + 1, UIYELLOW); FrameUIRect(l - 3, r + 2, b - 1, t + 2, UIYELLOW); /*Draw the expanded range*/ if (elements[0] == 1.0) { int c1, c2; /*Draw the full color*/ l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; if (rgbp) { /*It's in RGB mode, so we don't have to set the palette*/ /*Do the colors in the center*/ diff = r - l; start = l; c1 = elements[1]; c2 = elements[2]; for (k = c1; k <= c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; c3s(colors[k]); rectfi(l, b, r, t); l = r + 1; } } else { /*It's a color map window, have to set the colors*/ int beg; SetPalette((ObjPtr) palette); beg = palette -> beg; /*Do the colors in the center*/ diff = r - l; start = l; c1 = elements[1]; c2 = elements[2]; for (k = c1; k <=c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; color(beg + k); rectfi(l, b, r, t); l = r + 1; } } } else { int c1, c2; int height; c1 = elements[1]; c2 = elements[2]; comp = 4 - ((int) elements[0]); l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; ColorModelRect(l, r, b, t, cm, (int) elements[0] - 1); SetUIColor(UIGRAY62); /*Do the colors in the center*/ diff = r - l; start = l; for (k = c1; k <= c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; height = GetColorComponent(palette, k, comp) * (t - b) / 255.0 + 0.5; if (height < t - b) { rectfi(l, b + height, r, t); } l = r + 1; } } } /*Draw the tics at the top*/ if (elements[0] > 0.0) { real start, finish, halfSpace; l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; if (elements[2] >= elements[1]) { /*It's a range*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, (int) elements[1]) - halfSpace; finish = GetColorValue((ObjPtr) palette, (int) elements[2]) + halfSpace; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = start / majorWidth; curValue = temp * majorWidth; while (curValue > start) { curValue -= majorWidth; } k = 0; while (curValue < start) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } SetupFont(CBBIGTEXTFONT, CBBIGTEXTSIZE); /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= finish + ddiff * 1.0E-6) { int strOff; pixel = l + (curValue - start) * (r - l) / (ddiff); if (k == 0) { /*Major tic*/ DrawUILine(pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP + CBMAJORTICLEN, UIBLACK); sprintf(tempStr, "%lg", curValue); strOff = StrWidth(tempStr) / 2; if (pixel - strOff > l - CBLBORDER && pixel + strOff < r + CBRBORDER) { DrawString(pixel - strOff, top - CBTBORDER - CBTEXTDOWN, tempStr); } } else { /*Minor tic*/ DrawUILine(pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP + CBMAJORTICLEN / 2, UIBLACK); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } /*Draw the function box, if any*/ var = GetVar(colorBar, FUNCTIONBOX); if (var) { int boxL, boxR, boxB, boxT, boxX, boxY; real *elements; elements = ELEMENTS(var); boxL = l + (elements[0] - start) * (r - l) / (ddiff); boxR = l + (elements[1] - start) * (r - l) / (ddiff); boxB = b + elements[2] * (t - b) / 255.0; boxT = b + elements[3] * (t - b) / 255.0; boxX = (boxL + boxR) / 2; boxY = (boxB + boxT) / 2; SetClipRect(left + 3, right - 3, bottom + 3, top - 3); /*Now draw the box and its handles*/ FrameUIRect(boxL + 1, boxR + 2, boxB - 2, boxT - 1, UIBLACK); FrameUIRect(boxL + 1 - CBHANDLESIZE, boxL + 1, boxY - 1 - CBHANDLESIZE / 2, boxY - 1 + CBHANDLESIZE / 2, UIBLACK); FrameUIRect(boxR + 2, boxR + 2 + CBHANDLESIZE, boxY - 1 - CBHANDLESIZE / 2, boxY - 1 + CBHANDLESIZE / 2, UIBLACK); FrameUIRect(boxX + 2 - CBHANDLESIZE / 2, boxX + 2 + CBHANDLESIZE / 2, boxT - 1, boxT - 1 + CBHANDLESIZE, UIBLACK); FrameUIRect(boxX + 2 - CBHANDLESIZE / 2, boxX + 2 + CBHANDLESIZE / 2, boxB - 2 - CBHANDLESIZE, boxB - 2, UIBLACK); FrameUIRect(boxL, boxR, boxB, boxT, UIYELLOW); FrameUIRect(boxL - 1, boxR + 1, boxB - 1, boxT + 1, UIYELLOW); FillUIRect(boxL - 1 - CBHANDLESIZE, boxL, boxY - CBHANDLESIZE / 2, boxY + 1 + CBHANDLESIZE / 2, UIYELLOW); FillUIRect(boxR, boxR + 1 + CBHANDLESIZE, boxY - CBHANDLESIZE / 2, boxY + 1 + CBHANDLESIZE / 2, UIYELLOW); FillUIRect(boxX - CBHANDLESIZE / 2, boxX + 1 + CBHANDLESIZE / 2, boxT, boxT + 1 + CBHANDLESIZE, UIYELLOW); FillUIRect(boxX - CBHANDLESIZE / 2, boxX + 1 + CBHANDLESIZE / 2, boxB - 1 - CBHANDLESIZE, boxB, UIYELLOW); RestoreClipRect(); } } } #endif return ObjTrue; } ObjPtr SetFunctionBox(colorBar, functionBox) ObjPtr colorBar; ObjPtr functionBox; /*Sets the FUNCTIONBOX of colorBar to functionBox, also logs*/ { real *elements; PPtr repObj; if (functionBox && (!IsArray(functionBox) || RANK(functionBox) != 1 || DIMS(functionBox)[0] != 4)) { ReportError("SetFunctionBox", "Bad value given"); return ObjFalse; } repObj = (PPtr) GetPaletteVar("SetFunctionBox", colorBar, REPOBJ); if (!repObj) { return ObjFalse; } if (functionBox) { elements = ELEMENTS(functionBox); if (elements[2] < -0.5 || elements[2] >= 255.5 || elements[3] < -0.5 || elements[3] >= 255.5 || elements[2] > elements[3] || elements[0] > elements[1]) { ReportError("SetFunctionBox", "Value out of range"); return ObjFalse; } } SetVar(colorBar, FUNCTIONBOX, functionBox); if (logging) { char cmd[256]; char *s; sprintf(cmd, "set functionbox "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, colorBar); while (*s) ++s; *s++ = ' '; PrintScriptObject(s, functionBox); while (*s) ++s; *s++ = '\n'; *s = 0; Log(cmd); } return ObjTrue; } void LogColorChange(colorBar, colors, newColor) ObjPtr colorBar; short3 *colors; int newColor; /*Logs a change to colors[newColor] within colorBar*/ { if (logging) { char cmd[256]; char *s; sprintf(cmd, "set color "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, colorBar); while (*s) ++s; *s++ = ' '; sprintf(s, "%d %d %d %d\n", newColor, colors[newColor][0], colors[newColor][1], colors[newColor][2]); Log(cmd); } } ObjPtr SetColorBarColor(colorBar, whichColor, r, g, b) ObjPtr colorBar; int whichColor, r, g, b; /*Sets color whichColor from inside a color bar*/ { PPtr palette; short3 *colors; palette = (PPtr) GetPaletteVar("SetColorBarColor", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colors = palette -> colors; colors[whichColor][0] = r; colors[whichColor][1] = g; colors[whichColor][2] = b; ImInvalid(colorBar); LogColorChange(colorBar, colors, whichColor); ChangedValue(colorBar); CopyColorsToComponents(palette, whichColor, whichColor); #ifdef GRAPHICS MapPaletteColors(palette, whichColor, whichColor); #endif } static ObjPtr PressColorBar(colorBar, x, y, flags) ObjPtr colorBar; int x, y; int flags; /*Does a press in a color bar beginning at x and y. Returns true iff the press really was in the control.*/ { #ifdef INTERACTIVE int left, right, bottom, top; int l, r, b, t; int k; int cm; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); if (x >= left && x <= right && y >= bottom && y <= top) { real val[3]; ObjPtr value, var; real *origVal; ObjPtr palette; /*Hey! It really was a click in the time control*/ if (TOOL(flags) == T_HELP) { ContextHelp(colorBar); return ObjTrue; } b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; if (y < b) { /*Click below*/ val[0] = val[1] = val[2] = 0.0; value = NewRealArray(1, 3L); CArray2Array(value, val); SetValue(colorBar, value); return ObjTrue; } /*Get current value*/ value = GetFixedArrayVar("PressColorBar", colorBar, VALUE, 1, 3L); if (!value) { return ObjFalse; } origVal = (real *) ELEMENTS(value); palette = (ObjPtr) GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*Get the color model*/ var = GetIntVar("PressColorBar", (ObjPtr) palette, COLORMODEL); if (!var) { return ObjFalse; } cm = GetInt(var); /*See if it's in one of the components or full color*/ for (k = 0; k < 4; ++k) { t = b + CBCOMPHEIGHT; if (y <= t && y >= b) { ObjPtr radio; int newX, newY; int startColor; int lastColor; int newColor; Bool inp; /*True if inside*/ /*It's a press in track k*/ InhibitLogging(true); if ((flags & F_SHIFTDOWN) || TOOL(flags) == T_ROTATE) { /*Shift click, determine start from farthest*/ newColor = PixelToColor(colorBar, x); if (ABS(newColor - origVal[2]) < ABS(newColor - origVal[1])) { startColor = origVal[1]; } else { startColor = origVal[2]; } } else { startColor = PixelToColor(colorBar, x); } lastColor = -1; val[0] = (real) (k + 1); inp = true; /*Set the edit tool to free form*/ ResetColorBarTools(colorBar); while (Mouse(&newX, &newY)) { if (newY > t + SLOP || newY < b - SLOP || newX < left - SLOP || newX > right + SLOP) { /*It's outside*/ if (inp) { /*Transition from in to out*/ SetVar(colorBar, VALUE, value); ChangedValue(colorBar); inp = false; lastColor = -1; DrawMe(colorBar); } } else { /*It's inside*/ if (!inp) { /*Transition from out to in*/ inp = true; } newColor = PixelToColor(colorBar, newX); if (newColor != lastColor) { ObjPtr var; /*It's a new color, set it*/ if (newColor >= startColor) { val[1] = (real) startColor; val[2] = (real) newColor; } else { val[2] = (real) startColor; val[1] = (real) newColor; } var = NewRealArray(1, 3L); CArray2Array(var, val); SetVar(colorBar, VALUE, var); ChangedValue(colorBar); DrawMe(colorBar); lastColor = newColor; } } } InhibitLogging(false); LogControl(colorBar); return ObjTrue; } b = t + CBVGAP; } /*It wasn't in a component, maybe it's in the readout*/ t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; if (origVal[0] > 1.0 && y >= b - SLOP && y <= t + SLOP && x >= l - SLOP && x <= r + SLOP) { /*It is! Do stuff based on edit mode*/ int editMode; int lastColor, lastAmp; PPtr palette; int index1, index2; int k; int comp; short3 *colors; int newX, newY, newColor, newAmp; ObjPtr panel, button; palette = (PPtr) GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colors = palette -> colors; comp = 4 - origVal[0]; var = GetIntVar("PressColorBar", colorBar, EDITMODE); if (!var) { return ObjFalse; } editMode = GetInt(var); index1 = origVal[1] + 0.5; index2 = origVal[2] + 0.5; panel = GetVar(colorBar, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } if (editMode == PT_FREEFORM) { int firstAltered, lastAltered; Bool constrainX, constrainY; /*Free form*/ lastColor = lastAmp = -1; firstAltered = index2 + 1; lastAltered = index1 - 1; constrainX = constrainY = false; while (Mouse(&newX, &newY)) { if (newX >= l - SLOP && newX <= r + SLOP && newY >= b - SLOP && newY <= t + SLOP) { if (flags & F_SHIFTDOWN) { if (!constrainX && !constrainY) { int xDiff, yDiff; /*Must make some constraints*/ xDiff = ABS(newX - x); yDiff = ABS(newY - y); if (xDiff >= MINCONSTRAINT && yDiff >= MINCONSTRAINT) { if (yDiff > xDiff) { constrainX = true; } else { constrainY = true; } } } if (constrainX) newX = x; if (constrainY) newY = y; } /*Calculate newAmp*/ newAmp = ((newY - b) + 0.5) * 255.0 / (real) (t - b - 1); if (newAmp < 0) newAmp = 0; else if (newAmp > 255) newAmp = 255; /*Calculate newColor*/ newColor = index1 + ((real) newX - l) * ((real) index2 - index1 + 1) / ((real) (r - l - 1)); if (newColor < index1) newColor = index1; else if (newColor > index2) newColor = index2; if (newColor < firstAltered) { firstAltered = newColor; } if (newColor > lastAltered) { lastAltered = newColor; } if (newAmp != lastAmp || newColor != lastColor) { /*Set the new color to be correct*/ if (lastColor <= -1 || lastColor == newColor) { /*New in this range, just set this color*/ SetColorComponent(palette, newColor, comp, newAmp); #ifdef GRAPHICS MapPaletteColors(palette, newColor, newColor); #endif } else if (newColor > lastColor) { int nc; /*Linearly interpolate up to this color*/ for (k = lastColor + 1; k <= newColor; ++k) { nc = ((newColor - k) * lastAmp + (k - lastColor) * newAmp) / (newColor - lastColor); if (nc < 0) nc = 0; else if (nc > 255) nc = 255; SetColorComponent(palette, k, comp, nc); } #ifdef GRAPHICS MapPaletteColors(palette, lastColor, newColor); #endif } else if (newColor < lastColor) { int nc; /*Linearly interpolate down to this color*/ for (k = lastColor - 1; k >= newColor; --k) { nc = ((k - newColor) * lastAmp + (lastColor - k) * newAmp) / (lastColor - newColor); if (nc < 0) nc = 0; else if (nc > 255) nc = 255; SetColorComponent(palette, k, comp, nc); } #ifdef GRAPHICS MapPaletteColors(palette, lastColor, newColor); #endif } ChangedValue(colorBar); DrawMe(colorBar); lastAmp = newAmp; lastColor = newColor; } } else { lastColor = lastAmp = -1; } } for (k = firstAltered; k <= lastAltered; ++k) { LogColorChange(colorBar, colors, k); } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); } else { /*It's a tool*/ ObjPtr toolBounds; int boxL, boxR, boxB, boxT; int xOffset, yOffset; double start, finish, ddiff, halfSpace; real *elements; real newElements[4]; int whichMove = 0; real lastSide, nextSide; double majorWidth, minorWidth; int nTics; long temp; #define MOVEBOXTOP 1 #define MOVEBOXBOTTOM 2 #define MOVEBOXLEFT 3 #define MOVEBOXRIGHT 4 #define MOVEBOXLR 5 halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, index1) - halfSpace; finish = GetColorValue((ObjPtr) palette, index2) + halfSpace; ddiff = finish - start; toolBounds = GetFixedArrayVar("PressColorBar", colorBar, FUNCTIONBOX, 1, 4L); if (!toolBounds) { return ObjFalse; } elements = ELEMENTS(toolBounds); boxL = l + (elements[0] - start) * (r - l) / (ddiff); boxR = l + (elements[1] - start) * (r - l) / (ddiff); boxB = b + elements[2] * (t - b) / 255.0; boxT = b + elements[3] * (t - b) / 255.0; /*Figure out which side is clicked on*/ whichMove = 0; if (y >= boxB - (CBHANDLESIZE + 2) && y <= boxT + (CBHANDLESIZE + 2)) { if (x >= boxL - (CBHANDLESIZE + 2) && x <= boxL) { whichMove = MOVEBOXLEFT; xOffset = x - boxL; } else if (x >= boxR && x <= boxR + (CBHANDLESIZE + 2)) { whichMove = MOVEBOXRIGHT; xOffset = x - boxR; } } if (x >= boxL - (CBHANDLESIZE + 2) && x <= boxR + (CBHANDLESIZE + 2)) { if (y >= boxB - (CBHANDLESIZE + 2) && y <= boxB) { whichMove = MOVEBOXBOTTOM; yOffset = y - boxB; } else if (y >= boxT && y <= boxT + (CBHANDLESIZE + 2)) { whichMove = MOVEBOXTOP; yOffset = y - boxT; } } if (!whichMove) { whichMove = MOVEBOXLR; xOffset = x - boxL; yOffset = y - (boxT + boxB) / 2; } newElements[0] = elements[0]; newElements[1] = elements[1]; newElements[2] = elements[2]; newElements[3] = elements[3]; if (flags & F_SHIFTDOWN) { /*Constrained motion, have to calc constraint stuff*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, index1) - halfSpace; finish = GetColorValue((ObjPtr) palette, index2) + halfSpace; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; } /*Now do it*/ if (whichMove == MOVEBOXLEFT || whichMove == MOVEBOXRIGHT) { lastSide = newElements[whichMove == MOVEBOXLEFT ? 0 : 1]; while (Mouse(&newX, &newY)) { nextSide = start + (newX - xOffset - l) * (finish - start) / (r - l); if (flags & F_SHIFTDOWN) { /*Constrain*/ temp = nextSide / minorWidth + 0.5; nextSide = temp * minorWidth; } if (nextSide != lastSide) { /*Change it*/ newElements[whichMove == MOVEBOXLEFT ? 0 : 1] = nextSide; if (newElements[1] > newElements[0]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastSide = nextSide; } } } } else if (whichMove == MOVEBOXTOP || whichMove == MOVEBOXBOTTOM) { lastAmp = newElements[whichMove == MOVEBOXBOTTOM ? 2 : 3] + 0.5; while (Mouse(&newX, &newY)) { newAmp = ((newY - yOffset - b) + 0.5) * 255.0 / (real) (t - b - 1); if (newAmp < 0) newAmp = 0; else if (newAmp > 255) newAmp = 255; if (newAmp != lastAmp) { /*Change it*/ newElements[whichMove == MOVEBOXBOTTOM ? 2 : 3] = newAmp; if (newElements[3] > newElements[2]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastAmp = newAmp; } } } } if (whichMove == MOVEBOXLR) { lastSide = newElements[0]; while (Mouse(&newX, &newY)) { nextSide = start + (newX - xOffset - l) * (finish - start) / (r - l); if (flags & F_SHIFTDOWN) { /*Constrain*/ temp = nextSide / minorWidth + 0.5; nextSide = temp * minorWidth; } if (nextSide != lastSide) { /*Change it*/ newElements[0] = nextSide; newElements[1] = nextSide + elements[1] - elements[0]; if (newElements[1] > newElements[0]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastSide = nextSide; } } } } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); } } return ObjTrue; } else { return ObjFalse; } #else return ObjFalse; #endif } ObjPtr NewColorBar(left, right, bottom, top, name) int left, right, bottom, top; char *name; /*Makes a new hue/saturation control in left, right, bottom, top*/ { ObjPtr retVal; ObjPtr value; retVal = NewObject(colorBarClass, 0); Set2DIntBounds(retVal, left, right, bottom, top); SetVar(retVal, NAME, NewString(name)); SetVar(retVal, TYPESTRING, NewString("color bar control")); value = NewRealArray(1, 3L); ((real *) ELEMENTS(value))[0] = 1.0; ((real *) ELEMENTS(value))[1] = 0.0; ((real *) ELEMENTS(value))[1] = 0.0; SetVar(retVal, VALUE, value); return retVal; } #ifdef PROTO static void ChoosePaletteSliderValue(ObjPtr, PPtr, int, int, int); #endif static void ChoosePaletteSliderValue(slider, palette, component, index1, index2) ObjPtr slider; PPtr palette; int index1, index2, component; /*Chooses a value for the slider based on colors index1 through index2 of palette. Component is 0 for rgb, 1 for r, 2 for g, and 3 for b, */ { real min, max, testVal; short3 *colors; real hsv[3]; int k; colors = palette -> colors; min = 1.0; max = 0.0; if (component) { for (k = index1; k <= index2; ++k) { testVal = ((real) GetColorComponent(palette, k, component - 1)) / 255.0; if (testVal < min) { min = testVal; } if (testVal > max) { max = testVal; } } } else { for (k = index1; k <= index2; ++k) { RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), ((real) colors[k][0]) / 255.0, ((real) colors[k][1]) / 255.0, ((real) colors[k][2]) / 255.0); testVal = hsv[2]; if (testVal < min) { min = testVal; } if (testVal > max) { max = testVal; } } } testVal = (min + max) * 0.5; if (testVal < 0.0) testVal = 0.0; if (testVal > 1.0) testVal = 1.0; SetSliderValue(slider, testVal); SetVar(slider, INITVALUE, NewReal(testVal)); SetVar(slider, TEMPPALETTE, ClonePalette((ObjPtr) palette)); } static ObjPtr ChangePaletteBar(colorBar) ObjPtr colorBar; /*Changed value for a color bar that controls a palette*/ { ObjPtr colorWheel, slider, button, buttons; ThingListPtr buttonList; PPtr palette; ObjPtr value, newValue; FuncTyp changedValue; real hsv[3]; short3 *colors; int index; real *elements; value = GetFixedArrayVar("ChangePaletteBar", colorBar, VALUE, 1, 3L); colorWheel = GetObjectVar("ChangePaletteBar", colorBar, COLORWHEEL); palette = (PPtr) GetPaletteVar("ChangePaletteBar", colorBar, REPOBJ); slider = GetObjectVar("ChangePaletteBar", colorBar, SLIDER); if (!colorWheel || !palette || !value || !slider) { return ObjFalse; } elements = ELEMENTS(value); if (elements[0] == 1.0) { /*Active color wheel*/ ActivateColorWheel(colorWheel, true); if (elements[1] == elements[2]) { /*Give it a value*/ colors = palette -> colors; /*Update the left slider and color wheel*/ index = elements[1]; RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), ((real) colors[index][0]) / 255.0, ((real) colors[index][1]) / 255.0, ((real) colors[index][2]) / 255.0); if (hsv[2] < 0.0) hsv[2] = 0.0; else if (hsv[2] > 1.0) hsv[2] = 1.0; } else { /*No value*/ newValue = NULLOBJ; } changedValue = GetMethod(colorWheel, CHANGEDVALUE); SetMethod(colorWheel, CHANGEDVALUE, 0); newValue = NewRealArray(1, 2L); ((real *) ELEMENTS(newValue))[0] = hsv[0]; ((real *) ELEMENTS(newValue))[1] = hsv[1]; SetValue(colorWheel, newValue); SetMethod(colorWheel, CHANGEDVALUE, changedValue); } else { ActivateColorWheel(colorWheel, false); } buttons = GetVar(colorBar, FULLCOMPBUTTONS); if (buttons) { buttonList = LISTOF(buttons); } else { buttonList = 0; } if (elements[0] > 0.0) { /*Active Slider and buttons*/ int index1, index2; int comp; changedValue = GetMethod(slider, CHANGEDVALUE); SetMethod(slider, CHANGEDVALUE, 0); ActivateSlider(slider, true); /*Get a value for the slider*/ index1 = elements[1]; index2 = elements[2]; if (elements[0] == 1.0) { comp = 0; } else { comp = 5 - (int) elements[0]; } ChoosePaletteSliderValue(slider, palette, comp, index1, index2); SetMethod(slider, CHANGEDVALUE, changedValue); /*Activate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, true); buttonList = buttonList -> next; } } else { /*Inactive Slider*/ ActivateSlider(slider, false); /*Deactivate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, false); buttonList = buttonList -> next; } } buttons = GetVar(colorBar, COMPBUTTONS); if (buttons) { buttonList = LISTOF(buttons); } else { buttonList = 0; } if (elements[0] > 1.0 && elements[2] > elements[1]) { /*Activate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, true); buttonList = buttonList -> next; } } else { /*Deactivate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, false); buttonList = buttonList -> next; } } button = GetVar(colorBar, FREEFORMBUTTON); if (elements[0] > 1.0) { if (button) { ActivateButton(button, true); } } else { if (button) { ActivateButton(button, false); } } ImInvalid(colorBar); return ObjTrue; } static ObjPtr ChangePaletteColorWheel(colorWheel) ObjPtr colorWheel; /*Changes a color wheel*/ { ObjPtr slider, colorBar, panel, button; PPtr palette; ObjPtr var; real h, s, v; real r, g, b; int rs, gs, bs; short3 *colors; int index1, index2, k; real *elements; slider = GetObjectVar("ChangePaletteColorWheel", colorWheel, SLIDER); colorBar = GetObjectVar("ChangePaletteColorWheel", colorWheel, COLORBAR); if (!slider || !colorBar) { return ObjFalse; } palette = (PPtr) GetPaletteVar("ChangePaletteColorWheel", colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetValue(colorBar); if (!var) { return ObjFalse; } if (((real *) ELEMENTS(var))[0] != 1.0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; var = GetValue(colorWheel); if (!var) { return ObjFalse; } h = ((real *) ELEMENTS(var))[0]; s = ((real *) ELEMENTS(var))[1]; var = GetValue(slider); if (!var) { return ObjFalse; } v = GetReal(var); HSV2RGB(&r, &g, &b, h, s, v); /*Change the palette. Tricky.*/ rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (rs > 255) rs = 255; else if (rs < 0) rs = 0; if (gs > 255) gs = 255; else if (gs < 0) gs = 0; if (bs > 255) rs = 255; else if (bs < 0) bs = 0; colors = palette -> colors; for (k = index1; k <= index2; ++k) { colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(colorWheel, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } SetVar(slider, TEMPPALETTE, ClonePalette((ObjPtr) palette)); /* interactiveMoving = false;*/ ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } static ObjPtr ChangePaletteSlider(slider) ObjPtr slider; /*Changes a palette's slider*/ { ObjPtr colorBar, panel, button; PPtr palette, tempPalette; ObjPtr var; short rs, gs, bs; short3 *colors, *tempColors; int index1, index2, k, comp; real sliderValue, initValue; real change; ObjPtr radio; ObjPtr colorWheel, hsObj; colorBar = GetObjectVar("ChangePaletteSlider", slider, COLORBAR); tempPalette = (PPtr) GetPaletteVar("ChangePaletteSlider", slider, TEMPPALETTE); if (!colorBar || !tempPalette) { return ObjFalse; } palette = (PPtr) GetPaletteVar("ChangePaletteSlider", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colorWheel = GetObjectVar("ChangePaletteSlider", colorBar, COLORWHEEL); if (!colorWheel) { return ObjFalse; } var = GetRealVar("ChangePaletteSlider", slider, INITVALUE); if (var) { initValue = GetReal(var); } else { return ObjFalse; } var = GetValue(colorBar); if (!var) { return ObjFalse; } comp = 5 - ((real *) ELEMENTS(var))[0]; if (comp == 4) comp = 0; if (comp < 0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; var = GetValue(slider); if (!var) { return ObjFalse; } sliderValue = GetReal(var); colors = palette -> colors; tempColors = tempPalette -> colors; if (sliderValue < initValue) { /*Attenuate value*/ change = sliderValue / initValue; if (comp == 0) { /*Full color*/ real h, s, v, dummy; real r, g, b; for (k = index1; k <= index2; ++k) { r = tempColors[k][0] / 255.0; g = tempColors[k][1] / 255.0; b = tempColors[k][2] / 255.0; RGB2HSV(&h, &s, &v, r, g, b); if (index1 == index2) { hsObj = GetValue(colorWheel); if (!hsObj || !IsArray(hsObj) || RANK(hsObj) != 1 || DIMS(hsObj)[0] != 2) { return ObjFalse; } /*Single color, refresh value from wheel*/ h = ((real *) ELEMENTS(hsObj))[0]; s = ((real *) ELEMENTS(hsObj))[1]; v = sliderValue; } else { v *= change; } if (v > 1.0) v = 1.0; if (v < 0.0) v = 0.0; HSV2RGB(&r, &g, &b, h, s, v); rs = r * 255.0 + 0.5; gs = g * 255.0 + 0.5; bs = b * 255.0 + 0.5; colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); } else { real component; for (k = index1; k <= index2; ++k) { component = ((real) GetColorComponent(tempPalette, k, comp - 1)) / 255.0; component *= change; if (component > 1.0) component = 1.0; else if (component < 0.0) component = 0.0; SetColorComponent(palette, k, comp - 1, (int) (component * 255.0 + 0.5)); } CopyComponentsToColors(palette, index1, index2); } #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif } else { /*Brighten value*/ change = (1.0 - sliderValue) / (1.0 - initValue); if (comp == 0) { /*Full color*/ real h, s, v, dummy; real r, g, b; for (k = index1; k <= index2; ++k) { r = tempColors[k][0] / 255.0; g = tempColors[k][1] / 255.0; b = tempColors[k][2] / 255.0; RGB2HSV(&h, &s, &v, r, g, b); if (index1 == index2) { /*Single color, refresh value from wheel*/ hsObj = GetValue(colorWheel); if (!hsObj || !IsArray(hsObj) || RANK(hsObj) != 1 || DIMS(hsObj)[0] != 2) { return ObjFalse; } h = ((real *) ELEMENTS(hsObj))[0]; s = ((real *) ELEMENTS(hsObj))[1]; v = sliderValue; } else { v = 1.0 - (1.0 - v) * change; } if (v > 1.0) v = 1.0; if (v < 0.0) v = 0.0; HSV2RGB(&r, &g, &b, h, s, v); rs = r * 255.0 + 0.5; gs = g * 255.0 + 0.5; bs = b * 255.0 + 0.5; colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); } else { real component; for (k = index1; k <= index2; ++k) { component = ((real) GetColorComponent(tempPalette, k, comp - 1)) / 255.0; component = 1.0 - (1.0 - component) * change; if (component > 1.0) component = 1.0; else if (component < 0.0) component = 0.0; SetColorComponent(palette, k, comp - 1, (int) (component * 255.0 + 0.5)); } CopyComponentsToColors(palette, index1, index2); } #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif } ResetColorBarTools(colorBar); SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(slider, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } /* interactiveMoving = false;*/ ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } static ObjPtr RevertButton(button) ObjPtr button; /*Reverts to last palette saved*/ { ObjPtr panel, repObj, keptPalette, colorBar, textBox, radio; repObj = GetPaletteVar("RevertButton", button, REPOBJ); if (!repObj) { return ObjFalse; } keptPalette = GetPaletteVar("RevertButton", repObj, KEPTPALETTE); if (!keptPalette) { return ObjFalse; } CopyPalette(repObj, keptPalette); SetVar(repObj, CHANGED, ObjTrue); ActivateButton(button, false); if (panel = GetObjectVar("RevertButton", button, PARENT)) { if (button = GetObjectVar("RevertButton", panel, KEEPBUTTON)) { ActivateButton(button, false); } } if (colorBar = GetObjectVar("RevertButton", panel, COLORBAR)) { ObjPtr var; real newValue[3]; InhibitLogging(true); newValue[0] = newValue[1] = newValue[2] = 0.0; var = NewRealArray(1, 3L); CArray2Array(var, newValue); SetValue(colorBar, var); InhibitLogging(false); } /*Change the text boxes*/ if (textBox = GetObjectVar("RevertButton", panel, NCOLORBOX)) { sprintf(tempStr, "%d", ((PPtr) repObj) -> nColors); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", panel, MINBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> min); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", panel, MAXBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> max); SetValue(textBox, NewString(tempStr)); } if (radio = GetObjectVar("RevertButton", panel, CMODELRADIO)) { FuncTyp method; method = GetMethod(radio, CHANGEDVALUE); SetMethod(radio, CHANGEDVALUE, (FuncTyp) 0); SetValue(radio, GetVar(repObj, COLORMODEL)); SetMethod(radio, CHANGEDVALUE, method); } ForAllVisWindows(ImInvalid); return ObjTrue; } static ObjPtr KeepButton(button) ObjPtr button; /*Reverts to last palette saved*/ { ObjPtr panel, repObj, keptPalette, colorBar; repObj = GetPaletteVar("KeepButton", button, REPOBJ); if (!repObj) { return ObjFalse; } keptPalette = GetPaletteVar("KeepButton", repObj, KEPTPALETTE); if (!keptPalette) { return ObjFalse; } CopyPalette(keptPalette, repObj); ActivateButton(button, false); if (panel = GetObjectVar("KeepButton", button, PARENT)) { if (button = GetObjectVar("KeepButton", panel, REVERTBUTTON)) { ActivateButton(button, false); } } return ObjTrue; } static void SimplePaletteFunction(whichFunc, palette, index1, index2, comp, colorBar) int whichFunc; PPtr palette; int index1, index2, comp; ObjPtr colorBar; /*Does a simple function on palette*/ { int k; real r1, g1, b1, r2, g2, b2, r3, g3, b3, r, g, b, c; int rs, gs, bs, cs; switch (whichFunc) { case PF_RAMP: /*Change the palette to a ramp*/ for (k = index1 + 1; k < index2; ++k) { if (comp == 0 || comp == 1) { c = ((k - index1) * (GetColorComponent(palette, index2, 0) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 0) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 0, cs); } if (comp == 0 || comp == 2) { c = ((k - index1) * (GetColorComponent(palette, index2, 1) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 1) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 1, cs); } if (comp == 0 || comp == 3) { c = ((k - index1) * (GetColorComponent(palette, index2, 2) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 2) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 2, cs); } } break; case PF_REVERSE: for (k = 0; k < (index2 - index1 + 1) / 2; ++k) { int tempColor; if (comp == 0 || comp == 1) { /*First component*/ tempColor = GetColorComponent(palette, index2 - k, 0); SetColorComponent(palette, index2 - k, 0, GetColorComponent(palette, index1 + k, 0)); SetColorComponent(palette, index1 + k, 0, tempColor); } if (comp == 0 || comp == 2) { /*Secpmd component*/ tempColor = GetColorComponent(palette, index2 - k, 1); SetColorComponent(palette, index2 - k, 1, GetColorComponent(palette, index1 + k, 1)); SetColorComponent(palette, index1 + k, 1, tempColor); } if (comp == 0 || comp == 3) { /*Third component*/ tempColor = GetColorComponent(palette, index2 - k, 2); SetColorComponent(palette, index2 - k, 2, GetColorComponent(palette, index1 + k, 2)); SetColorComponent(palette, index1 + k, 2, tempColor); } } break; case PF_RUFFLE: { int left, right, bottom, top, l, r; long oldQuotient, newQuotient; double ddiff, majorWidth, minorWidth, halfSpace; real val; ObjPtr var; int nTics; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); l = left + CBLBORDER + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min + 2 * halfSpace; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; l = index1; val = (l - 2) * ddiff / (palette -> nColors - 3); oldQuotient = val / minorWidth; for (r = l + 1; r <= index2; ++r) { val = (r - 2) * ddiff / (palette -> nColors - 3); newQuotient = val / minorWidth; if (newQuotient != oldQuotient || r == index2) { /*Time for a reversal*/ if (r == index2) ++r; oldQuotient = newQuotient; for (k = 0; k < (r - l) / 2; ++k) { int tempColor; if (comp == 0 || comp == 1) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 0); SetColorComponent(palette, r - 1 - k, 0, GetColorComponent(palette, l + k, 0)); SetColorComponent(palette, l + k, 0, tempColor); } if (comp == 0 || comp == 2) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 1); SetColorComponent(palette, r - 1 - k, 1, GetColorComponent(palette, l + k, 1)); SetColorComponent(palette, l + k, 1, tempColor); } if (comp == 0 || comp == 3) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 2); SetColorComponent(palette, r - 1 - k, 2, GetColorComponent(palette, l + k, 2)); SetColorComponent(palette, l + k, 2, tempColor); } } l = r; } } } break; case PF_SMOOTH: if (index2 <= index1) break; r1 = (GetColorComponent(palette, index1, 0) + 0.5) / 255.0; g1 = (GetColorComponent(palette, index1, 1) + 0.5) / 255.0; b1 = (GetColorComponent(palette, index1, 2) + 0.5) / 255.0; r2 = (GetColorComponent(palette, index1 + 1, 0) + 0.5) / 255.0; g2 = (GetColorComponent(palette, index1 + 1, 1) + 0.5) / 255.0; b2 = (GetColorComponent(palette, index1 + 1, 2) + 0.5) / 255.0; for (k = index1 + 2; k < index2; ++k) { r3 = (GetColorComponent(palette, k + 1, 0) + 0.5) / 255.0; g3 = (GetColorComponent(palette, k + 1, 1) + 0.5) / 255.0; b3 = (GetColorComponent(palette, k + 1, 2) + 0.5) / 255.0; r = ((r1 + r3) * 0.5 + r2) * 0.5; g = ((g1 + g3) * 0.5 + g2) * 0.5; b = ((b1 + b3) * 0.5 + b2) * 0.5; rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (comp == 0 || comp == 1) { SetColorComponent(palette, k, 0, rs); } if (comp == 0 || comp == 2) { SetColorComponent(palette, k, 1, gs); } if (comp == 0 || comp == 3) { SetColorComponent(palette, k, 2, bs); } r1 = r2; r2 = r3; g1 = g2; g2 = g3; b1 = b2; b2 = b3; } break; case PF_SHARPEN: if (index2 <= index1) break; r1 = (GetColorComponent(palette, index1, 0) + 0.5) / 255.0; g1 = (GetColorComponent(palette, index1, 1) + 0.5) / 255.0; b1 = (GetColorComponent(palette, index1, 2) + 0.5) / 255.0; r2 = (GetColorComponent(palette, index1 + 1, 0) + 0.5) / 255.0; g2 = (GetColorComponent(palette, index1 + 1, 1) + 0.5) / 255.0; b2 = (GetColorComponent(palette, index1 + 1, 2) + 0.5) / 255.0; for (k = index1 + 2; k < index2; ++k) { r3 = (GetColorComponent(palette, k + 1, 0) + 0.5) / 255.0; g3 = (GetColorComponent(palette, k + 1, 1) + 0.5) / 255.0; b3 = (GetColorComponent(palette, k + 1, 2) + 0.5) / 255.0; r = r2 + (r2 - (r1 + r3) * 0.5) * 2.0; if (r > 1.0) r = 1.0; else if (r < 0.0) r = 0.0; g = g2 + (g2 - (g1 + g3) * 0.5) * 2.0; if (g > 1.0) g = 1.0; else if (g < 0.0) g = 0.0; b = b2 + (b2 - (b1 + b3) * 0.5) * 2.0; if (b > 1.0) b = 1.0; else if (b < 0.0) b = 0.0; rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (comp == 0 || comp == 1) { SetColorComponent(palette, k, 0, rs); } if (comp == 0 || comp == 2) { SetColorComponent(palette, k, 1, gs); } if (comp == 0 || comp == 3) { SetColorComponent(palette, k, 2, bs); } r1 = r2; r2 = r3; g1 = g2; g2 = g3; b1 = b2; b2 = b3; } break; } CopyComponentsToColors(palette, index1, index2); } static ObjPtr SimpleFuncButton(button) ObjPtr button; /*Do a simple palette function*/ { ObjPtr colorBar, panel; PPtr palette; ObjPtr var; int whichFunc; int index1, index2, comp, k; colorBar = GetObjectVar("SimpleFuncButton", button, COLORBAR); if (!colorBar) { return ObjFalse; } var = GetIntVar("SimpleFuncButton", button, PALETTEFUNC); if (!var) { return ObjFalse; } whichFunc = GetInt(var); palette = (PPtr) GetPaletteVar("SimpleFuncButton", colorBar, REPOBJ); if (!palette) { return false; } var = GetValue(colorBar); if (!var) { return ObjFalse; } if (((real *) ELEMENTS(var))[0] < 1.0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; if (((real *) ELEMENTS(var))[0] == 1.0) { comp = 0; } else { comp = 5 - (int) ((real *) ELEMENTS(var))[0]; } SimplePaletteFunction(whichFunc, palette, index1, index2, comp, colorBar); #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(button, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } /* interactiveMoving = false;*/ InhibitLogging(true); ChangedValue(colorBar); InhibitLogging(false); ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } #ifdef PROTO void ActivateColorWheel(ObjPtr wheel, Bool whether) #else void ActivateColorWheel(wheel, whether) ObjPtr wheel; Bool whether; #endif /*Activates a color wheel*/ { SetVar(wheel, ACTIVATED, whether ? ObjTrue : ObjFalse); ImInvalid(wheel); } #ifdef PROTO static int GetColorComponent(PPtr palette, int whichColor, int comp) #else static int GetColorComponent(palette, whichColor, comp) PPtr palette; int whichColor; int comp; #endif /*Gets the color component comp from whichColor in palette*/ { return palette -> components[whichColor][comp]; } #ifdef PROTO static void SetColorComponent(PPtr palette, int whichColor, int comp, int cc) #else static void SetColorComponent(palette, whichColor, comp, cc) PPtr palette, int whichColor; int comp; int cc; #endif /*Changes component comp in whichColor of palette to cc*/ { real rgb[3], hsv[3], hls[3], yiq[3]; palette -> components[whichColor][comp] = cc; CopyComponentsToColors(palette, whichColor, whichColor); } ObjPtr ImposeColorFunction(colorBar) ObjPtr colorBar; /*Imposes a color function on colorBar. Function is given by EDITMODE Box is given by FUNCTIONBOX */ { ObjPtr value, var, palette, panel, button; real *elements; int comp; int index1, index2, k, cc; real beg, end, fieldVal; int min, max; int tool; int cm; value = GetValue(colorBar); if (!value) { return ObjFalse; } palette = GetPaletteVar("ImposeColorFunction", colorBar, REPOBJ); if (!palette) { return ObjFalse; } elements = ELEMENTS(value); if (elements[1] < 1.5) { /*Not on a component*/ return ObjFalse; } var = GetIntVar("ImposeColorFunction", colorBar, EDITMODE); if (!var) { return ObjFalse; } tool = GetInt(var); comp = 4 - elements[0]; index1 = elements[1] + 0.5; index2 = elements[2] + 0.5; var = GetVar(colorBar, FUNCTIONBOX); if (!var) { /*No box around function!*/ return ObjFalse; } elements = ELEMENTS(var); beg = elements[0]; end = elements[1]; min = elements[2] + 0.5; max = elements[3] + 0.5; var = GetVar(palette, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } for (k = index1; k <= index2; ++k) { fieldVal = GetColorValue(palette, k); while (fieldVal < beg) { fieldVal += end - beg; } while (fieldVal > end) { fieldVal -= end - beg; } fieldVal -= beg; fieldVal /= (end - beg); /*Now fieldVal is in [0, 1) */ switch (tool) { case PT_SINE: /*Sine function*/ cc = min + (max - min) * ((1.0 + rsin(fieldVal * 2.0 * M_PI)) * 0.5); break; case PT_TRIANGLE: /*Triangle function*/ if (fieldVal < 0.25) { cc = (max + min) / 2 + fieldVal * 2.0 * (max - min); } else if (fieldVal > 0.75) { cc = min + (fieldVal - 0.75) * 2.0 * (max - min); } else { cc = min + (0.75 - fieldVal) * 2.0 * (max - min); } break; case PT_SAWTOOTH: /*Sawtooth function*/ cc = min + fieldVal * (max - min); break; case PT_TOOTHSAW: /*Toothsaw function*/ cc = max - fieldVal * (max - min); break; case PT_SQUARE: /*Square wave function*/ if (fieldVal < 0.5) { cc = max; } else { cc = min; } break; default: cc = 0; } SetColorComponent((PPtr) palette, k, comp, cc); } CopyComponentsToColors((PPtr) palette, index1, index2); MapPaletteColors((PPtr) palette, index1, index2); panel = GetVar(colorBar, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ChangedValue(colorBar); return ObjTrue; } static ObjPtr ChangeColorTool(group) ObjPtr group; /*Changes a color tool in response to a radio button group*/ { ObjPtr colorBar; PPtr palette; ObjPtr value; ObjPtr var; int tool; ObjPtr selection; real *elements; colorBar = GetObjectVar("ChangeColorTool", group, REPOBJ); if (!colorBar) { return ObjFalse; } selection = GetValue(colorBar); elements = ELEMENTS(selection); palette = (PPtr) GetPaletteVar("ChangeColorTool", colorBar, REPOBJ); if (!palette) { return ObjFalse; } value = GetValue(group); if (!value) { return false; } tool = GetInt(value); var = GetVar(colorBar, EDITMODE); if (var && GetInt(var) == tool) { /*Don't need to do anything*/ return ObjFalse; } SetVar(colorBar, EDITMODE, NewInt(tool)); if (tool > 0) { /*It's a function.*/ var = GetVar(colorBar, FUNCTIONBOX); if (!var) { /*Calculate initial function box*/ int left, right, bottom, top, l, r, b, t; double majorWidth; double halfSpace; double start, finish, middle, ddiff; int nTics; long temp; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, (int) elements[1]) - halfSpace; finish = GetColorValue((ObjPtr) palette, (int) elements[2]) + halfSpace; middle = (start + finish) * 0.5; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); /*Minor and major tics first*/ temp = middle / majorWidth; start = temp * majorWidth; finish = start + majorWidth; var = NewRealArray(1, 4L); ((real *) ELEMENTS(var))[0] = start - majorWidth; ((real *) ELEMENTS(var))[1] = finish; ((real *) ELEMENTS(var))[2] = 0.0; ((real *) ELEMENTS(var))[3] = 255.0; InhibitLogging(true); SetFunctionBox(colorBar, var); InhibitLogging(false); } InhibitLogging(true); ImposeColorFunction(colorBar); SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); InhibitLogging(false); } else { /*No function box*/ InhibitLogging(true); SetFunctionBox(colorBar, NULLOBJ); InhibitLogging(false); } ImInvalid(colorBar); return ObjTrue; } static ObjPtr MakePaletteBarHelp(colorBar, class) ObjPtr colorBar; ObjPtr class; /*Makes help for a color bar*/ { ObjPtr help, temp; ObjPtr var; int editMode; real *elements; help = NewString("This control shows a color palette. The color bar at \ the bottom shows the range of colors in the palette associated with the field \ values, plus colors for missing data, overflow, and underflow values. \ Above the color bar are three bars showing the magnitude of the three components \ of each color, plus a magnified readout at the top.\n\ \n\ You can select a range of colors to edit by clicking in the color bar or one of the \ three component bars and dragging through the colors you want to edit. When you \ select a range, controls in the window that can edit the color will become active. \ Also, the selected range will be expanded to fill the magnified readout at the top of the control. \ When a color component is selected, you can edit it using the Edit Component \ buttons to the left."); var = GetValue(colorBar); if (var) { elements = ELEMENTS(var); if (elements[0] > 1.5) { /*A component is selected*/ var = GetIntVar("MakePaletteBarHelp", colorBar, EDITMODE); if (var) { ObjPtr palette; int cm; editMode = GetInt(var); palette = GetVar(colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetVar(palette, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } sprintf(tempStr, "\n\nThe %s components of a range of colors are \ currently selected. The Intensity slider on the left lets you change the brightness \ of this component of the range. The buttons at the top of the window let you \ perform some simple functions over the entire range of colors. Use Help In \ Context to find out what each of these buttons does.\n\n", componentNames[cm][4 - (int) (elements[0] + 0.5)]); temp = NewString(tempStr); help = ConcatStrings(help, temp); if (editMode == PT_FREEFORM) { /*Free form tool*/ temp = NewString("The free form tool is selected. \ You can modify the waveform shown at the top of the control by clicking and drawing \ within the box. The Shift key will constrain motion in just the vertical or \ horizontal direction.\n"); help = ConcatStrings(help, temp); } else { /*Waveform tool*/ sprintf(tempStr, "The %s tool is selected. Notice \ that there is a yellow box within the magnified readout at \ the top of the control. This box encloses one period of a %s which is used \ to fill the entire selected range of the component. ", toolNames[editMode], toolNames[editMode]); temp = NewString(tempStr); help = ConcatStrings(help, temp); temp = NewString("Click and drag the square \ handles on the top or bottom to change the minimum and maximum values of the wave. Click \ Click and drag the handles on the left or right to change the beginning and end \ of the wave as well as its wavelength. The Shift key will constrain motion to \ the nearest tic mark. Click and drag within the box to move the entire waveform \ left or right."); help = ConcatStrings(help, temp); } } } else if (elements[0] > 0.5) { temp = NewString("\n\nA range of colors is \ currently selected. The Intensity slider on the left lets you change the brightness \ of this component of the range. The Hue/Saturation color wheel lets you change \ the hue and saturation of the entire range. When you click on this \ control, the entire range will become a single color. \ The buttons at the top of the window let you \ perform some simple functions over the entire range of colors. Use Help In \ Context to find out what each of these buttons does."); help = ConcatStrings(help, temp); } } SetVar(class, HELPSTRING, help); } void DoNumberError() /*Whines at the user about a numeric error*/ { WinInfoPtr errWindow; errWindow = AlertUser(UIRED, (WinInfoPtr) 0, "There is a syntax error in the number.", 0, 0, ""); SetVar((ObjPtr) errWindow, HELPSTRING, NewString("There is a syntax error in the number you have just entered. \ Please enter the number once more.")); } void DoRangeError() /*Whines at the user about a range error*/ { WinInfoPtr errWindow; errWindow = AlertUser(UIRED, (WinInfoPtr) 0, "The maximum value must be greater than the minimum.", 0, 0, ""); SetVar((ObjPtr) errWindow, HELPSTRING, NewString("The number you have just entered would cause the maximum value \ to be less than the minimum. \ Please enter the number once more.")); } void DoWrongNColorsError() /*Whines at the user about the wrong number of colors*/ { WinInfoPtr errWindow; errWindow = AlertUser(UIRED, (WinInfoPtr) 0, "The number of colors must be between 5 and 2048.", 0, 0, ""); SetVar((ObjPtr) errWindow, HELPSTRING, NewString("The number you have just entered is an invalid number of colors \ for a color table. \ Please enter a number between 5 and 2048.")); } static ObjPtr EnterMin(box) ObjPtr box; /*Enters the minimum value from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; float min; char *s; FuncTyp method; value = GetValue(box); if (!value) { return ObjFalse; } s = GetString(value); if (1 != sscanf(s, " %g", &min)) { DoUniqueTask(DoNumberError); return ObjFalse; } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (min >= palette -> max) { DoUniqueTask(DoRangeError); return ObjFalse; } palette -> min = min; ReinitColorBar(colorBar); ImInvalid(colorBar); SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } return ObjTrue; } static ObjPtr EnterMax(box) ObjPtr box; /*Enters the max value from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; float max; FuncTyp method; value = GetValue(box); if (!value) { return ObjFalse; } if (1 != sscanf(GetString(value), " %g", &max)) { DoUniqueTask(DoNumberError); return ObjFalse; } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (max <= palette -> min) { DoUniqueTask(DoRangeError); return ObjFalse; } palette -> max = max; SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); ReinitColorBar(colorBar); ImInvalid(colorBar); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } return ObjTrue; } static ObjPtr EnterNColors(box) ObjPtr box; /*Enters the number of colors from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; int nColors; real *elements; int oldNColors; value = GetValue(box); if (!value) { return ObjFalse; } if (1 != sscanf(GetString(value), " %d", &nColors)) { DoUniqueTask(DoNumberError); return ObjFalse; } colorBar = GetObjectVar("EnterNColors", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (nColors < 5 || nColors > 2048) { DoUniqueTask(DoWrongNColorsError); return ObjFalse; } oldNColors = palette -> nColors; SetPaletteNColors((ObjPtr) palette, nColors); SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } value = GetValue(colorBar); if (value) { real newValue[4]; elements = ELEMENTS(value); newValue[0] = elements[0]; newValue[1] = elements[1]; newValue[2] = elements[2]; newValue[3] = elements[3]; if (elements[0] > 0.5) { int k; for (k = 1; k <=2; ++k) { if (((int) elements[k] + 0.5) >= oldNColors - 1) { newValue[k] = nColors - 1; } else if (((int) elements[k] + 0.5) > 1) { newValue[k] = 2.0 + (elements[k] - 2.0) * (nColors - 3) / (oldNColors - 3); if (((int) newValue[k] + 0.5) >= nColors - 1) { newValue[k] = nColors - 2.0; } if (((int) newValue[k] + 0.5) < 2) { newValue[k] = 2.0; } } } if (newValue[3] <= newValue[2]) newValue[3] += 1.0; } value = NewRealArray(1, 3L); CArray2Array(value, newValue); InhibitLogging(true); SetValue(colorBar, value); InhibitLogging(false); } return ObjTrue; } ObjPtr ChangeTextColorWheel(wheel) ObjPtr wheel; /*Changes text colors according to a color wheel*/ { ObjPtr repObj, slider; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeTextColorWheel", wheel, REPOBJ); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeTextColorWheel", wheel, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, COLOR, value); ImInvalid(repObj); return ObjTrue; } ObjPtr ChangeTextColorSlider(slider) ObjPtr slider; /*Changes text color according to a color slider*/ { ObjPtr repObj, wheel; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeTextColorWheel", slider, REPOBJ); if (!repObj) { return ObjFalse; } wheel = GetObjectVar("ChangeTextColorWheel", slider, COLORWHEEL); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, COLOR, value); ImInvalid(repObj); return ObjTrue; } ObjPtr ChangeBackgroundColorWheel(wheel) ObjPtr wheel; /*Changes text colors according to a color wheel*/ { ObjPtr repObj, slider, checkBox; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorWheel", wheel, REPOBJ); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeBackgroundColorWheel", wheel, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); checkBox = GetObjectVar("ChangeBackgroundColorSlider", wheel, CHECKBOX); if (checkBox) { FuncTyp method; method = GetMethod(checkBox, CHANGEDVALUE); SetMethod(checkBox, CHANGEDVALUE, 0); InhibitLogging(true); SetValue(checkBox, NewInt(0)); InhibitLogging(false); SetMethod(checkBox, CHANGEDVALUE, method); } return ObjTrue; } ObjPtr ChangeBackgroundColorSlider(slider) ObjPtr slider; /*Changes background color according to a color slider*/ { ObjPtr repObj, wheel, checkBox; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorSlider", slider, REPOBJ); if (!repObj) { return ObjFalse; } wheel = GetObjectVar("ChangeBackgroundColorSlider", slider, COLORWHEEL); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); checkBox = GetObjectVar("ChangeBackgroundColorSlider", slider, CHECKBOX); if (checkBox) { FuncTyp method; method = GetMethod(checkBox, CHANGEDVALUE); SetMethod(checkBox, CHANGEDVALUE, 0); InhibitLogging(true); SetValue(checkBox, NewInt(0)); InhibitLogging(false); SetMethod(checkBox, CHANGEDVALUE, method); } return ObjTrue; } static ObjPtr ChangeColorByPalette(checkBox) ObjPtr checkBox; /*Changes an object's COLORBYFIELD according to checkBox*/ { ObjPtr repObj, value; repObj = GetObjectVar("ChangeColorByPalette", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } value = GetValue(checkBox); if (!value) { return ObjFalse; } SetVar(repObj, COLORBYFIELD, value); ImInvalid(repObj); return ObjFalse; } ObjPtr ChangeNoBackground(checkBox) ObjPtr checkBox; /*Changes background color according to a check box*/ { ObjPtr repObj, wheel, slider; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorSlider", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } value = GetValue(checkBox); if (!value) { return ObjFalse; } if (GetInt(value)) { SetVar(repObj, BACKGROUND, NULLOBJ); ImInvalid(repObj); return ObjTrue; } wheel = GetObjectVar("ChangeBackgroundColorSlider", checkBox, COLORWHEEL); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeBackgroundColorSlider", checkBox, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowMissing(checkBox) ObjPtr checkBox; /*Changes the SHOWMISSING according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowMissing", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWMISSING, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowOverUnder(checkBox) ObjPtr checkBox; /*Changes the SHOWOVERUNDER according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowOverUnder", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWOVERUNDER, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowMinorTics(checkBox) ObjPtr checkBox; /*Changes the SHOWMINORTICS according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowMinorTics", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWMINORTICS, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeNumbersOnly(checkBox) ObjPtr checkBox; /*Changes the NUMBERSONLY according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeNumbersOnly", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, NUMBERSONLY, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ShowPaletteDisplayControls(display, ownerWindow, windowName) ObjPtr display; WinInfoPtr ownerWindow; char *windowName; /*Makes a new control window to control a palette display*/ { WinInfoPtr controlWindow; ObjPtr var; ObjPtr panel; ObjPtr corral; ObjPtr contents; real rgb[3], hsv[3]; WinInfoPtr dialogExists; Bool hasBackground; dialogExists = DialogExists((WinInfoPtr) 0, display); controlWindow = GetDialog((WinInfoPtr) 0, display, windowName, DSPPALWINWIDTH, DSPPALWINHEIGHT, DSPPALWINWIDTH, DSPPALWINHEIGHT, WINDBUF + WINRGB + WINFIXEDSIZE); if (!dialogExists) { long info; ObjPtr value; ObjPtr checkBox, icon, name, colorBar, titleBox, textBox