/*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" #include "ScianGarbageMan.h" #include "ScianFontSystem.h" #include "ScianDepend.h" #include "ScianHelp.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*/ 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(ObjPtr palette, int whichColor, int comp, int cc); static int GetColorComponent(ObjPtr palette, int whichColor, int comp); #endif 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(OVERRED, &o1r, &o1g, &o1b); mapcolor(OVERRED, 255, 0, 0); color(1); } } else { if (0 == --overDraw) { 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, nColors; ObjPtr var; short3 *colors; int beg; if (hasCmap == false) return; var = GetVar(p, BEGCOLOR); if (!var) return; beg = GetInt(var); var = GetIntVar("MapPalette", p, NCOLORS); if (!var) return; nColors = GetInt(var); MakeVar(p, COLORS); var = GetVar(p, COLORS); if (!var) return; colors = ELEMENTS(var); for (k = 0; k < nColors; ++k) { mapcolor(beg + k, colors[k][0], colors[k][1], colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void MapPaletteColors(ObjPtr p, int start, int end) #else void MapPaletteColors(p, start, end) ObjPtr p; int start; int end; #endif /*Maps color from start to end in palette p*/ { #ifdef GRAPHICS int k, nColors; ObjPtr var; short3 *colors; int beg; MakeVar(p, COLORS); var = GetVar(p, COLORS); if (!var) return; colors = ELEMENTS(var); var = GetIntVar("MapPaletteColors", p, NCOLORS); if (!var) return; nColors = GetInt(var); if (!hasCmap) return; var = GetVar(p, BEGCOLOR); if (!var) return; beg = GetInt(var); for (k = start; k < MIN(nColors, end + 1); ++k) { mapcolor(beg + k, colors[k][0], colors[k][1], colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void CopyColorsToComponents(ObjPtr p) #else void CopyColorsToComponents(p) ObjPtr p; #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; long dims[2]; var = GetIntVar("CopyColorsToComponents", p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } MakeVar(p, COLORS); var = GetVar(p, COLORS); if (!var) return; colors = ELEMENTS(var); dims[0] = DIMS(var)[0]; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); if (!var) return; components = ELEMENTS(var); SetVar(p, COLORCOMP, var); for (k = 0; k < dims[0]; ++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(ObjPtr p) #else void CopyComponentsToColors(p) ObjPtr p; #endif /*Copies the colors to components based on color model*/ { ObjPtr var; int cm, k; short3 *colors, *components; long dimensions[2]; real r, g, b, h, s, v, l, y, i, q; var = GetIntVar("CopyComponentsToColors", p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } var = GetVar(p, COLORCOMP); if (!var) return; components = ELEMENTS(var); dimensions[0] = DIMS(var)[0]; dimensions[1] = 3; var = NewArray(AT_SHORT, 2, dimensions); if (!var) return; colors = ELEMENTS(var); SetVar(p, COLORS, var); for (k = 0; k < dimensions[0]; ++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; } } } #ifdef PROTO void CopyColorsToPalette(ObjPtr p, short3 *colors) #else void CopyColorsToPalette(p, colors) ObjPtr p; short3 *colors; #endif /*Copies the colors into palette p*/ { int k, nColors; ObjPtr var; long dims[2]; short3 *newColors; var = GetIntVar("CopyColorsToPalette", p, NCOLORS); if (!var) return; nColors = GetInt(var); dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); SetVar(p, COLORS, var); newColors = ELEMENTS(var); for (k = 0; k < nColors; ++k) { newColors[k][0] = colors[k][0]; newColors[k][1] = colors[k][1]; newColors[k][2] = colors[k][2]; } CopyColorsToComponents(p); } #ifdef PROTO void FieldPaletteName(ObjPtr palette, ObjPtr field) #else void FieldPaletteName(palette, field) ObjPtr palette, field; #endif /*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; if (runningScript) { fprintf(stderr, "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."); } else { 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.")); SetVar((ObjPtr) errWindow, INHIBITLOGGING, ObjTrue); } } #ifdef PROTO void SetPalette(ObjPtr p) #else void SetPalette(p) ObjPtr p; #endif /*Sets the current palette to p*/ { ObjPtr var; int nColors; int beg; var = GetIntVar("SetPalette", p, NCOLORS); if (!var) return; nColors = GetInt(var); curNColors = nColors; MakeVar(p, MINMAX); var = GetFixedArrayVar("SetPalette", p, MINMAX, 1, 2L); if (!var) { return; } curMin = ((real *) ELEMENTS(var))[0]; curMax = ((real *) ELEMENTS(var))[1]; #ifdef GRAPHICS if ((!(var = GetVar(p, BEGCOLOR))) && (!rgbp)) { /*Allocate some colors on demand*/ beg = AllocColors(curNColors); if (beg >= 0) { /*Allocation succeeded*/ SetVar(p, BEGCOLOR, NewInt(beg)); MapPalette(p); curBeg = 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 = GetInt(var) + 2; } MakeVar(p, COLORS); var = GetVar(p, COLORS); if (!var) { return; } curColors = ((short3 *) ELEMENTS(var)) + 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*/ { ObjPtr var; var = NewRealArray(1, 2L); ((real *) ELEMENTS(var))[0] = min; ((real *) ELEMENTS(var))[1] = max; SetVar(p, MINMAX, var); SetVar(p, CHANGED, ObjTrue); } #ifdef PROTO static void CompactColors(void) #else static void CompactColors() #endif /*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; } } } #ifdef PROTO static int AllocColors(int n) #else static int AllocColors(n) int n; #endif /*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; } } #ifdef PROTO static void FreeColors(int start, int n) #else static void FreeColors(start, n) int start, n; #endif /*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; } #ifdef PROTO static void MakeUIColor(int whichColor, short r, short g, short b) #else static void MakeUIColor(whichColor, r, g, b) int whichColor; short r, g, b; #endif /*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] * rcos(2.0 * M_PI * value[0]); cy += radius * value[1] * rsin(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] * rcos(2.0 * M_PI * value[0]); lastY = cy + value[1] * rsin(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; ObjPtr var; int nColors; var = GetIntVar("CleanupPalette", palette, NCOLORS); if (!var) return; nColors = GetInt(var); if ((var = GetVar(palette, BEGCOLOR)) && nColors > 0) { /*There are some colors*/ FreeColors(GetInt(var), nColors); } runner = &activePalettes; while (*runner) { if (*runner == (PPtr) palette) { *runner = (*runner) -> next; } else { runner = &((*runner) -> next); } } return ObjTrue; } #ifdef PROTO ObjPtr NewPalette(int nColors) #else ObjPtr NewPalette(nColors) int nColors; #endif /*Returns a new palette of nColors, initially set to a grey ramp. Returns 0 if it can't.*/ { int k, colorBeg; ObjPtr retVal; short3 *colors, *components; ObjPtr var; long dims[2]; retVal = NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return retVal; } dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); SetVar(retVal, COLORCOMP, var); if (!var) { OMErr(); return NULLOBJ; } components = ELEMENTS(var); var = NewArray(AT_SHORT, 2, dims); SetVar(retVal, COLORS, var); if (!var) { OMErr(); return NULLOBJ; } colors = ELEMENTS(var); ((PPtr) retVal) -> next = activePalettes; activePalettes = ((PPtr) retVal) -> next; SETOBJTYPE(retVal -> flags, PALETTE); SetVar(retVal, BEGCOLOR, NULLOBJ); SetVar(retVal, NCOLORS, NewInt(nColors)); for (k = 0; k < nColors; ++k) { colors[k][0] = colors[k][1] = colors[k][2] = (k + 1) * 255 / nColors; } CopyColorsToComponents(retVal); return retVal; } #ifdef PROTO ObjPtr NewAtomicPalette(void) #else ObjPtr NewAtomicPalette() #endif /*Returns a new atomic palette, which maps atomic numbers onto colors*/ { int atom; short3 *colors; ObjPtr atomNames; ObjPtr *namesPtr; ObjPtr retVal; ObjPtr var; long dim; dim = N_ATOMS + 3; retVal = NewPalette(dim); SetPaletteMinMax(retVal, 1, (real) N_ATOMS); /*Give it some colors*/ MakeVar(retVal, COLORS); var = GetVar(retVal, COLORS); if (!var) { return NULLOBJ; } colors = ELEMENTS(var); colors += 2; /*Make the atom names*/ atomNames = NewArray(AT_OBJECT, 1, &dim); namesPtr = ELEMENTS(atomNames); namesPtr[0] = NewString("Missing"); namesPtr[1] = NewString("Bonds"); for (atom = 0; atom < N_ATOMS; ++atom) { namesPtr[atom + 2] = NewString(atomInfo[atom] . longName); GetString(namesPtr[atom + 2])[0] = toupper(GetString(namesPtr[atom + 2])[0]); (*colors)[0] = atomInfo[atom] . color[0]; (*colors)[1] = atomInfo[atom] . color[1]; (*colors)[2] = atomInfo[atom] . color[2]; ++colors; } SetVar(retVal, COLORNAMES, atomNames); return retVal; } #ifdef PROTO void CopyPalette(ObjPtr d, ObjPtr s) #else void CopyPalette(d, s) ObjPtr d, s; #endif /*Copies palette s to d*/ { int k; ObjPtr var; int nDColors, nSColors; short3 *dColors, *sColors; short3 *sComponents, *dComponents; long dims[2]; var = GetIntVar("CopyPalette", d, NCOLORS); if (!var) return; nDColors = GetInt(var); var = GetIntVar("CopyPalette", s, NCOLORS); if (!var) return; nSColors = GetInt(var); /*Free the colors*/ if (var = GetVar(d, BEGCOLOR)) { FreeColors(GetInt(var), nDColors); SetVar(d, BEGCOLOR, NULLOBJ); } SetVar(d, CHANGED, ObjTrue); dims[0] = nSColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); dColors = ELEMENTS(var); SetVar(d, COLORS, var); var = NewArray(AT_SHORT, 2, dims); SetVar(d, COLORCOMP, var); dComponents = ELEMENTS(var); var = GetVar(s, COLORCOMP); sComponents = ELEMENTS(var); if (nDColors != nSColors) { SetVar(d, NCOLORS, NewInt(nSColors)); SetVar(d, CHANGED, ObjTrue); } else { SetVar(d, JUSTCOLORCHANGE, ObjTrue); } SetVar(d, MINMAX, GetVar(s, MINMAX)); MakeVar(s, COLORS); var = GetVar(s, COLORS); if (!var) return; sColors = ELEMENTS(var); for (k = 0; k < nSColors; ++k) { dColors[k][0] = sColors[k][0]; dColors[k][1] = sColors[k][1]; dColors[k][2] = sColors[k][2]; dComponents[k][0] = sComponents[k][0]; dComponents[k][1] = sComponents[k][1]; dComponents[k][2] = sComponents[k][2]; } SetVar(d, COLORMODEL, GetVar(s, COLORMODEL)); MapPalette(d); } #ifdef PROTO void SetPaletteNColors(ObjPtr p, int nColors) #else void SetPaletteNColors(p, nColors) ObjPtr p; int nColors; #endif /*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; ObjPtr var; int oldNColors; long dims[2]; /*Make a new set of colors*/ /*DO NOT Make(p, COLORS)!*/ var = GetVar(p, COLORS); if (!var) return; oldColors = ELEMENTS(var); oldNColors = DIMS(var)[0]; dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); SetVar(p, COLORS, var); colors = ELEMENTS(var); /*Free the colors*/ if (var = GetVar(p, BEGCOLOR)) { FreeColors(GetInt(var), oldNColors); SetVar(p, BEGCOLOR, NULLOBJ); } /*And a new set of components*/ var = GetVar(p, COLORCOMP); if (!var) return; oldComponents = ELEMENTS(var); var = NewArray(AT_SHORT, 2, dims); SetVar(p, COLORCOMP, var); components = ELEMENTS(var); /*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[oldNColors - 1][0]; colors[nColors - 1][1] = oldColors[oldNColors - 1][1]; colors[nColors - 1][2] = oldColors[oldNColors - 1][2]; increment = ((real) oldNColors - 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*/ SetVar(p, NCOLORS, NewInt(nColors)); CopyColorsToComponents(p); 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; ObjPtr var; int nDColors, nSColors; long dims[2]; short3 *sColors, *dColors; var = GetIntVar("CopyAttenuatedPalette", d, NCOLORS); if (!var) return; nDColors = GetInt(var); var = GetIntVar("CopyAttenuatedPalette", s, NCOLORS); if (!var) return; nSColors = GetInt(var); /*Free the colors*/ if (var = GetVar(d, BEGCOLOR)) { FreeColors(GetInt(var), nDColors); SetVar(d, BEGCOLOR, NULLOBJ); } dims[0] = nSColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); dColors = ELEMENTS(var); SetVar(d, COLORS, var); var = NewArray(AT_SHORT, 2, dims); SetVar(d, COLORCOMP, var); MakeVar(s, COLORS); var = GetVar(s, COLORS); if (!var) return; sColors = ELEMENTS(var); SetVar(d, NCOLORS, NewInt(nSColors)); if (nDColors != nSColors) { SetVar(d, CHANGED, ObjTrue); } else { SetVar(d, JUSTCOLORCHANGE, ObjTrue); } SetVar(d, MINMAX, GetVar(s, MINMAX)); for (k = 0; k < nSColors; ++k) { dColors[k][0] = sColors[k][0] * atten; dColors[k][1] = sColors[k][1] * atten; dColors[k][2] = sColors[k][2] * atten; } CopyColorsToComponents(d); MapPalette(d); } ObjPtr ClonePalette(oldPalette) ObjPtr oldPalette; /*Clones a new palette*/ { ObjPtr retVal; short3 *colors, *components; ObjPtr var; int nColors; long dims[2]; var = GetIntVar("ClonePalette", oldPalette, NCOLORS); if (!var) return; nColors = GetInt(var); retVal = NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return retVal; } dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); colors = ELEMENTS(var); SetVar(retVal, COLORS, var); var = NewArray(AT_SHORT, 2, dims); components = ELEMENTS(var); SetVar(retVal, COLORCOMP, var); ((PPtr) retVal) -> next = activePalettes; activePalettes = ((PPtr) retVal) -> next; SETOBJTYPE(retVal -> flags, PALETTE); SetVar(retVal, BEGCOLOR, NULLOBJ); SetVar(retVal, NCOLORS, GetVar(oldPalette, NCOLORS)); CopyPalette(retVal, oldPalette); return retVal; } #ifdef PROTO void InterpPalette(ObjPtr palette, int r1, int g1, int b1, int r2, int g2, int b2) #else void InterpPalette(palette, r1, g1, b1, r2, g2, b2) ObjPtr palette; int r1, g1, b1, r2, g2, b2; #endif /*Makes palette be an interpolation between r1, g1, b1, and r2, g2, b2*/ { int k; int n; int nColors; ObjPtr var; long dims[2]; short3 *colors, *oldColors; var = GetIntVar("InterpPalette", palette, NCOLORS); if (!var) return; nColors = GetInt(var); MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return; oldColors = ELEMENTS(var); dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); colors = ELEMENTS(var); SetVar(palette, COLORS, var); n = nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { colors[k + 2][0] = (k + 1) * r2 / n + (n - k) * r1 / n; colors[k + 2][1] = (k + 1) * g2 / n + (n - k) * g1 / n; colors[k + 2][2] = (k + 1) * b2 / n + (n - k) * b1 / n; } /*Fill in missing*/ colors[0][0] = 64; colors[0][1] = 64; colors[0][2] = 64; /*Fill in min*/ colors[1][0] = colors[2][0]; colors[1][1] = colors[2][1]; colors[1][2] = colors[2][2]; /*Fill in max*/ colors[n + 2][0] = colors[n + 1][0]; colors[n + 2][1] = colors[n + 1][1]; colors[n + 2][2] = colors[n + 1][2]; CopyColorsToComponents(palette); MapPalette(palette); } #ifdef PROTO void BlueToRedPalette(ObjPtr p) #else void BlueToRedPalette(p) ObjPtr p; #endif /*Makes a blue to red palette in p*/ { int k; real hue, r, g, b; int n; int nColors; ObjPtr var; short3 *colors; long dims[2]; var = GetIntVar("BlueToRedPalette", p, NCOLORS); if (!var) return; nColors = GetInt(var); dims[0] = nColors; dims[1] = 3; var = NewArray(AT_SHORT, 2, dims); colors = ELEMENTS(var); SetVar(p, COLORS, var); n = nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { real v = 1.0; 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); colors[k + 2][0] = r * 255; colors[k + 2][1] = g * 255; colors[k + 2][2] = b * 255; } /*Fill in missing*/ colors[0][0] = 64; colors[0][1] = 64; colors[0][2] = 64; /*Fill in min*/ colors[1][0] = colors[2][0]; colors[1][1] = colors[2][1]; colors[1][2] = colors[2][2]; /*Fill in max*/ colors[n + 2][0] = colors[n + 1][0]; colors[n + 2][1] = colors[n + 1][1]; colors[n + 2][2] = colors[n + 1][2]; CopyColorsToComponents(p); MapPalette(p); } #ifdef PROTO real PSColor(void) #else real PSColor() #endif /*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; } #ifdef PROTO void SetUIColor(int c) #else void SetUIColor(c) int c; #endif /*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); 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 } #ifdef PROTO ObjPtr NewColorWheel(int left, int right, int bottom, int top, char *name) #else ObjPtr NewColorWheel(left, right, bottom, top, name) int left, right, bottom, top; char *name; #endif /*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; } } #ifdef PROTO static int ColorToPixel(ObjPtr colorBar, int clr) #else static int ColorToPixel(colorBar, clr) ObjPtr colorBar; int clr; #endif /*Returns the horizontal pixel for the color value in clr*/ { int left, right, bottom, top; ObjPtr palette; int nColors; ObjPtr var; /*Get the palette*/ palette = GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ var = GetIntVar("ColorToPixel", palette, NCOLORS); if (!var) return; nColors = GetInt(var); 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; } } #ifdef PROTO static Bool ColorToPixels(int *lPix, int *rPix, ObjPtr colorBar, int clr) #else static Bool ColorToPixels(lPix, rPix, colorBar, clr) ObjPtr colorBar; int clr; int *lPix, *rPix; #endif /*Returns the horizontal pixelx around the color value in clr*/ { int left, right, bottom, top; ObjPtr palette; int nColors; ObjPtr var; /*Get the palette*/ palette = GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return false; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ var = GetIntVar("ColorToPalette", palette, NCOLORS); if (!var) return; nColors = GetInt(var); 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; } } #ifdef PROTO static int PixelToColor(ObjPtr colorBar, int pix) #else static int PixelToColor(colorBar, pix) ObjPtr colorBar; int pix; #endif /*Returns the color for the horizontal pixel pixel*/ { int left, right, bottom, top; ObjPtr palette; int nColors; ObjPtr var; /*Get the palette*/ palette = GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ var = GetIntVar("ColorToPalette", palette, NCOLORS); if (!var) return; nColors = GetInt(var); 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 */ { double deltaLog; /*Log of the delta at minimum*/ double minDelta; /*Minimum delta between major tics*/ double pixPerMajor; /*Pixels per major step*/ if (diff <= 0.0) { *majorWidth = 0.0; *nMinorSteps = 1; } minDelta = diff * minMajorPix / pixWidth; deltaLog = floor(log10(minDelta)); *majorWidth = pow((double) 10.0, 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; } } /*Adjust to eliminate sub-3-pixel minor tics*/ pixPerMajor = *majorWidth * pixWidth / diff; if (pixPerMajor / *nMinorSteps < 3 && *nMinorSteps > 1) { *nMinorSteps = 1; } } #ifdef PROTO void ResetColorBarTools(ObjPtr colorBar) #else void ResetColorBarTools(colorBar) ObjPtr colorBar; #endif /*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; ObjPtr repObj; real *elements; ObjPtr var; int nColors; 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 = GetPaletteVar("SetColorBarVal", object, REPOBJ); if (repObj) { var = GetIntVar("SetColorBarVal", repObj, NCOLORS); if (!var) { return ObjFalse; } nColors = GetInt(var); if (elements[1] >= ((real) nColors) - 0.5 || elements[2] >= ((real) 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; } } #ifdef PROTO static ObjPtr ReinitColorBar(ObjPtr colorBar) #else static ObjPtr ReinitColorBar(colorBar) ObjPtr colorBar; #endif /*Reinitializes a color bar*/ { return ObjTrue; } #ifdef PROTO real GetColorValue(ObjPtr palette, int color) #else real GetColorValue(palette, color) ObjPtr palette; int color; #endif /*Gets a field value for center of color color. Ignores missing*/ { ObjPtr var; real *minmax; int nColors; var = GetFixedArrayVar("GetColorValue", palette, MINMAX, 1, 2L); if (!var) { return 0.0; } minmax = ELEMENTS(var); var = GetIntVar("GetColorValue", palette, NCOLORS); if (!var) { return 0.0; } nColors = GetInt(var); return minmax[0] + (color - 2) * (minmax[1] - minmax[0]) / (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; ObjPtr 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*/ real *minmax; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); if (IsDrawingRestricted(left, right, bottom, top)) return ObjFalse; /*Get the palette*/ palette = GetPaletteVar("DrawColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*Get the stuff from the palette*/ var = GetIntVar("DrawColorBar", palette, NCOLORS); if (!var) return; nColors = GetInt(var); MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return; colors = ELEMENTS(var); /*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; var = GetVar(palette, MINMAX); if (!var) { return ObjFalse; } minmax = ELEMENTS(var); ddiff = minmax[1] - minmax[0]; halfSpace = ddiff / (nColors - 4) * 0.5; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = minmax[0] / majorWidth; curValue = temp * majorWidth; while (curValue > minmax[0]) { curValue -= majorWidth; } k = 0; while (curValue < minmax[0]) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= minmax[1] + ddiff * 1.0E-6) { pixel = l + (curValue - minmax[0]) * (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", 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(palette); var = GetVar(palette, BEGCOLOR); if (!var) return ObjFalse; beg = GetInt(var); /*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(palette); var = GetVar(palette, BEGCOLOR); if (!var) return ObjFalse; beg = GetInt(var); /*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 = (minmax[1] - minmax[0]) / (nColors - 4) * 0.5; start = GetColorValue(palette, (int) elements[1]) - halfSpace; finish = GetColorValue(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; } #ifdef PROTO ObjPtr SetFunctionBox(ObjPtr colorBar, ObjPtr functionBox) #else ObjPtr SetFunctionBox(colorBar, functionBox) ObjPtr colorBar; ObjPtr functionBox; #endif /*Sets the FUNCTIONBOX of colorBar to functionBox, also logs*/ { real *elements; ObjPtr repObj; if (functionBox && (!IsRealArray(functionBox) || RANK(functionBox) != 1 || DIMS(functionBox)[0] != 4)) { ReportError("SetFunctionBox", "Bad value given"); return ObjFalse; } repObj = 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; } #ifdef PROTO void LogColorChange(ObjPtr colorBar, short3 *colors, int newColor) #else void LogColorChange(colorBar, colors, newColor) ObjPtr colorBar; short3 *colors; int newColor; #endif /*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); } } #ifdef PROTO ObjPtr SetColorBarColor(ObjPtr colorBar, int whichColor, int r, int g, int b) #else ObjPtr SetColorBarColor(colorBar, whichColor, r, g, b) ObjPtr colorBar; int whichColor, r, g, b; #endif /*Sets color whichColor from inside a color bar*/ { ObjPtr palette; short3 *colors; ObjPtr var; palette = GetPaletteVar("SetColorBarColor", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*DIKEO destructive! Change this later!*/ MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!colors) return ObjFalse; colors = ELEMENTS(var); colors[whichColor][0] = r; colors[whichColor][1] = g; colors[whichColor][2] = b; ImInvalid(colorBar); LogColorChange(colorBar, colors, whichColor); ChangedValue(colorBar); #ifdef GRAPHICS MapPaletteColors(palette, whichColor, whichColor); #endif SetVar(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; int nColors; ObjPtr var; 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 = GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetIntVar("PressColorBar", palette, NCOLORS); if (!var) return; nColors = GetInt(var); /*Get the color model*/ var = GetIntVar("PressColorBar", 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; ObjPtr palette; int index1, index2; int k; int comp; short3 *colors; int newX, newY, newColor, newAmp; ObjPtr panel, button; ObjPtr var; palette = GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) { return ObjFalse; } colors = ELEMENTS(var); 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 } CopyComponentsToColors(palette); 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(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; real *minmax; #define MOVEBOXTOP 1 #define MOVEBOXBOTTOM 2 #define MOVEBOXLEFT 3 #define MOVEBOXRIGHT 4 #define MOVEBOXLR 5 var = GetVar(palette, MINMAX); minmax = ELEMENTS(var); halfSpace = (minmax[1] - minmax[0]) / (nColors - 4) * 0.5; start = GetColorValue(palette, index1) - halfSpace; finish = GetColorValue(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 = (minmax[1] - minmax[0]) / (nColors - 4) * 0.5; start = GetColorValue(palette, index1) - halfSpace; finish = GetColorValue(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(palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); } } return ObjTrue; } else { return ObjFalse; } #else return ObjFalse; #endif } #ifdef PROTO ObjPtr NewColorBar(int left, int right, int bottom, int top, char *name) #else ObjPtr NewColorBar(left, right, bottom, top, name) int left, right, bottom, top; char *name; #endif /*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 slider, ObjPtr palette, int component, int index1, int index2) #else static void ChoosePaletteSliderValue(slider, palette, component, index1, index2) ObjPtr slider; ObjPtr palette; int index1, index2, component; #endif /*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; ObjPtr var; MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return; colors = ELEMENTS(var); 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, CloneObject(palette)); } static ObjPtr ChangePaletteBar(colorBar) ObjPtr colorBar; /*Changed value for a color bar that controls a palette*/ { ObjPtr colorWheel, slider, button, buttons; ThingListPtr buttonList; ObjPtr 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 = 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*/ ObjPtr var; MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return ObjFalse; colors = ELEMENTS(var); /*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; ObjPtr 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 = 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; /*DIKEO DESTRUCTIVE change*/ MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return ObjFalse; colors = ELEMENTS(var); for (k = index1; k <= index2; ++k) { colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette); #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif SetVar(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, CloneObject(palette)); /* interactiveMoving = false;*/ ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } static ObjPtr ChangePaletteSlider(slider) ObjPtr slider; /*Changes a palette's slider*/ { ObjPtr colorBar, panel, button; ObjPtr 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 = GetPaletteVar("ChangePaletteSlider", slider, TEMPPALETTE); if (!colorBar || !tempPalette) { return ObjFalse; } palette = 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); /*DIKEO DESTRUCTIVE*/ MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) return ObjFalse; colors = ELEMENTS(var); MakeVar(tempPalette, COLORS); var = GetVar(tempPalette, COLORS); if (!var) return ObjFalse; tempColors = ELEMENTS(var); 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); } 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); } #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); } 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); } #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif } ResetColorBarTools(colorBar); SetVar(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); } /*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; } #ifdef PROTO static void SimplePaletteFunction(int whichFunc, ObjPtr palette, int index1, int index2, int comp, ObjPtr colorBar) #else static void SimplePaletteFunction(whichFunc, palette, index1, index2, comp, colorBar) int whichFunc; ObjPtr palette; int index1, index2, comp; ObjPtr colorBar; #endif /*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; ObjPtr var; real *minmax; int nColors; var = GetVar(palette, MINMAX); if (!var) { return; } minmax = ELEMENTS(var); var = GetIntVar("SimplePaletteFunction", palette, NCOLORS); if (!var) return; nColors = GetInt(var); 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 = (minmax[1] - minmax[0]) / (nColors - 4) * 0.5; ddiff = minmax[1] - minmax[0] + 2 * halfSpace; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; l = index1; val = (l - 2) * ddiff / (nColors - 3); oldQuotient = val / minorWidth; for (r = l + 1; r <= index2; ++r) { val = (r - 2) * ddiff / (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); } static ObjPtr SimpleFuncButton(button) ObjPtr button; /*Do a simple palette function*/ { ObjPtr colorBar, panel; ObjPtr 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 = 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(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; ObjPtr 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 = 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(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(ObjPtr palette, int whichColor, int comp) #else static int GetColorComponent(palette, whichColor, comp) ObjPtr palette; int whichColor; int comp; #endif /*Gets the color component comp from whichColor in palette*/ { ObjPtr var; short3 *components; var = GetVar(palette, COLORCOMP); components = ELEMENTS(var); return components[whichColor][comp]; } #ifdef PROTO static void SetColorComponent(ObjPtr palette, int whichColor, int comp, int cc) #else static void SetColorComponent(palette, whichColor, comp, cc) ObjPtr 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]; ObjPtr var; short3 *components; var = GetVar(palette, COLORCOMP); components = ELEMENTS(var); /*DIKEO DESTRUCTIVE*/ components[whichColor][comp] = cc; } #ifdef PROTO ObjPtr ImposeColorFunction(ObjPtr colorBar) #else ObjPtr ImposeColorFunction(colorBar) ObjPtr colorBar; #endif /*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(palette, k, comp, cc); } CopyComponentsToColors(palette); MapPaletteColors(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(palette, JUSTCOLORCHANGE, ObjTrue); return ObjTrue; } static ObjPtr ChangeColorTool(group) ObjPtr group; /*Changes a color tool in response to a radio button group*/ { ObjPtr colorBar; ObjPtr palette; ObjPtr value; ObjPtr var; int tool; ObjPtr selection; real *elements; int nColors; colorBar = GetObjectVar("ChangeColorTool", group, REPOBJ); if (!colorBar) { return ObjFalse; } selection = GetValue(colorBar); elements = ELEMENTS(selection); palette = GetPaletteVar("ChangeColorTool", colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetIntVar("ChangeColorTool", palette, NCOLORS); if (!var) { return ObjFalse; } nColors = GetInt(var); 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; real *minmax; var = GetFixedArrayVar("ChangeColorTool", palette, MINMAX, 1, 2L); if (!var) { return ObjFalse; } minmax = ELEMENTS(var); Get2DIntBounds(colorBar, &left, &right, &bottom, &top); l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; halfSpace = (minmax[1] - minmax[0]) / (nColors - 4) * 0.5; start = GetColorValue(palette, (int) elements[1]) - halfSpace; finish = GetColorValue(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(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 ShowPaletteDisplayControls(display, windowName) ObjPtr display; char *windowName; /*Makes a new control window to control a palette display*/ { WinInfoPtr controlWindow; ObjPtr var; ObjPtr panel; ObjPtr corral; ObjPtr contents; WinInfoPtr dialogExists; Bool hasBackground; dialogExists = DialogExists((WinInfoPtr) display, NewString("Controls")); controlWindow = GetDialog((WinInfoPtr) display, NewString("Controls"), windowName, DSPPALWINWIDTH, DSPPALWINHEIGHT, DSPPALWINWIDTH, DSPPALWINHEIGHT, WINDBUF + WINRGB + WINFIXEDSIZE); if (!dialogExists) { long info; ObjPtr value; ObjPtr checkBox, icon, name, colorBar, titleBox, textBox, button; ObjPtr colorWheel, slider, radioGroup; int left, right, bottom, top; SetVar((ObjPtr) controlWindow, REPOBJ, display); /*Set help string*/ SetVar((ObjPtr) controlWindow, HELPSTRING, NewString("This window \ shows controls for a color palette legend. For information about any of the controls \ in the window, use Help In Context on the control.\n")); /*Add in a panel*/ panel = NewPanel(greyPanelClass, 0, DSPPALWINWIDTH, 0, DSPPALWINHEIGHT); if (!panel) { return ObjFalse; } contents = GetVar((ObjPtr) controlWindow, CONTENTS); PrefixList(contents, panel); SetVar(panel, PARENT, (ObjPtr) controlWindow); contents = GetVar(panel, CONTENTS); /*Add in the group of controls for text color*/ left = MAJORBORDER; top = DSPPALWINHEIGHT - MAJORBORDER; right = left + 4 * MAJORBORDER + COLORWHEELWIDTH + SLIDERWIDTH; titleBox = NewTitleBox(left, right, top - TITLEBOXTOP - MAJORBORDER - 2 * MINORBORDER - COLORWHEELWIDTH - CHECKBOXHEIGHT - TEXTBOXHEIGHT - TEXTBOXSEP, top, "Text and Lines"); SetVar(titleBox, PARENT, panel); PrefixList(contents, titleBox); left += MAJORBORDER; right -= MAJORBORDER; top -= TITLEBOXTOP + MAJORBORDER; /*Make the color wheel*/ colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH, top, "Text Color"); SetVar(colorWheel, PARENT, panel); PrefixList(contents, colorWheel); AssocColorControlWithVar(colorWheel, display, COLOR); SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \ hue and saturation of the color used to draw the text and lines in the palette legend. \ The final color is a combination of this hue and saturation and the value, or brightness, \ given by the Value slider.")); /*Make the text box below*/ textBox = NewTextBox(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Text Color Label", "Color"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); /*Make the brightness slider*/ slider = NewSlider(right - SLIDERWIDTH, right, top - COLORWHEELWIDTH, top, PLAIN, "Text Color Value"); SetVar(slider, PARENT, panel); PrefixList(contents, slider); SetSliderRange(slider, 1.0, 0.0, 0.0); AssocBrightnessControlWithVar(slider, display, COLOR); SetVar(slider, HELPSTRING, NewString("This slider controls the \ value, or brightness, of the color used to draw the text and lines in the palette legend. \ The final color is a combination of this value and the hue and saturation \ given by the Color color wheel.")); /*Make the text box below*/ textBox = NewTextBox(right - SLIDERWIDTH - MAJORBORDER, right + MAJORBORDER, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Text Value Label", "Value"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); left -= MINORBORDER; right += MINORBORDER; /*Make the check box*/ top -= COLORWHEELWIDTH + TEXTBOXSEP + TEXTBOXHEIGHT + MINORBORDER; if (!GetVar(display, COLORBYFIELD)) { SetVar(display, COLORBYFIELD, ObjFalse); } checkBox = NewCheckBox(left, right, top - CHECKBOXHEIGHT, top, "Color Text by Palette", GetPredicate(display, COLORBYFIELD)); SetVar(checkBox, PARENT, panel); AssocDirectControlWithVar(checkBox, display, COLORBYFIELD); PrefixList(contents, checkBox); SetVar(checkBox, HELPSTRING, NewString("This check box controls \ how the numbers in the palette legend are colored. If the box is checked, the \ numbers are colored according to the values they represent. If the box is not \ checked, the numbers are colored with the same color used for the lines in the \ legend.")); /*Make the background controls*/ top = DSPPALWINHEIGHT - MAJORBORDER; right = DSPPALWINWIDTH - MAJORBORDER; left = right - (4 * MAJORBORDER + COLORWHEELWIDTH + SLIDERWIDTH); titleBox = NewTitleBox(left, right, top - TITLEBOXTOP - MAJORBORDER - 2 * MINORBORDER - COLORWHEELWIDTH - CHECKBOXHEIGHT - TEXTBOXHEIGHT - TEXTBOXSEP, top, "Background"); SetVar(titleBox, PARENT, panel); PrefixList(contents, titleBox); left += MAJORBORDER; right -= MAJORBORDER; top -= TITLEBOXTOP + MAJORBORDER; /*Make the color wheel*/ colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH, top, "Background Color"); SetVar(colorWheel, PARENT, panel); PrefixList(contents, colorWheel); AssocColorControlWithVar(colorWheel, display, BACKGROUND); SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \ hue and saturation of the color used to draw the background of the palette legend. \ The final color is a combination of this hue and saturation and the value, or brightness, \ given by the Value slider.")); /*Make the text box below*/ textBox = NewTextBox(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Background Color Label", "Color"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); /*Make the brightness slider*/ slider = NewSlider(right - SLIDERWIDTH, right, top - COLORWHEELWIDTH, top, PLAIN, "Background Value"); SetVar(slider, PARENT, panel); PrefixList(contents, slider); SetSliderRange(slider, 1.0, 0.0, 0.0); AssocBrightnessControlWithVar(slider, display, BACKGROUND); SetVar(slider, HELPSTRING, NewString("This slider controls the \ value, or brightness, of the color used to draw the background of the palette legend. \ The final color is a combination of this value and the hue and saturation \ given by the Color color wheel.")); /*Make the text box below*/ textBox = NewTextBox(right - SLIDERWIDTH - MAJORBORDER, right + MAJORBORDER, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Background Value Label", "Value"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); left -= MINORBORDER; right += MINORBORDER; /*Make the check box*/ top -= COLORWHEELWIDTH + TEXTBOXSEP + TEXTBOXHEIGHT + MINORBORDER; checkBox = NewCheckBox(left, right, top - CHECKBOXHEIGHT, top, "No Background", hasBackground ? false : true); SetVar(checkBox, PARENT, panel); PrefixList(contents, checkBox); AssocInhibitControlWithVar(checkBox, display, BACKGROUND, NewInt(UIBLACK)); SetVar(checkBox, HELPSTRING, NewString("This checkbox controls whether \ a background is shown. If it is selected, no background is shown, and the \ objects behind can be seen.")); top -= CHECKBOXHEIGHT + MINORBORDER + MINORBORDER; left = MAJORBORDER; right = DSPPALWINWIDTH - MAJORBORDER; /*Make checkbox for show missing*/ checkBox = NewCheckBox(left, (left + right) / 2, top - CHECKBOXHEIGHT, top, "Show Missing", GetPredicate(display, SHOWMISSING)); if (!GetVar(display, SHOWMISSING)) { SetVar(display, SHOWMISSING, ObjFalse); } SetVar(checkBox, PARENT, panel); PrefixList(contents, checkBox); AssocDirectControlWithVar(checkBox, display, SHOWMISSING); SetVar(checkBox, HELPSTRING, NewString("This check box controls \ whether an entry for Missing data is shown in the palette legend.")); /*Make checkbox for show Over and Under*/ checkBox = NewCheckBox((left + right) / 2, right, top - CHECKBOXHEIGHT, top, "Show Over and Under", GetPredicate(display, SHOWOVERUNDER)); SetVar(checkBox, PARENT, panel); PrefixList(contents, checkBox); if (!GetVar(display, SHOWOVERUNDER)) { SetVar(display, SHOWOVERUNDER, ObjFalse); } AssocDirectControlWithVar(checkBox, display, SHOWOVERUNDER); SetVar(checkBox, HELPSTRING, NewString("This check box controls \ whether entries for Over and Under data are shown in the palette legend.")); top -= CHECKBOXHEIGHT + MINORBORDER; /*Make checkbox for show minor tics*/ checkBox = NewCheckBox(left, (left + right) / 2, top - CHECKBOXHEIGHT, top, "Show Minor Tics", GetPredicate(display, SHOWMINORTICS)); SetVar(checkBox, PARENT, panel); PrefixList(contents, checkBox); if (!GetVar(display, SHOWMINORTICS)) { SetVar(display, SHOWMINORTICS, ObjFalse); } AssocDirectControlWithVar(checkBox, display, SHOWMINORTICS); SetVar(checkBox, HELPSTRING, NewString("This check box controls \ whether minor tic marks are shown in the palette legend in addition to major \ tic marks and numbers.")); /*Make checkbox for numbers only*/ checkBox = NewCheckBox((left + right) / 2, right, top - CHECKBOXHEIGHT, top, "Numbers Only", GetPredicate(display, NUMBERSONLY)); SetVar(checkBox, PARENT, panel); PrefixList(contents, checkBox); if (!GetVar(display, NUMBERSONLY)) { SetVar(display, NUMBERSONLY, ObjFalse); } AssocDirectControlWithVar(checkBox, display, NUMBERSONLY); SetVar(checkBox, HELPSTRING, NewString("When this check box is down, \ only the numbers are shown in the palette legend. This is useful in conjunction \ with the \"Color text by palette\" check box.")); } return (ObjPtr) controlWindow; } void ColorModelFromMenu(whichColorModel) int whichColorModel; /*Sets the color model in the current window from whichColorModel*/ { ObjPtr colorBar, palette; ObjPtr var; int nColors; if (!selWinInfo) { return; } #ifndef MENUSFROM0 --whichColorModel; #endif if (logging) { Log("model "); Log(colorModelNames[whichColorModel]); Log("\n"); } colorBar = GetVar((ObjPtr) selWinInfo, COLORBAR); if (!colorBar) { return; } palette = GetPaletteVar("ColorModelFromMenu", colorBar, REPOBJ); if (!colorBar) { return; } SetVar(palette, COLORMODEL, NewInt(whichColorModel)); var = GetIntVar("SimplePaletteFunction", palette, NCOLORS); if (!var) return; nColors = GetInt(var); CopyColorsToComponents(palette); ChangedValue(colorBar); ImInvalid(colorBar); /*Set the edit tool to free form*/ ResetColorBarTools(colorBar); } static ObjPtr ShowPaletteControls(palette, windowName) ObjPtr palette; char *windowName; /*Makes a new control window to control a palette*/ { WinInfoPtr controlWindow; ObjPtr var; ObjPtr panel; ObjPtr corral; ObjPtr contents; WinInfoPtr dialogExists; int left, right, bottom, top; GetTemplateBounds(PaletteTemplate, "Panel", &left, &right, &bottom, &top); dialogExists = DialogExists((WinInfoPtr) palette, NewString("Controls")); controlWindow = GetDialog((WinInfoPtr) palette, NewString("Controls"), windowName, right - left, top - bottom, SCRWIDTH, SCRHEIGHT, WINDBUF + WINRGB); if (!dialogExists) { long info; ObjPtr value; int k; ObjPtr checkBox, icon, name, colorBar, titleBox, textBox, button; ObjPtr colorWheel, slider, fullCompList, compList, radioGroup; char numBuf[200]; char *s; /*Add some menu items*/ DefineMenuItem((ObjPtr) controlWindow, FILEMENU, "Save Palette", DoSaveObject); DefineMenuItem((ObjPtr) controlWindow, COLORMENU, "Save Palette", DoSaveObject); DefineMenuItem((ObjPtr) controlWindow, COLORMENU, "Keep Changes", DoKeepPalette); DefineMenuItem((ObjPtr) controlWindow, COLORMENU, "Revert to Original", DoRevertPalette); for (k = 0; k < NPALETTEFUNCS; ++k) { strcpy(numBuf, spfNames[k]); numBuf[0] = toupper(numBuf[0]); DefineMenuItem((ObjPtr) controlWindow, EFFECTSMENU, numBuf, SimpleFuncFromMenu); } for (k = 0; k < NCOLORMODELS; ++k) { strcpy(numBuf, colorModelNames[k]); numBuf[0] = toupper(numBuf[0]); DefineMenuItem((ObjPtr) controlWindow, COLORMODELMENU, numBuf, ColorModelFromMenu); } SetVar((ObjPtr) controlWindow, REPOBJ, palette); /*Set help string*/ SetVar((ObjPtr) controlWindow, HELPSTRING, NewString("This window \ shows controls for a color palette. For information about any of the controls \ in the window, use Help In Context on the control.\n")); /*Add in a panel*/ panel = TemplatePanel(PaletteTemplate, "Panel"); if (!panel) { return ObjFalse; } contents = GetVar((ObjPtr) controlWindow, CONTENTS); PrefixList(contents, panel); SetVar(panel, PARENT, (ObjPtr) controlWindow); contents = GetVar(panel, CONTENTS); /*Create a color bar to add in later*/ left = 2 * MAJORBORDER + PCWINLSIDE; right = PCWINWIDTH - MAJORBORDER; bottom = MAJORBORDER + PCBARUP; top = bottom + PCBARHEIGHT; colorBar = TemplateColorBar(PaletteTemplate, "Palette Colors"); fullCompList = NewList(); /*List of buttons active on full or component*/ compList = NewList(); /*List of buttons active on component*/ SetVar(colorBar, FULLCOMPBUTTONS, fullCompList); SetVar(colorBar, COMPBUTTONS, compList); SetVar(colorBar, EDITMODE, NewInt(PT_FREEFORM)); /*Freeform editor*/ SetVar((ObjPtr) controlWindow, COLORBAR, colorBar); SetVar(colorBar, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT + STICKYBOTTOM + STICKYTOP)); /*Ramp button*/ button = TemplateButton(PaletteTemplate, "Ramp"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_RAMP)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button interpolates between the selected \ colors to make a smooth color ramp. When a range in the full color bar is \ selected, all components will be interpolated. When a range of a single component \ is selected, just that component will be interpolated.\n")); SetVar(button, HALTHELP, ObjTrue); /*Reverse button*/ button = TemplateButton(PaletteTemplate, "Reverse"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_REVERSE)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button reverses the range of selected colors. \ When a range in the full color bar is \ selected, all components will be reversed. When a range of a single component \ is selected, just that component will be reversed.\n")); SetVar(button, HALTHELP, ObjTrue); /*Smooth button*/ button = TemplateButton(PaletteTemplate, "Smooth"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_SMOOTH)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button smooths the selected colors. \ This will reduce the abrupt changes which can worsen artifacts such as Mach bands. \ You can smooth a range more by pressing the button repeatedly. \ When a range in the full color bar is \ selected, all components will be smoothed. When a range of a single component \ is selected, just that component will be smoothed.\n")); SetVar(button, HALTHELP, ObjTrue); /*Sharpen button*/ button = TemplateButton(PaletteTemplate, "Sharpen"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_SHARPEN)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button sharpens color distinction within the selected colors. \ This may increase artifacts such as Mach bands. Sharpen and Smooth are not \ quite inverse operations, but they have roughly opposite effects. Sharpen will \ amplify noise and variations in the colors, which will become evident after the \ button is pressed three or four times. \ When a range in the full color bar is \ selected, all components will be sharpened. When a range of a single component \ is selected, just that component will be sharpened.\n")); SetVar(button, HALTHELP, ObjTrue); /*Put in the min and max text boxes below*/ textBox = TemplateTextBox(PaletteTemplate, "Field Min", EDITABLE + WITH_PIT + ONE_LINE, ""); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, HELPSTRING, NewString("This text box shows the maximum \ field value represented by the color table. Any value above this will use the \ overflow color. To change this value, enter the new number and press the Enter \ key.")); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); AssocIndexedTextRealControlWithVar( textBox, palette, MINMAX, 0, minusInf, plusInf, 0); /*Min legend*/ textBox = TemplateTextBox(PaletteTemplate, "Field Min Legend", 0, "Minimum:"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); /*Max text box*/ textBox = TemplateTextBox(PaletteTemplate, "Field Max", EDITABLE + WITH_PIT + ONE_LINE, ""); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, HELPSTRING, NewString("This text box shows the minimum \ field value represented by the color table. Any value below this will use the \ underflow color. To change this value, enter the new number and press the Enter \ key.")); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); AssocIndexedTextRealControlWithVar( textBox, palette, MINMAX, 1, minusInf, plusInf, 0); /*Max legend*/ textBox = TemplateTextBox(PaletteTemplate, "Field Max Legend", 0, "Maximum:"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); /*nColors text box*/ left = MAJORBORDER; textBox = TemplateTextBox(PaletteTemplate, "N Colors", EDITABLE + WITH_PIT + ONE_LINE, ""); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, HELPSTRING, NewString("This text box shows the number of colors \ in the palette, including the missing data, underflow, and overflow entries. \ To change the number of colors, enter the new number and press the Enter \ key. The palette will be resampled with the new number of colors. When increasing \ the number of colors, it is sometimes useful to do a Smooth operation afterward \ to smooth out the changes.")); AssocTextIntControlWithVar( textBox, palette, NCOLORS, 5.0, plusInf, TR_INT_ONLY | TR_NE_TOP); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); /*nColors legend*/ textBox = TemplateTextBox(PaletteTemplate, "NColors Legend", 0, "Colors"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetVar(textBox, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGBOTTOM)); /*Add in the left color control group*/ left = MINORBORDER; right = left + PCWINLSIDE; top = PCWINHEIGHT - MINORBORDER; SetVar(palette, KEPTPALETTE, CloneObject(palette)); bottom = MINORBORDER + PCBARUP; top = bottom + COLORWHEELWIDTH + TEXTBOXHEIGHT + TEXTBOXSEP; /*Color wheel*/ colorWheel = TemplateColorWheel(PaletteTemplate, "Color"); SetVar(colorWheel, PARENT, panel); PrefixList(contents, colorWheel); SetVar(colorWheel, REPOBJ, palette); ActivateColorWheel(colorWheel, false); SetVar(colorWheel, VALUE, false); SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the hue and saturation of the \ entire range of selected colors. When you use this control, the entire range \ will be set to the new color.")); SetVar(colorWheel, HALTHELP, ObjTrue); /*Color wheel text box*/ textBox = TemplateTextBox(PaletteTemplate, "HS Text", 0, "Color"); PrefixList(contents, textBox); SetVar(textBox, PARENT, panel); SetTextAlign(textBox, CENTERALIGN); /*Slider*/ slider = TemplateSlider(PaletteTemplate, "Intensity", PLAIN); PrefixList(contents, slider); SetVar(slider, PARENT, panel); SetSliderRange(slider, 1.0, 0.0, 0.0); SetSliderValue(slider, 1.0); ActivateSlider(slider, false); SetVar(slider, HELPSTRING, NewString("This slider controls the intensity of \ the colors selected in the color bar control to the right. When a range of colors is selected, this slider controls the value \ of the colors represented in the Hue/Saturation/Value color model. \ When a range of a single color component is selected, it controls the intensity \ of that component.")); SetVar(slider, HALTHELP, ObjTrue); /*Slider text box*/ textBox = TemplateTextBox(PaletteTemplate, "Intensity Text", 0, "Intensity"); PrefixList(contents, textBox); SetVar(textBox, PARENT, panel); SetTextAlign(textBox, CENTERALIGN); /*Link slider and color wheel*/ SetVar(slider, COLORWHEEL, colorWheel); SetVar(colorWheel, SLIDER, slider); /*Link the color wheels to the color bar*/ SetVar(slider, COLORBAR, colorBar); SetVar(colorWheel, COLORBAR, colorBar); /*Waveform tools*/ top = MAJORBORDER + PCBARHEIGHT + PCBARUP; bottom = top - (TITLEBOXTOP + 2 * MINORBORDER + VWTOOLBORDER + 2 * SMALLICONBUTTONSIZE); titleBox = TemplateTitleBox(PaletteTemplate, "Edit Component"); PrefixList(contents, titleBox); SetVar(titleBox, PARENT, panel); left += MINORBORDER; right -= MINORBORDER; bottom += MINORBORDER; top -= TITLEBOXTOP + MINORBORDER; /*Icons*/ radioGroup = NewRadioButtonGroup("Waveform Tools"); SetVar(colorBar, TOOLGROUP, radioGroup); SetVar(radioGroup, HELPSTRING, NewString("This is a group of tools that allow you to edit the \ currently selected color component. \ To use one of these tools, \ first select a range in any one of the color components by dragging through the range \ and then press the button of the tool \ you want to use.")); SetVar(radioGroup, PARENT, panel); PrefixList(contents, radioGroup); SetVar(radioGroup, HALTHELP, ObjTrue); /*Freeform*/ button = TemplateIconButton(PaletteTemplate, "Free form", ICONFREEFORM, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); SetVar(colorBar, FREEFORMBUTTON, button); SetVar(button, HELPSTRING, NewString("This button selects the \ free form tool, which allows you to edit the waveform simply by clicking \ and drawing in the magnified readout at the top of the color bar to the right. \ Hold down the Shift key to constrain motion to just the horizontal or \ vertical direction.")); /*Sine*/ button = TemplateIconButton(PaletteTemplate, "Sine", ICONSINE, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); PrefixList(compList, button); SetVar(button, HELPSTRING, NewString("This button selects the \ sine wave tool, which fills the entire selected range with a sine wave. \ When this tool is selected, a yellow box in the magnified readout lets you \ change the period, phase, and position of the wave.")); /*Triangle*/ button = TemplateIconButton(PaletteTemplate, "Triangle", ICONTRIANGLE, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); PrefixList(compList, button); SetVar(button, HELPSTRING, NewString("This button selects the \ triangle wave tool, which fills the entire selected range with a triangle wave. \ When this tool is selected, a yellow box in the magnified readout lets you \ change the period, phase, and position of the wave.")); /*Sawtooth*/ button = TemplateIconButton(PaletteTemplate, "Sawtooth", ICONSAWTOOTH, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); PrefixList(compList, button); SetVar(button, HELPSTRING, NewString("This button selects the \ sawtooth wave tool, which fills the entire selected range with a sawtooth wave. \ When this tool is selected, a yellow box in the magnified readout lets you \ change the period, phase, and position of the wave.")); /*Toothsaw*/ button = TemplateIconButton(PaletteTemplate, "Toothsaw", ICONTOOTHSAW, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); PrefixList(compList, button); SetVar(button, HELPSTRING, NewString("This button selects the \ reverse sawtooth wave tool, which fills the entire selected range with a reverse sawtooth wave. \ When this tool is selected, a yellow box in the magnified readout lets you \ change the period, phase, and position of the wave.")); /*Square*/ button = TemplateIconButton(PaletteTemplate, "Square", ICONSQUARE, UIYELLOW, BS_PLAIN); AddRadioButton(radioGroup, button); ActivateButton(button, false); PrefixList(compList, button); SetVar(button, HELPSTRING, NewString("This button selects the \ square wave tool, which fills the entire selected range with a square wave. \ When this tool is selected, a yellow box in the magnified readout lets you \ change the period, phase, and position of the wave.")); SetValue(radioGroup, NewInt(PT_FREEFORM)); SetVar(radioGroup, REPOBJ, colorBar); SetMethod(radioGroup, CHANGEDVALUE, ChangeColorTool); /*Now add in the color bar*/ SetMethod(colorBar, MAKE1HELPSTRING, MakePaletteBarHelp); SetVar(colorBar, HALTHELP, ObjTrue); PrefixList(contents, colorBar); SetVar(colorBar, PARENT, panel); SetVar(colorBar, REPOBJ, palette); SetVar(colorBar, SLIDER, slider); SetVar(colorBar, COLORWHEEL, colorWheel); SetVar(panel, COLORBAR, colorBar); value = NewRealArray(1, 3L); ((real *) ELEMENTS(value))[0] = 0.0; ((real *) ELEMENTS(value))[1] = 0.0; ((real *) ELEMENTS(value))[2] = 0.0; SetMethod(colorBar, CHANGEDVALUE, ChangePaletteBar); SetValue(colorBar, value); ReinitColorBar(colorBar); /*Give the color wheels and sliders changedValue routines*/ SetMethod(colorWheel, CHANGEDVALUE, ChangePaletteColorWheel); SetMethod(slider, CHANGEDVALUE, ChangePaletteSlider); } return (ObjPtr) controlWindow; } #ifdef PROTO int ChooseSelectionColor(ObjPtr object) #else int ChooseSelectionColor(object) ObjPtr object; #endif /*Chooses a selection color to contrast with object's COLOR and BACKGROUND*/ { ObjPtr color, background, oneOnly; float target[3]; float r1, g1, b1, r2, g2, b2, t, b; real *elements; color = GetVar(object, COLOR); background = GetVar(object, BACKGROUND); if (!color && !background) { /*Nothing there, so use UIWHITE*/ return UIWHITE; } if (color) { if (IsInt(color)) { int c; c = GetInt(color); r1 = ((float) uiColors[c][0]) / 255.0; g1 = ((float) uiColors[c][1]) / 255.0; b1 = ((float) uiColors[c][2]) / 255.0; } else if (IsRealArray(color) && RANK(color) == 1 && DIMS(color)[0] == 3) { elements = ELEMENTS(color); r1 = elements[0]; g1 = elements[1]; b1 = elements[2]; } else { ReportError("ChooseSelectionColor", "Bad color"); return UIWHITE; } } else { r1 = g1 = b1 = 0.0; } if (background) { if (IsInt(background)) { int c; c = GetInt(background); r2 = ((float) uiColors[c][0]) / 255.0; g2 = ((float) uiColors[c][1]) / 255.0; b2 = ((float) uiColors[c][2]) / 255.0; } else if (IsRealArray(background) && RANK(background) == 1 && DIMS(background)[0] == 3) { elements = ELEMENTS(background); r2 = elements[0]; g2 = elements[1]; b2 = elements[2]; } else { ReportError("ChooseSelectionColor", "Bad background"); return UIWHITE; } } else { r2 = g2 = b2 = 0.0; } /*Try to choose a good target color*/ /*First r*/ t = MAX(r1, r2); b = MIN(r1, r2); if (t < 0.75) target[0] = 1.0; else target[0] = 0.0; /*Now g*/ t = MAX(g1, g2); b = MIN(g1, g2); if (t < 0.75) target[1] = 1.0; else target[1] = 0.0; /*Now b*/ t = MAX(b1, b2); b = MIN(b1, b2); if (b > 0.25) target[2] = 0.0; else target[2] = 1.0; return ClosestUIColor(target); } #ifdef PROTO void SetObjectColor(ObjPtr col) #else void SetObjectColor(col) ObjPtr col; #endif /*If col is an int, sets its ui color. If col is a real 3-array, sets its value */ { #ifdef GRAPHICS if (overDraw) { if (IsInt(col) && GetInt(col) == UIBLACK) { color(OVERCLEAR); } else { color(OVERRED); } } else { if (IsInt(col)) { SetUIColor(GetInt(col)); } else if (IsRealArray(col) && RANK(col) == 1 && DIMS(col)[0] == 3) { float clr[3]; real *elements; elements = ELEMENTS(col); if (drawingMode == DRAW_SCREEN) { clr[0] = elements[0]; clr[1] = elements[1]; clr[2] = elements[2]; RGBC(clr); } else { curRed = elements[0]; curGreen = elements[1]; curBlue = elements[2]; } } else { ReportError("SetObjectColor", "Bad color value"); } } #endif } #define PALDISPLAYBORDER 20 #define PALDISPLAYTEXTWIDTH 0.6 #define PALDISPLAYVCOLORWIDTH 0.3 #define PALDISPLAYVCOLORHEIGHT 0.08 #define PALDISPLAYHCOLORWIDTH 0.12 #define PALDISPLAYHCOLORHEIGHT 0.6 ObjPtr DrawPaletteDisplay(display) ObjPtr display; /*Draws a display*/ { #ifdef GRAPHICS int left, right, bottom, top; int l, r, b, t; int intLeft, intRight, intBottom, intTop; /*Interior dims*/ double halfSpace, ddiff, majorWidth, minorWidth, curValue; int pixel; long temp; int nTics; int k, diff, start; int alignment; Bool drawOverUnder; Bool drawMissing; Bool numbersOnly; Bool drawMinorTics; ObjPtr palette; ObjPtr var; char *textFont; short3 *colors; int beg; int nColors; int textSize; ObjPtr textColor; int minMajorStep; Bool colorByPalette; int boxWidth, boxHeight, stringWidth, stringHeight; real *minmax; Get2DIntBounds(display, &left, &right, &bottom, &top); intLeft = left + PALDISPLAYBORDER; intRight = right - PALDISPLAYBORDER; intBottom = bottom + PALDISPLAYBORDER; intTop = top - PALDISPLAYBORDER; textColor = GetVar(display, COLOR); palette = GetPaletteVar("DrawPaletteDisplay", display, REPOBJ); if (!palette) { return ObjFalse; } MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) { return ObjFalse; } colors = ELEMENTS(var); if (!rgbp) { var = GetIntVar("DrawPaletteDisplay", palette, BEGCOLOR); if (!var) return ObjFalse; beg = GetInt(var); } else { beg = 0; } var = GetIntVar("DrawPaletteDisplay", palette, NCOLORS); if (!var) { return ObjFalse; } nColors = GetInt(var); var = GetFixedArrayVar("DrawPaletteDisplay", palette, MINMAX, 1, 2L); if (!var) { return ObjFalse; } minmax = ELEMENTS(var); /*Get colorByPalette predicate*/ colorByPalette = GetPredicate(display, COLORBYFIELD); /*Get draw portions predicates*/ drawOverUnder = GetPredicate(display, SHOWOVERUNDER); drawMissing = GetPredicate(display, SHOWMISSING); numbersOnly = GetPredicate(display, NUMBERSONLY); drawMinorTics = GetPredicate(display, SHOWMINORTICS); /*Set the color palette*/ SetPalette(palette); /*Draw the background*/ var = GetVar(display, BACKGROUND); if (var) { SetObjectColor(var); FillRect(left, right, bottom, top); } /*Draw the info on the palette itself*/ SetObjectColor(textColor); var = GetIntVar("DrawPaletteDisplay", display, MINMAJORSTEP); if (var) { minMajorStep = GetInt(var); } else { minMajorStep = 30; } var = GetStringVar("DrawPaletteDisplay", display, TEXTFONT); if (var) { textFont = GetString(var); } else { textFont = "Helvetica"; } var = GetIntVar("DrawPaletteDisplay", display, TEXTSIZE); if (var) { textSize = GetInt(var); } else { textSize = 18; } var = GetIntVar("DrawPaletteDisplay", display, ALIGNMENT); if (var) { alignment = GetInt(var); } else { alignment = CENTERALIGN; } SetupFont(textFont, textSize); stringWidth = (intRight - intLeft) * PALDISPLAYTEXTWIDTH; stringHeight = textSize; if (right - left < top - bottom) { /*It's vertical*/ int rangeBot, rangeTop; int x; b = intBottom; t = intTop; boxWidth = (intRight - intLeft) * PALDISPLAYVCOLORWIDTH; boxHeight = (intTop - intBottom) * PALDISPLAYVCOLORHEIGHT; if (drawMissing) { /*Draw the missing data box*/ t = b + boxHeight; if (numbersOnly) { l = intLeft; r = intRight; } else { r = intRight; l = r - boxWidth; FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); if (rgbp) { c3s(colors[0]); } else { color(beg); } FillRect(l + 1, r - 1, b + 1, t - 1); SetObjectColor(textColor); r = intLeft + stringWidth; DrawLine(l, (b + t) / 2, r, (b + t) / 2); DrawLine(l, (b + t) / 2 + 1, r, (b + t) / 2 + 1); l = intLeft; } strcpy(tempStr, "Missing"); switch(alignment) { case LEFTALIGN: x = l; break; case CENTERALIGN: x = (l + r - DSPPALETTESTL) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL; break; } if (colorByPalette) { SetRealColor(missingData); } DrawAString(alignment, x, (b + t - textSize) / 2, tempStr); if (colorByPalette) { SetObjectColor(textColor); } b = t + MINORBORDER; t = intTop; } if (drawOverUnder) { /*Draw the underflow data box*/ t = b + boxHeight; if (numbersOnly) { l = intLeft; r = intRight; } else { r = intRight; l = r - boxWidth; FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); if (rgbp) { c3s(colors[1]); } else { color(beg + 1); } FillRect(l + 1, r - 1, b + 1, t - 1); SetObjectColor(textColor); r = intLeft + stringWidth; DrawLine(l, (b + t) / 2, r, (b + t) / 2); DrawLine(l, (b + t) / 2 + 1, r, (b + t) / 2 + 1); l = intLeft; } strcpy(tempStr, "Under"); switch(alignment) { case LEFTALIGN: x = l; break; case CENTERALIGN: x = (l + r - DSPPALETTESTL) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL; break; } if (colorByPalette) { SetRealColor(MINUSINF); } DrawAString(alignment, x, (b + t - textSize) / 2, tempStr); if (colorByPalette) { SetObjectColor(textColor); } b = t + MINORBORDER; /*Draw the overflow data box*/ t = intTop; if (numbersOnly) { l = intLeft; r = intRight; } else { r = intRight; l = r - boxWidth; FrameRect(l, r, t - boxHeight, t); FrameRect(l - 1, r + 1, t - boxHeight - 1, t + 1); if (rgbp) { c3s(colors[nColors - 1]); } else { color(beg + nColors - 1); } FillRect(l + 1, r - 1, t - boxHeight + 1, t - 1); SetObjectColor(textColor); r = intLeft + stringWidth; DrawLine(l, t - boxHeight / 2, r, t - boxHeight / 2); DrawLine(l, t - boxHeight / 2 + 1, r, t - boxHeight / 2 + 1); l = intLeft; } strcpy(tempStr, "Over"); switch(alignment) { case LEFTALIGN: x = l; break; case CENTERALIGN: x = (l + r - DSPPALETTESTL) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL; break; } if (colorByPalette) { SetRealColor(PLUSINF); } DrawAString(alignment, x, t - boxHeight / 2 - textSize / 2, tempStr); if (colorByPalette) { SetObjectColor(textColor); } t = intTop - boxHeight - MINORBORDER; } /*Draw the main section of the display*/ r = intRight; l = r - boxWidth; if (!numbersOnly) { FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); } /*Do the colors in the center*/ rangeBot = b + 1; rangeTop = t - 1; diff = t - b - 2; if (diff > 0) { b = start = rangeBot; if (!numbersOnly) { for (k = 2; k < nColors - 1; ++k) { t = (k - 1) * diff / (nColors - 3) + start; if (rgbp) { c3s(colors[k]); } else { color(beg + k); } FillRect(l + 1, r - 1, b, t); b = t; } } SetObjectColor(textColor); r = l - 1; l = intLeft + stringWidth; /*Draw all the tics in the middle*/ ddiff = minmax[1] - minmax[0]; halfSpace = (ddiff) / (nColors - 4) * 0.5; CalcGoodSteps(ddiff, rangeTop - rangeBot, minMajorStep, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = minmax[0] / majorWidth; curValue = temp * majorWidth; while (curValue > minmax[0]) { curValue -= majorWidth; } k = 0; while (curValue < minmax[0]) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= minmax[1] + ddiff * 1.0E-6) { pixel = rangeBot + (curValue - minmax[0]) * (rangeTop - rangeBot) / (ddiff); if (k == 0) { /*Major tic*/ if (numbersOnly) { sprintf(tempStr, "%lg", curValue); switch(alignment) { case LEFTALIGN: x = intLeft; break; case CENTERALIGN: x = (intLeft + intRight - DSPPALETTESTL - StrWidth(tempStr)) / 2; break; case RIGHTALIGN: x = intRight - DSPPALETTESTL - StrWidth(tempStr); break; } } else { DrawLine(l, pixel, r, pixel); DrawLine(l, pixel + 1, r, pixel + 1); sprintf(tempStr, "%lg", curValue); switch(alignment) { case LEFTALIGN: x = intLeft; break; case CENTERALIGN: x = (intLeft + l - DSPPALETTESTL) / 2; break; case RIGHTALIGN: x = l - DSPPALETTESTL; break; } } if (colorByPalette) { SetRealColor(curValue); } DrawAString(alignment, x, pixel - textSize / 2, tempStr); if (colorByPalette) { SetObjectColor(textColor); } } else if ((!numbersOnly) && drawMinorTics) { /*Minor tic*/ DrawLine((l + r) / 2, pixel, r, pixel); DrawLine((l + r) / 2, pixel + 1, r, pixel + 1); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } } } else { /*It's horizontal*/ int rangeLeft, rangeRight; int x; minMajorStep *= 3; l = intLeft; r = intRight; boxWidth = (intRight - intLeft) * PALDISPLAYHCOLORWIDTH; boxHeight = (intTop - intBottom) * PALDISPLAYHCOLORHEIGHT; if (drawMissing) { /*Draw the missing data box*/ r = l + boxWidth; if (numbersOnly) { b = intBottom; t = intTop; } else { t = intTop; b = t - boxHeight; FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); if (rgbp) { c3s(colors[0]); } else { color(beg); } FillRect(l + 1, r - 1, b + 1, t - 1); SetObjectColor(textColor); b = intBottom + stringHeight; DrawLine((l + r) / 2, b, (l + r) / 2, t - boxHeight); DrawLine((l + r) / 2 + 1, b, (l + r) / 2 + 1, t - boxHeight); b = intBottom; } strcpy(tempStr, "Missing"); switch(alignment) { case LEFTALIGN: x = (l + r) / 2; break; case CENTERALIGN: x = (l + r) / 2; break; case RIGHTALIGN: x = (l + r) / 2; break; } if (colorByPalette) { SetRealColor(missingData); } DrawAString(alignment, x, b, tempStr); if (colorByPalette) { SetObjectColor(textColor); } l = r + MINORBORDER; r = intRight; } if (drawOverUnder) { /*Draw the underflow data box*/ r = l + boxWidth; if (numbersOnly) { b = intBottom; t = intTop; } else { t = intTop; b = t - boxHeight; FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); if (rgbp) { c3s(colors[1]); } else { color(beg + 1); } FillRect(l + 1, r - 1, b + 1, t - 1); SetObjectColor(textColor); b = intBottom + stringHeight; DrawLine((l + r) / 2, b, (l + r) / 2, t - boxHeight); DrawLine((l + r) / 2 + 1, b, (l + r) / 2 + 1, t - boxHeight); b = intBottom; } strcpy(tempStr, "Under"); switch(alignment) { case LEFTALIGN: x = (l + r) / 2; break; case CENTERALIGN: x = (l + r) / 2; break; case RIGHTALIGN: x = (l + r) / 2; break; } if (colorByPalette) { SetRealColor(MINUSINF); } DrawAString(alignment, x, b, tempStr); if (colorByPalette) { SetObjectColor(textColor); } l = r + MINORBORDER; r = intRight; /*Draw the overflow data box*/ if (numbersOnly) { b = intBottom; t = intTop; } else { t = intTop; b = t - boxHeight; FrameRect(r - boxWidth, r, b, t); FrameRect(r - boxWidth - 1, r + 1, b - 1, t + 1); if (rgbp) { c3s(colors[nColors - 1]); } else { color(beg + nColors - 1); } FillRect(r - boxWidth + 1, r - 1, b + 1, t - 1); SetObjectColor(textColor); b = intBottom + stringHeight; DrawLine((r - boxWidth + r) / 2, b, (r - boxWidth + r) / 2, t - boxHeight); DrawLine((r - boxWidth + r) / 2 + 1, b, (r - boxWidth + r) / 2 + 1, t - boxHeight); b = intBottom; } strcpy(tempStr, "Over"); switch(alignment) { case LEFTALIGN: x = (r - boxWidth + r) / 2; break; case CENTERALIGN: x = (r - boxWidth + r) / 2; break; case RIGHTALIGN: x = (r - boxWidth + r) / 2; break; } if (colorByPalette) { SetRealColor(PLUSINF); } DrawAString(alignment, x, b, tempStr); if (colorByPalette) { SetObjectColor(textColor); } r = intRight - boxWidth - MINORBORDER; } /*Draw the main section of the display*/ t = intTop; b = t - boxHeight; if (!numbersOnly) { FrameRect(l, r, b, t); FrameRect(l - 1, r + 1, b - 1, t + 1); } /*Do the colors in the center*/ rangeLeft = l + 1; rangeRight = r - 1; diff = r - l - 2; if (diff > 0) { l = start = rangeLeft; if (!numbersOnly) { for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; if (rgbp) { c3s(colors[k]); } else { color(beg + k); } FillRect(l, r, b + 1, t - 1); l = r; } } SetObjectColor(textColor); t = b - 1; b = intBottom + stringHeight + 2; /*Draw all the tics in the middle*/ ddiff = minmax[1] - minmax[0]; halfSpace = (ddiff) / (nColors - 4) * 0.5; CalcGoodSteps(ddiff, rangeRight - rangeLeft, minMajorStep, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = minmax[0] / majorWidth; curValue = temp * majorWidth; while (curValue > minmax[0]) { curValue -= majorWidth; } k = 0; while (curValue < minmax[0]) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= minmax[1] + ddiff * 1.0E-6) { pixel = rangeLeft + (curValue - minmax[0]) * (rangeRight - rangeLeft) / (ddiff); if (k == 0) { /*Major tic*/ if (numbersOnly) { sprintf(tempStr, "%lg", curValue); } else { DrawLine(pixel, b, pixel, t); DrawLine(pixel + 1, b, pixel + 1, t); sprintf(tempStr, "%lg", curValue); } if (colorByPalette) { SetRealColor(curValue); } DrawAString(alignment, pixel, intBottom, tempStr); if (colorByPalette) { SetObjectColor(textColor); } } else if ((!numbersOnly) && drawMinorTics) { /*Minor tic*/ DrawLine(pixel, (t + b) / 2, pixel, t); DrawLine(pixel + 1, (t + b) / 2, pixel + 1, t); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } } } if (IsSelected(display)) { int horCent = (left + right)/2; int vertCent = (bottom + top)/2; /* Draw incredibly fancy frame for moving and resizing palette display */ FrameUIWideRect(left+INSET, right-INSET, bottom+INSET, top-INSET, OUTSIDEFRAMEWEIGHT, OUTSIDEFRAMECOLOR); FrameUIWideRect(left+INSET+OUTSIDEFRAMEWEIGHT, right-INSET-OUTSIDEFRAMEWEIGHT, bottom+INSET+OUTSIDEFRAMEWEIGHT, top-INSET-OUTSIDEFRAMEWEIGHT, INSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FrameUIWideRect(left+INSET+OUTSIDEFRAMEWEIGHT+INSIDEFRAMEWEIGHT, right-INSET-OUTSIDEFRAMEWEIGHT-INSIDEFRAMEWEIGHT, bottom+INSET+OUTSIDEFRAMEWEIGHT+INSIDEFRAMEWEIGHT, top-INSET-OUTSIDEFRAMEWEIGHT-INSIDEFRAMEWEIGHT, OUTSIDEFRAMEWEIGHT, OUTSIDEFRAMECOLOR); /* Now draw the handles */ /* center of sides */ FillUIRect(left, left+HANDLESIZE, vertCent-HANDLESIZE/2, vertCent+HANDLESIZE/2, OUTSIDEFRAMECOLOR); FillUIRect(left+OUTSIDEFRAMEWEIGHT, left+HANDLESIZE-OUTSIDEFRAMEWEIGHT, vertCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT, vertCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE, right, vertCent-HANDLESIZE/2, vertCent+HANDLESIZE/2, OUTSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT, right-OUTSIDEFRAMEWEIGHT, vertCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT, vertCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); /* top edge */ FillUIRect(horCent-HANDLESIZE/2, horCent+HANDLESIZE/2, top-HANDLESIZE, top, OUTSIDEFRAMECOLOR); FillUIRect(horCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT, horCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, top-HANDLESIZE+OUTSIDEFRAMEWEIGHT, top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FillUIRect(left, left+HANDLESIZE, top-HANDLESIZE, top, OUTSIDEFRAMECOLOR); FillUIRect(left+OUTSIDEFRAMEWEIGHT, left+HANDLESIZE-OUTSIDEFRAMEWEIGHT, top-HANDLESIZE+OUTSIDEFRAMEWEIGHT, top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE, right, top-HANDLESIZE, top, OUTSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT, right-OUTSIDEFRAMEWEIGHT, top-HANDLESIZE+OUTSIDEFRAMEWEIGHT, top-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); /* bottom edge */ FillUIRect(horCent-HANDLESIZE/2, horCent+HANDLESIZE/2, bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR); FillUIRect(horCent-HANDLESIZE/2+OUTSIDEFRAMEWEIGHT, horCent+HANDLESIZE/2-OUTSIDEFRAMEWEIGHT, bottom+OUTSIDEFRAMEWEIGHT, bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FillUIRect(left, left+HANDLESIZE, bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR); FillUIRect(left+OUTSIDEFRAMEWEIGHT, left+HANDLESIZE-OUTSIDEFRAMEWEIGHT, bottom+OUTSIDEFRAMEWEIGHT, bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE, right, bottom, bottom+HANDLESIZE, OUTSIDEFRAMECOLOR); FillUIRect(right-HANDLESIZE+OUTSIDEFRAMEWEIGHT, right-OUTSIDEFRAMEWEIGHT, bottom+OUTSIDEFRAMEWEIGHT, bottom+HANDLESIZE-OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR); } #endif return ObjTrue; } ObjPtr SelectPaletteDisplay(object, selectp) ObjPtr object; Bool selectp; /*Selects an icon*/ { if (selectp) { MakeMeCurrent(object); } ImInvalid(object); return ObjTrue; } #define PDPICKSLOP 10 static ObjPtr PressPaletteDisplay(display, mouseX, mouseY, flags) ObjPtr display; int mouseX, mouseY; long flags; { #ifdef INTERACTIVE int left, right, bottom, top, hCent, vCent; Bool ml, mr, mb, mt; int mX, mY; ObjPtr var, palette; Get2DIntBounds(display, &left, &right, &bottom, &top); /* return if mouse outside text box */ if (mouseX < left || mouseX > right || mouseY < bottom || mouseY > top) return ObjFalse; if (TOOL(flags) == T_HELP) /* help mode? */ { ContextHelp(display); return ObjTrue; } MakeMeCurrent(display); hCent = (left + right)/2; vCent = (bottom + top)/2; ml = mr = mb = mt = false; if (mouseX < left + HANDLESIZE) /* on left side */ { if (mouseY > top - HANDLESIZE) /* top-left handle */ mt = ml = true; else if (mouseY < bottom + HANDLESIZE) /* bottom-left handle */ mb = ml = true; else if (mouseY > vCent - HANDLESIZE/2 && mouseY < vCent + HANDLESIZE/2) ml = true; /* bottom middle handle */ else ml = mr = mb = mt = true; /* in frame */ } else if (mouseX > right - HANDLESIZE) /* on right side */ { if (mouseY > top - HANDLESIZE) /* top-right handle */ mt = mr = true; else if (mouseY < bottom + HANDLESIZE) /* bottom-right handle */ mb = mr = true; else if (mouseY > vCent - HANDLESIZE/2 && mouseY < vCent + HANDLESIZE/2) mr = true; else ml = mr = mb = mt = true; /* in frame */ } else if (mouseY < bottom + HANDLESIZE) /* on bottom */ { /* already handled (heh heh) corners */ if (mouseX > hCent - HANDLESIZE/2 && mouseX < hCent + HANDLESIZE/2) mb = true; /* bottom middle handle */ else ml = mr = mb = mt = true; /* in frame */ } else if (mouseY > top - HANDLESIZE) /* on top */ { /* already handled (heh heh) corners */ if (mouseX > hCent - HANDLESIZE/2 && mouseX < hCent + HANDLESIZE/2) mt = true; /* middle top handle */ else ml = mr = mb = mt = true; /* in frame */ } { if (!(flags & F_EXTEND) && !IsSelected(display)) { /*It's a new selection and not already selected. Deselect the rest*/ DeselectAll(); } if ((flags & F_EXTEND) && IsSelected(display)) { /*Deselect*/ Select(display, false); return ObjTrue; } else if (!IsSelected(display)) { /*Must select it*/ Select(display, true); DrawMe(display); UpdateDrawing(); } } if (mr || ml || mb || mt) /* drag the incredibly fancy frame around */ { /* I am greatly indebted to my friend and colleague, Eric Pepke, for the following code. Any errors or obfuscations are his. */ /*Oh yeah? Well, I stole it back! So now the bugs are yours!*/ int initX = mouseX, initY = mouseY; int newLeft, newRight, newBottom, newTop; int oldNewLeft, oldNewRight, oldNewBottom, oldNewTop; SaveForUndo(display); newLeft = oldNewLeft = left; newRight = oldNewRight = right; newBottom = oldNewBottom = bottom; newTop = oldNewTop = top; while (Mouse(&mX, &mY)) { if (ml) newLeft = left + mX - initX; if (mr) newRight = right + mX - initX; if (mb) newBottom = bottom + mY - initY; if (mt) newTop = top + mY - initY; if (flags & F_SHIFTDOWN) { /*Grid drag*/ if (ml && mr && mb && mt) { /*Special case--whole object gridded Only grid top left*/ int width, height; width = newRight - newLeft; height = newTop - newBottom; newLeft = GRIDX(newLeft); newRight = newLeft + width; newTop = top - (GRIDY(top - newTop)); newBottom = newTop - height; } else { /*Normal case*/ if (ml) newLeft = GRIDX(newLeft); if (mr) newRight = right - GRIDX(right - newRight); if (mb) newBottom = GRIDY(newBottom); if (mt) newTop = top - GRIDY(top - newTop); } } if (ml && newLeft + 3 * HANDLESIZE > newRight) newLeft = newRight - 3 * HANDLESIZE; if (mr && newLeft + 3 * HANDLESIZE > newRight) newRight = newLeft + 3 * HANDLESIZE; if (mb && newBottom + 3 * HANDLESIZE > newTop) newBottom = newTop - 3 * HANDLESIZE; if (mt && newBottom + 3 * HANDLESIZE > newTop) newTop = newBottom + 3 * HANDLESIZE; if ((newLeft != oldNewLeft || newRight != oldNewRight || newBottom != oldNewBottom || newTop != oldNewTop) && newLeft < newRight && newBottom < newTop) { Set2DIntBounds(display, newLeft, newRight, newBottom, newTop); oldNewLeft = newLeft; oldNewRight = newRight; oldNewBottom = newBottom; oldNewTop = newTop; DrawMe(display); } } if (logging) { char cmd[256]; MakeObjectName(tempStr, display); sprintf(cmd, "set bounds %s [%d %d %d %d]\n", tempStr, newLeft, newRight, newBottom, newTop); Log(cmd); } } return ObjTrue; #else return ObjFalse; #endif } #ifdef PROTO ObjPtr NewPaletteDisplay(int left, int right, int bottom, int top, char *name, ObjPtr palette) #else ObjPtr NewPaletteDisplay(left, right, bottom, top, name, palette) int left, right, bottom, top; char *name; ObjPtr palette; #endif /*Makes a new palette display*/ { ObjPtr retVal; retVal = NewObject(paletteDisplayClass, 0); if (!retVal) { return NULLOBJ; } Set2DIntBounds(retVal, left, right, bottom, top); SetVar(retVal, NAME, NewString(name)); SetVar(retVal, REPOBJ, palette); return retVal; } ObjPtr CompleteSavePalette(palette, whichButton) ObjPtr palette; int whichButton; /*Completes a "save palette" operation*/ { SaveObjectControls(palette, GetVar(palette, DIRECTORY)); return ObjTrue; } ObjPtr SavePalette(palette) ObjPtr palette; /*Asks for a palette to be saved*/ { ObjPtr name, directory; char *s, nameStr[401]; name = GetStringVar("SavePalette", palette, NAME); if (!name) { return ObjFalse; } strcpy(nameStr, GetString(name)); s = nameStr; while (*s) ++s; while (*s != ' ') --s; *s = 0; directory = GetVar(palette, DIRECTORY); if (directory) { sprintf(tempStr, "Save this palette for datasets named %s in directory %s?", nameStr, GetString(directory)); } else { sprintf(tempStr, "Save this palette for datasets named %s in the current directory?", nameStr); } AlertUser(UICAUTIONALERT, (WinInfoPtr) palette, tempStr, CompleteSavePalette, 2, "Save", "Cancel"); return ObjTrue; } ObjPtr SavePaletteControls(palette) ObjPtr palette; /*Saves a palette by logging all palette controls*/ { int k; ObjPtr var; real *minmax; int nColors; short3 *colors; var = GetFixedArrayVar("SavePaletteControls", palette, MINMAX, 1, 2L); if (!var) { return ObjFalse; } minmax = ELEMENTS(var); var = GetIntVar("SavePaletteControls", palette, NCOLORS); if (!var) { return ObjFalse; } nColors = GetInt(var); sprintf(tempStr, "set value Field\\ Max \"%g\"\n", minmax[1]); Log(tempStr); sprintf(tempStr, "set value Field\\ Min \"%g\"\n", minmax[0]); Log(tempStr); sprintf(tempStr, "set value N\\ Colors \"%d\"\n", nColors); Log(tempStr); MakeVar(palette, COLORS); var = GetVar(palette, COLORS); if (!var) { return ObjFalse; } colors = ELEMENTS(var); for (k = 0; k < nColors; ++k) { sprintf(tempStr, "set color Palette\\ Colors %d %d %d %d\n", k, colors[k][0], colors[k][1], colors[k][2]); Log(tempStr); } return ObjTrue; } static ObjPtr MakeColorBarAppearance(colorBar) ObjPtr colorBar; /*Makes an object's appearance*/ { ImInvalid(colorBar); SetVar(colorBar, APPEARANCE, ObjTrue); return ObjTrue; } static ObjPtr MakePaletteColors(palette) ObjPtr palette; /*Makes a palette's colors. May have to resample if the number of colors has changed.*/ { ObjPtr colors, newColors; ObjPtr var; long nColors; colors = GetVar(palette, COLORS); if (!colors) { return ObjFalse; } MakeVar(palette, NCOLORS); var = GetIntVar("MakePaletteColors", palette, NCOLORS); if (!var) { return ObjFalse; } nColors = GetInt(var); if (nColors != DIMS(colors)[0]) { /*Need to resample*/ SetPaletteNColors(palette, nColors); } else { SetVar(palette, COLORS, GetVar(palette, COLORS)); } return ObjTrue; } static ObjPtr MakePaletteChanged(palette) ObjPtr palette; /*Makes a palette changed*/ { SetVar(palette, CHANGED, ObjTrue); return ObjTrue; } void InitColors() /*Initialize the color system*/ { int k; int colorBeg, colorEnd; ObjPtr var; ObjPtr list; iconColorPalette = NewIcon(0, 0, ICONCTABLE, "Color Palette"); AddToReferenceList(iconColorPalette); /*Make a color palette class*/ paletteClass = NewObject(NULLOBJ, sizeof(Palette) - sizeof(Thing)); AddToReferenceList(paletteClass); SETOBJTYPE(paletteClass -> flags, PALETTE); SetVar(paletteClass, COLORCOMP, NULLOBJ); SetVar(paletteClass, BEGCOLOR, NULLOBJ); SetVar(paletteClass, NCOLORS, NewInt(0)); SetVar(paletteClass, DEFAULTICON, iconColorPalette); SetVar(paletteClass, COLORMODEL, NewInt(CM_RGB)); SetMethod(paletteClass, EDITPALETTE, NewControlWindow); SetVar(paletteClass, DOUBLECLICK, NewString(OF_SHOW_CONTROLS)); SetMethod(paletteClass, NAME, MakePaletteName); SetMethod(paletteClass, CLONE, ClonePalette); SetMethod(paletteClass, CLEANUP, CleanupPalette); SetMethod(paletteClass, NEWCTLWINDOW, ShowPaletteControls); SetMethod(paletteClass, SHOWCONTROLS, NewControlWindow); SetVar(paletteClass, SAVEEXTENSION, NewString("pal")); SetMethod(paletteClass, SAVECPANEL, SavePalette); SetMethod(paletteClass, SAVEALLCONTROLS, SavePaletteControls); SetMethod(paletteClass, LOCALCOPY, MakeLocalCopy); DeclareDependency(paletteClass, CHANGED, COLORS); DeclareDependency(paletteClass, CHANGED, MINMAX); SetMethod(paletteClass, CHANGED, MakePaletteChanged); DeclareDependency(paletteClass, COLORS, NCOLORS); SetMethod(paletteClass, COLORS, MakePaletteColors); var = NewRealArray(1, 2L); ((real *) ELEMENTS(var))[0] = 0.0; ((real *) ELEMENTS(var))[1] = 1.0; SetVar(paletteClass, MINMAX, var); #ifdef GRAPHICS /*If there is a cmap mode, figure out the number of colors*/ if (hasCmap) { char *nColorsString; char *colorBegString; colorEnd = 1; for (k = 0; k < cmapBitPlanes; ++k) { colorEnd *= 2; } /*Trim off the top 512 if it's too big for the GTX version*/ if (colorEnd >= 4096) { colorEnd -= 512; } /*Determine beginning based on end*/ if (colorEnd <= 512) { colorBeg = COLORBEG8BITS; } else { colorBeg = COLORBEGMOREBITS; } if (colorBegString = getenv("SCIAN_COLOR_BEG")) { int temp; if (1 == sscanf(colorBegString, "%d", &temp)) { colorBeg = temp; if (showConfig) fprintf(stderr, "Color beginning overridden to %d\n", temp); } else { fprintf(stderr, "Bad color beginning: %s\n", colorBegString); } } if (nColorsString = getenv("SCIAN_N_COLORS")) { int nColors; if (1 == sscanf(nColorsString, "%d", &nColors)) { colorEnd = colorBeg + nColors; if (showConfig) printf("Number of colors overridden to be %d\n", nColors); } else { fprintf(stderr, "Bad value for environment variable SCIAN_NCOLORS: %s\n", nColorsString); } } if (showConfig) { printf("Visualization colors from %d to %d\n", colorBeg, colorEnd); } curUIColorIndex = colorBeg; #ifdef RELEASE nScavengeColors = colorBeg; #else nScavengeColors = 256; #endif } if (hasCmap && scavengeColors) { Colorindex i; nScavengeColors = colorBeg; colorsToScavenge = (short3 *) Alloc(nScavengeColors * sizeof(short3)); if (!colorsToScavenge) { nScavengeColors = 0; } /*Load up the scavenged colors*/ for (i = 0; i < nScavengeColors; ++i) { getmcolor(i, &(colorsToScavenge[i][0]), &(colorsToScavenge[i][1]), &(colorsToScavenge[i][2])); } } else { nScavengeColors = 0; colorsToScavenge = 0; } /*Initialize user interface colors*/ MakeUIColor(UIBLACK, 0, 0, 0); MakeUIColor(UIGRAY12, 30, 30, 30); MakeUIColor(UIGRAY25, 61, 61, 61); MakeUIColor(UIGRAY37, 95, 95, 95); MakeUIColor(UIGRAY50, 128, 128, 128); MakeUIColor(UIGRAY62, 163, 163, 163); MakeUIColor(UIGRAY75, 193, 193, 193); MakeUIColor(UIGRAY87, 224, 224, 224); MakeUIColor(UIWHITE, 255, 255, 255); MakeUIColor(UIRED, 225, 0, 0); MakeUIColor(UIGREEN, 0, 225, 0); MakeUIColor(UIBLUE, 0, 0, 225); MakeUIColor(UIMAGENTA, 225, 0, 225); MakeUIColor(UIYELLOW, 245, 245, 0); MakeUIColor(UICYAN, 0, 225, 225); MakeUIColor(UIGOLD, 247, 188, 0); MakeUIColor(UIPRED, 182, 128, 128); MakeUIColor(UIPGREEN, 128, 171, 128); MakeUIColor(UIPBLUE, 128, 145, 171); MakeUIColor(UIPMAGENTA, 171, 128, 171); MakeUIColor(UIPYELLOW, 171, 171, 128); MakeUIColor(UIPCYAN, 128, 171, 171); if (colorsToScavenge) { Free(colorsToScavenge); colorsToScavenge = 0; } /*Now colorBeg set to be above NUICOLORS*/ if (hasCmap) { colorBeg = curUIColorIndex; /*Make first color range*/ colorRanges = newp(ColorRange); colorRanges -> beg = colorBeg; colorRanges -> end = colorEnd; colorRanges -> next = (ColorRange *) 0; } else { colorRanges = 0; } #endif colorControlClass = NewObject(controlClass, 0); AddToReferenceList(colorControlClass); colorWheelClass = NewObject(colorControlClass, 0); AddToReferenceList(colorWheelClass); #ifdef GRAPHICS SetMethod(colorWheelClass, DRAW, DrawColorWheel); #endif #ifdef INTERACTIVE SetMethod(colorWheelClass, PRESS, PressColorWheel); #endif SetMethod(colorWheelClass, SETVAL, SetColorWheelVal); SetVar(colorWheelClass, TYPESTRING, NewString("color wheel")); SetVar(colorWheelClass, HELPSTRING, NewString("To select a color, click at the color you desire. \ Colors around the edge of the circle are fully saturated; colors near the center are \ less saturated. Hold down the Shift key while pressing to \ constrain to full or half saturation. Double-click to snap to the closest full- or half-saturated \ color or white.")); /*Create a color bar class*/ colorBarClass = NewObject(controlClass, 0); AddToReferenceList(colorBarClass); #ifdef GRAPHICS SetMethod(colorBarClass, DRAW, DrawColorBar); #endif #ifdef INTERACTIVE SetMethod(colorBarClass, PRESS, PressColorBar); #endif SetVar(colorBarClass, OPAQUE, ObjTrue); SetMethod(colorBarClass, SETVAL, SetColorBarVal); DeclareIndirectDependency(colorBarClass, APPEARANCE, REPOBJ, COLORS); DeclareIndirectDependency(colorBarClass, APPEARANCE, REPOBJ, MINMAX); SetMethod(colorBarClass, APPEARANCE, MakeColorBarAppearance); /*Create a palette display class*/ paletteDisplayClass = NewObject(controlClass, 0); AddToReferenceList(paletteDisplayClass); SetVar(paletteDisplayClass, SHOWMINORTICS, ObjTrue); #ifdef GRAPHICS SetMethod(paletteDisplayClass, DRAW, DrawPaletteDisplay); #endif #ifdef INTERACTIVE SetMethod(paletteDisplayClass, PRESS, PressPaletteDisplay); #endif SetMethod(paletteDisplayClass, NEWCTLWINDOW, ShowPaletteDisplayControls); SetMethod(paletteDisplayClass, SHOWCONTROLS, NewControlWindow); /*Make list of snapshot variables*/ list = NewList(); PrefixList(list, NewSymbol(BOUNDS)); PrefixList(list, NewSymbol(TEXTFONT)); PrefixList(list, NewSymbol(TEXTSIZE)); PrefixList(list, NewSymbol(ALIGNMENT)); SetVar(paletteDisplayClass, SNAPVARS, list); var = NewRealArray(1, 3L); ((real *) ELEMENTS(var))[0] = 1.0; ((real *) ELEMENTS(var))[1] = 1.0; ((real *) ELEMENTS(var))[2] = 1.0; SetVar(paletteDisplayClass, COLOR, var); SetTextFont(paletteDisplayClass, DSPPALETTEFONT); SetTextSize(paletteDisplayClass, DSPPALETTESIZE); SetMethod(paletteDisplayClass, SELECT, SelectPaletteDisplay); SetTextAlign(paletteDisplayClass, RIGHTALIGN); SetVar(paletteDisplayClass, TICDENSITY, NewReal(10.0)); SetVar(paletteDisplayClass, MINMAJORSTEP, NewInt(30)); } void KillColors() { DeleteThing(paletteDisplayClass); DeleteThing(colorBarClass); DeleteThing(colorWheelClass); DeleteThing(colorControlClass); DeleteThing(paletteClass); DeleteThing(iconColorPalette); }