/*ScianColors.c Color management routines for scian Eric Pepke March 15, 1990 */ #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" #include "ScianFiles.h" #include "ScianVisWindows.h" #include "ScianObjFunctions.h" #include "ScianTemplates.h" #include "ScianTemplateHelper.h" #include "ScianSciences.h" #include "gamtables.h" #include "ScianSymbols.h" #ifdef GRAPHICS #ifdef NEEDSGAMMA #endif #define OVERCLEAR 0 /*Clear in overlay planes*/ #define OVERRED 1 /*Red in overlay planes*/ #ifdef NEEDSGAMMA #define CVAL(k) LinToGamma[k] #else #define CVAL(k) (k) #endif #endif int overDraw = 0; /*Counter for overlay drawing*/ short curRed, curGreen, curBlue; /*Current color components in other than screen draw mode*/ ObjPtr iconColorPalette; char *spfNames[NPALETTEFUNCS] = { "ramp", "reverse", "ruffle", "smooth", "sharpen" }; char *toolNames[NPALETTETOOLS] = { "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"} }; char *colorModelNames[NCOLORMODELS] = { "RGB", "YIQ", "HSV", "HLS" }; 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}}; int paletteSerialNum = 0; /*Serial num for palettes*/ static int ColorToPixel(ObjPtr, int); static int PixelToColor(ObjPtr, int); static int AllocColors(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*/ #define COLORWHEELBORDER 6 /*Border around HS control*/ #define COLORWHEELSPOTSIZE 4 /*Size of spot in HS control*/ int curUIColorIndex; /*Global current color index*/ short uiColors[NUICOLORS][3]; /*Components for the UI colors*/ int uiColorIndex[NUICOLORS]; /*Indices for ui colors*/ short3 *colorsToScavenge; /*Colors to scavenge*/ int nScavengeColors = 0; /*Number of colors for scavenging*/ 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 static short o0r, o0g, o0b; static short o1r, o1g, o1b; static short o2r, o2g, o2b; #ifdef PROTO void OverDraw(Bool whether) #else void OverDraw(whether) Bool whether; #endif /*Sets system into overlay drawing mode, or not*/ { if (hasOverDraw == false) { printf("No overlay drawing!\n"); return; } #ifdef GRAPHICS if (whether) { if (!overDraw++) { pushattributes(); drawmode(pupForOverDraw ? PUPDRAW : OVERDRAW); getmcolor(OVERCLEAR, &o0r, &o0g, &o0b); getmcolor(OVERRED, &o1r, &o1g, &o1b); mapcolor(OVERCLEAR, 0, 0, 0); mapcolor(OVERRED, 255, 0, 0); color(1); } } else { if (0 == --overDraw) { mapcolor(OVERCLEAR, o0r, o0g, o0b); mapcolor(OVERRED, o1r, o1g, o1b); drawmode(NORMALDRAW); popattributes(); } } #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); } void FieldPaletteName(palette, field) ObjPtr palette, field; /*Names a palette based on a field*/ { ObjPtr name; MakeVar(field, NAME); name = GetStringVar("FieldPaletteName", field, NAME); if (!name) { return; } strcpy(tempStr, GetString(name)); strcat(tempStr, " Palette"); SetVar(palette, NAME, NewString(tempStr)); } 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(UICAUTIONALERT, (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; #ifdef GRAPHICS 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) / HEARTBEAT; if (curTime > colorFailTime + COLORFAILTIMEOUT) { colorFailTime = curTime; DoUniqueTask(AlertColorFailure); } curNColors = uiColorIndex[UIWHITE] - uiColorIndex[UIBLACK]; curBeg = uiColorIndex[UIBLACK]; } } else #endif { 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 = newp(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 r = CVAL(r); g = CVAL(g); b = CVAL(b); /*Search the existing colors for the best match.*/ if (hasCmap && scavengeColors) { short bestR, bestG, bestB; int bestC; short testR, testG, testB; int testC; int bestDist = MAXCDIST + 1; int testDist; for (testC = 0; testC < nScavengeColors; ++testC) { if (testC < 16 || testC >= 32) { /*Colors between 16 and 32 unreliable*/ testR = colorsToScavenge[testC][0]; testG = colorsToScavenge[testC][1]; testB = colorsToScavenge[testC][2]; testDist = MAX(ABS(testR - r), MAX(ABS(testG - g), ABS(testB - b))); if (testDist <= bestDist) /*Change to < for first not last*/ { if ((r == g) && (g == b)) { /*Test for gray dirtiness failure*/ if (MAX(testR, MAX(testG, testB)) - MIN(testR, MIN(testG, testB)) > MAXGRAYDIRT) { /*Disallow this one and continue search*/ continue; } } bestDist = testDist; bestR = testR; bestG = testG; bestB = testB; bestC = testC; } } } /*Now see if it's good enough*/ if (bestDist <= MAXCDIST) { /*It's OK, use this one*/ if (showConfig) { printf("Best match to UI color %d (%d %d %d) found at %d (%d %d %d)\n", whichColor, r, g, b, (int) bestC, (int) bestR, (int) bestG, (int) bestB); } uiColorIndex[whichColor] = bestC; } else { /*No good, allocate one*/ if (hasCmap) { if (showConfig) { printf("UI Color %d (%d %d %d) failed color scavenge search. Allocated at %d.\n", whichColor, r, g, b, curUIColorIndex); } uiColorIndex[whichColor] = curUIColorIndex++; mapcolor(uiColorIndex[whichColor], r, g, b); TinyDelay(); } else { uiColorIndex[whichColor] = -1; if (showConfig) { printf("UI Color %d (%d %d %d) failed color scavenge search. Not allocated.\n", whichColor, r, g, b); } } } } else { /*Just use the next value in the color map*/ if (hasCmap) { if (showConfig) { printf("UI Color %d (%d %d %d) allocated at %d.\n", whichColor, r, g, b, curUIColorIndex); } uiColorIndex[whichColor] = curUIColorIndex++; if (hasCmap) { mapcolor(uiColorIndex[whichColor], r, g, b); TinyDelay(); } } else { if (showConfig) { printf("UI Color %d (%d %d %d) not allocated because it's always RGB.\n", whichColor, r, g, b); } uiColorIndex[whichColor] = -1; } } uiColors[whichColor][0] = r; uiColors[whichColor][1] = g; uiColors[whichColor][2] = b; #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; } 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*/ DrawRaisedRect(left, right, bottom, top, 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*/ FillUIWedge(cx, cy, radius, -30, 30, UIRED); FillUIWedge(cx, cy, radius, 30, 90, UIYELLOW); FillUIWedge(cx, cy, radius, 90, 150, UIGREEN); FillUIWedge(cx, cy, radius, 150, 210, UICYAN); FillUIWedge(cx, cy, radius, 210, 270, UIBLUE); FillUIWedge(cx, cy, radius, 270, 330, UIMAGENTA); FillUIGauzeDisc(cx, cy, (int) radius * 2 / 3, UIWHITE); FillUIDisc(cx, cy, (int) radius / 3, UIWHITE); /*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; } if (*r > 1.0) *r = 0.0; else if (*r < 0.0) *r = 0.0; if (*g > 1.0) *g = 0.0; else if (*g < 0.0) *g = 0.0; if (*b > 1.0) *b = 0.0; else if (*b < 0.0) *b = 0.0; } #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); } if (*r > 1.0) *r = 0.0; else if (*r < 0.0) *r = 0.0; if (*g > 1.0) *g = 0.0; else if (*g < 0.0) *g = 0.0; if (*b > 1.0) *b = 0.0; else if (*b < 0.0) *b = 0.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 PressColorWheel(object, mouseX, mouseY, flags) ObjPtr object; int mouseX, mouseY; long 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; MakeMeCurrent(object); SaveForUndo(object); 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("PressColorWheel", 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); 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; } } } /*See if value is different*/ valueArray = GetVar(object, VALUE); if (valueArray) { Array2CArray(value, valueArray); if (hue == value[0] && saturation == value[1]) { continue; } } value[0] = hue; value[1] = saturation; valueArray = NewRealArray(1, 2L); CArray2Array(valueArray, value); SetVar(object, VALUE, valueArray); DrawMe(object); 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 || (IsRealArray(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; SETOBJTYPE(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; } ObjPtr NewAtomicPalette() /*Returns a new atomic palette, which maps atomic numbers onto colors*/ { int atom; short3 *colors; ObjPtr retVal; retVal = NewPalette(N_ATOMS + 3); SetPaletteMinMax(retVal, 1, (real) N_ATOMS); /*Give it some colors*/ colors = ((PPtr) retVal) -> colors; colors += 2; for (atom = 0; atom < N_ATOMS; ++atom) { (*colors)[0] = atomInfo[atom] . color[0]; (*colors)[1] = atomInfo[atom] . color[1]; (*colors)[2] = atomInfo[atom] . color[2]; ++colors; } return 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); SAFEFREE(((PPtr) d) -> colors); ((PPtr) d) -> colors = malloc(sizeof(short3) * ((PPtr) s) -> nColors); SAFEFREE(((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; SETOBJTYPE(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); } real PSColor() /*Returns a grayscale equivalent for the current color in DRAW_POSTSCRIPT mode*/ { real y, dummy; real h, s, v, w; int ival; real retVal; RGB2HSV(&h, &s, &v, curRed/255.0, curGreen/255.0, curBlue/255.0); RGB2YIQ(&y, &dummy, &dummy, curRed/255.0, curGreen/255.0, curBlue/255.0); w = (s - 0.25) * 4.0 / 3.0; retVal = (w * y + (1.0 - w) * v); if (retVal > 1.0) retVal = 1.0; if (retVal < 0.0) retVal = 0.0; ival = retVal * 255.0; retVal = ((real) LinToGamma[ival]) / 255.0; if (retVal > 1.0) retVal = 1.0; if (retVal < 0.0) retVal = 0.0; return retVal; } 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 (drawingMode == DRAW_SCREEN) { if (overDraw) { if (c == UIBLACK) { color(OVERCLEAR); } else { color(OVERRED); } } else if (rgbp) { /*It's an RGB window*/ lmcolor(LMC_COLOR); #ifdef INDIGOCOLORS if (uiColorIndex[c] >= 0) { color(uiColorIndex[c]); } else #endif c3s(uiColors[c]); } else { /*It's a cmap window*/ color(uiColorIndex[c]); } } else { curRed = uiColors[c][0]; curGreen = uiColors[c][1]; curBlue = uiColors[c][2]; } #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; } } #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 = 1; } minDelta = diff * minMajorPix / pixWidth; deltaLog = ((long) (1000.0 + log10((double) minDelta))) - 1000; *majorWidth = pow((double) 10.0, (double) deltaLog); *nMinorSteps = 1; 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 (IsRealArray(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*/ { #ifdef GRAPHICS 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; v2i(v); for (c = 1; c < 5; ++c) { SetUIColor(hueColors[c]); v[1] = bottom + (top - bottom) * c / 6; v[0] = right; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v2i(v); v[0] = right; v2i(v); } SetUIColor(hueColors[c]); v[1] = top; v[0] = right; 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; v2i(v); SetUIColor(UICYAN); v[1] = top; 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; v2i(v); SetUIColor(UICYAN); v[1] = top; 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; 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; v2i(v); SetUIColor(UIWHITE); v[1] = top; 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; 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; v2i(v); SetUIColor(UIWHITE); v[1] = top; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if (k == 2) { /*i, cyan/orange index (use red instead of orange)*/ long v[2]; bgnpolygon(); SetUIColor(UICYAN); v[0] = left; v[1] = bottom; v2i(v); v[0] = right; v2i(v); SetUIColor(UIRED); v[1] = top; 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; v2i(v); SetUIColor(UIMAGENTA); v[1] = top; v2i(v); v[0] = left; v2i(v); endpolygon(); } shademodel(FLAT); break; } #endif } #ifdef PROTO static void DrawFunctionBox(real *elements, int l, int r, int b, int t, real start, real finish) #else static void DrawFunctionBox(elements, l, r, b, t, start, finish) real *elements; int l, r, b, t; real start, finish; #endif /*Draws a function box*/ { int boxL, boxR, boxB, boxT, boxX, boxY; real ddiff; ddiff = finish - start; 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; /*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); } static ObjPtr DrawColorBar(colorBar) ObjPtr colorBar; /*Draws a color bar*/ { #ifdef GRAPHICS 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*/ Get2DIntBounds(colorBar, &left, &right, &bottom, &top); if (IsDrawingRestricted(left, right, bottom, top)) return ObjFalse; /*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, but not if the changed bounds is smaller than the bounds*/ var = GetVar(colorBar, CHANGEDBOUNDS); if (!var || !IsArray(var)) { DrawRaisedRect(left, right, bottom, top, UIBACKGROUND); } else { elements = ELEMENTS(var); if (left >= CURSTATE . screenMask[0] - CURSTATE . translation[0] && right <= CURSTATE . screenMask[1] - CURSTATE . translation[0] && bottom >= CURSTATE . screenMask[2] - CURSTATE . translation[1] && top <= CURSTATE . screenMask[3] - CURSTATE . translation[1]) { DrawRaisedRect(left, right, bottom, top, UIBACKGROUND); } } /*Draw the legends and tic marks and stuff at the bottom*/ SetUIColor(UIBLACK); SetupFont(CBTEXTFONT, CBTEXTSIZE); b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; DrawAString(CENTERALIGN, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, bottom + CBBORDER + CBTEXTUP, "Missing"); DrawUILine( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); DrawAString(CENTERALIGN, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 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); DrawAString(CENTERALIGN, pixel, 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; } DrawAString(CENTERALIGN, right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 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); DrawAString(LEFTALIGN, 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]); FillRect( left + CBLBORDER + CBLTEXTSPACE + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, b, t); /*Do underflow data box*/ c3s(colors[1]); FillRect( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, b, 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]); FillRect(l, r, b, t); l = r; } /*Do overflow data box*/ c3s(colors[nColors - 1]); FillRect( right - CBRBORDER - CBBOXWIDTH + 1, right - CBRBORDER - 1, b, 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); FillRect( left + CBLBORDER + CBLTEXTSPACE + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, b, t); /*Do underflow data box*/ color(beg + 1); FillRect( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, b, 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); FillRect(l, r, b, t); l = r; } /*Do overflow data box*/ color(beg + nColors - 1); FillRect( right - CBRBORDER - CBBOXWIDTH + 1, right - CBRBORDER - 1, b, 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) { FillRect( left + CBLBORDER + CBLTEXTSPACE + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t - CBCOMPHEIGHT + height + 1, t - 1); } /*Do underflow data box*/ height = GetColorComponent(palette, 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { FillRect( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t - CBCOMPHEIGHT + height + 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) { FillRect(l, r, t - CBCOMPHEIGHT + height + 1, t - 1); } l = r; } /*Overflow*/ height = GetColorComponent(palette, nColors - 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { FillRect(right - CBRBORDER - CBBOXWIDTH + 1, right - CBRBORDER - 1, t - CBCOMPHEIGHT + height + 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]); FillRect(l, r, b, t); l = r; } } 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); FillRect(l, r, b, t); l = r; } } } 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) { FillRect(l, r, b + height, t); } l = r; } } } /*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) { 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); { DrawAString(CENTERALIGN, pixel, 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) { real *elements; elements = ELEMENTS(var); SetClipRect(left + 3, right - 3, bottom + 3, top - 3); DrawFunctionBox(elements, l, r, b, t, start, finish); 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 && (!IsRealArray(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 SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); return ObjTrue; } static ObjPtr PressColorBar(colorBar, x, y, flags) ObjPtr colorBar; int x, y; long 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; Bool doubleP; 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 color bar*/ 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; } doubleP = IsDoubleBuf(selWinInfo) ? true : false; MakeMeCurrent(colorBar); SaveForUndo(colorBar); /*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*/ int dummy; /*Dummy for colorToPixels*/ int cb, ct, cl, cr; /*b, t, l, r for cursor*/ /*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); if (!doubleP) { DrawSkeleton(true); cb = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + ((int) (val[0] - 0.5)) * (CBVGAP + CBCOMPHEIGHT); ct = b + CBCOMPHEIGHT; ColorToPixels(&cl, &dummy, colorBar, (int) (val[1] + 0.5)); ColorToPixels(&dummy, &cr, colorBar, (int) (val[2] + 0.5)); FrameUIRect(cl - 2, cr + 1, cb, ct + 1, UIRED); FrameUIRect(cl - 3, cr + 2, cb - 1, ct + 2, UIRED); } 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); inp = false; lastColor = -1; if (doubleP) { DrawMe(colorBar); } else { EraseAll(); } } } 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); if (doubleP) { DrawMe(colorBar); } else { ColorToPixels(&cl, &dummy, colorBar, (int) (val[1] + 0.5)); ColorToPixels(&dummy, &cr, colorBar, (int) (val[2] + 0.5)); EraseAll(); FrameUIRect(cl - 2, cr + 1, cb, ct + 1, UIRED); FrameUIRect(cl - 3, cr + 2, cb - 1, ct + 2, UIRED); } lastColor = newColor; } } } if (!doubleP) { DrawSkeleton(false); } ChangedValue(colorBar); ImInvalid(colorBar); 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 } DrawMeInBounds(colorBar, left + 3, right - 3, bottom + 3, top - 3); lastAmp = newAmp; lastColor = newColor; } } else { lastColor = lastAmp = -1; } } for (k = firstAltered; k <= lastAltered; ++k) { LogColorChange(colorBar, colors, k); } ChangedValue(colorBar); 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; if (!doubleP) { DrawSkeleton(true); } /*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); if (doubleP) { DrawMe(colorBar); } else { EraseAll(); DrawFunctionBox(newElements, l, r, b, t, start, finish); } 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); if (doubleP) { DrawMe(colorBar); } else { EraseAll(); DrawFunctionBox(newElements, l, r, b, t, start, finish); } 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); if (doubleP) { DrawMe(colorBar); } else { EraseAll(); DrawFunctionBox(newElements, l, r, b, t, start, finish); } lastSide = nextSide; } } } } if (!doubleP) { DrawSkeleton(false); } ChangedValue(colorBar); 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 || !IsRealArray(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 || !IsRealArray(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; } void DoRevertPalette() /*Reverts a palette in the top window*/ { ObjPtr repObj, keptPalette, colorBar, textBox, radio; Log("revert\n"); if (!selWinInfo) { return; } repObj = GetPaletteVar("DoRevertPalette", (ObjPtr) selWinInfo, REPOBJ); if (!repObj) { return; } keptPalette = GetPaletteVar("DoRevertPalette", repObj, KEPTPALETTE); if (!keptPalette) { return; } CopyPalette(repObj, keptPalette); SetVar(repObj, CHANGED, ObjTrue); if (colorBar = GetObjectVar("DoRevertPalette", (ObjPtr) selWinInfo, 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", (ObjPtr) selWinInfo, NCOLORBOX)) { sprintf(tempStr, "%d", ((PPtr) repObj) -> nColors); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", (ObjPtr) selWinInfo, MINBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> min); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", (ObjPtr) selWinInfo, MAXBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> max); SetValue(textBox, NewString(tempStr)); } if (radio = GetObjectVar("RevertButton", (ObjPtr) selWinInfo, CMODELRADIO)) { FuncTyp method; method = GetMethod(radio, CHANGEDVALUE); SetMethod(radio, CHANGEDVALUE, (FuncTyp) 0); SetValue(radio, GetVar(repObj, COLORMODEL)); SetMethod(radio, CHANGEDVALUE, method); } /*DIKEO figure out a better way of doing this*/ ForAllVisWindows(ImInvalid); } void DoKeepPalette() /*Keeps the changes in the palette of the current window*/ { ObjPtr repObj, keptPalette, colorBar; Log("keep\n"); if (!selWinInfo) { return; } repObj = GetPaletteVar("DoKeepPalette", (ObjPtr) selWinInfo, REPOBJ); if (!repObj) { return; } CopyPalette(keptPalette, repObj); return; } 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; if (logging) { Log("effect "); Log(spfNames[whichFunc]); Log("\n"); } 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); /*DIKEO figure out a better way of doing this*/ ForAllVisWindows(ImInvalid); ImInvalid(colorBar); return ObjTrue; } void SimpleFuncFromMenu(whichFunc) int whichFunc; /*Do a simple palette function*/ { ObjPtr colorBar, panel; PPtr palette; ObjPtr var; int index1, index2, comp, k; if (!selWinInfo) { return; } #ifndef MENUSFROM0 --whichFunc; #endif colorBar = GetObjectVar("SimpleFuncFromMenu", (ObjPtr) selWinInfo, COLORBAR); if (!colorBar) { return; } palette = (PPtr) GetPaletteVar("SimpleFuncButton", (ObjPtr) selWinInfo, REPOBJ); if (!palette) { return; } var = GetValue(colorBar); if (!var) { return; } if (((real *) ELEMENTS(var))[0] < 1.0) { return; } 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); InhibitLogging(true); ChangedValue(colorBar); InhibitLogging(false); /*DIKEO figure out a better way*/ ForAllVisWindows(ImInvalid); ImInvalid(colorBar); return; } #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); 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 Color 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); return ObjTrue; } 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 (!ParseReal(&min, s)) { return ObjFalse; } #if 0 if (min <= minusInf || min >= plusInf) { DoUniqueTask(DoInfinityError); return ObjFalse; } #endif if (min == missingData) { DoUniqueTask(DoMissingError); return ObjFalse; } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } #if 0 if (min >= palette -> max) { DoUniqueTask(DoRangeError); return ObjFalse; } #endif 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 (!ParseReal(&max, GetString(value))) { DoUniqueTask(DoNumberError); return ObjFalse; } #if 0 if (max <= minusInf || max >= plusInf) { DoUniqueTask(DoInfinityError); return ObjFalse; } #endif if (max == missingData) { DoUniqueTask(DoMissingError); } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } #if 0 if (max <= palette -> min) { DoUniqueTask(DoRangeError); return ObjFalse; } #endif 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 (!ParseInteger(&nColors, GetString(value))) { 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 = GetVar(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 = GetVar(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 Ob