/*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" #define INDIGOCOLORS #ifdef GRAPHICS #ifndef GL4D #include "gamtables.h" #endif #ifdef GL4D /*No gamma correction on the 4d*/ #define CVAL(k) k #else /*3000's need gammacorrection*/ #define CVAL(k) LinToGamma[k] #endif #endif int overDraw = 0; /*Counter for overlay drawing*/ Bool showConfig; /*True iff want to show configuration*/ short curRed, curGreen, curBlue; /*Current color components in other than screen draw mode*/ ObjPtr iconColorPalette; /*Simple palette functions*/ #define PF_RAMP 1 /*Interpolate a ramp*/ #define PF_REVERSE 2 /*Reverse range of colors*/ #define PF_RUFFLE 3 /*Ruffle range of colors*/ #define PF_SMOOTH 4 /*Smooth range of colors*/ #define PF_SHARPEN 5 /*Sharpen range of colors*/ /*Color models*/ #define CM_RGB 0 /*RGB color model*/ #define CM_YIQ 1 #define CM_HSV 2 #define CM_HLS 3 #define NCOLORMODELS 4 /*Palette tools*/ #define PT_FREEFORM 0 /*Free form drawing*/ #define PT_SINE 1 /*Sine function*/ #define PT_TRIANGLE 2 /*Triangle function*/ #define PT_SAWTOOTH 3 /*Sawtooth function*/ #define PT_TOOTHSAW 4 /*Toothsaw function*/ #define PT_SQUARE 5 /*Square wave function*/ char *toolNames[6] = { "free form", "sine wave", "triangle wave", "sawtooth wave", "reverse sawtooth wave", "square wave" }; char *componentNames[NCOLORMODELS][3] = { {"red", "green", "blue"}, {"\"Y\"", "\"I\"", "\"Q\""}, {"hue", "saturation", "value"}, {"hue", "lightness", "saturation"} }; char *shortComponentNames[NCOLORMODELS][3] = { {"R", "G", "B"}, {"Y", "I", "Q"}, {"H", "S", "V"}, {"H", "L", "S"} }; real RGB2YIQMat[3][3] = {{ 0.30, 0.59, 0.11}, { 0.60, -0.28, -0.32}, { 0.21, -0.52, 0.31}}; real YIQ2RGBMat[3][3] = {{ 1.0000, 0.9483, 0.6240}, { 1.0000, -0.2761, -0.6398}, { 1.0000, -1.1055, 1.7299}}; Bool hasRGB; /*True iff has RGB*/ Bool hasCmap; /*True iff has color map mode*/ Bool hasDouble; /*True iff has double buffer mode*/ Bool hasZbuf; /*True iff has z buffer mode*/ Bool hasTransparency; /*True iff has transparency*/ Bool hasTwoSided; /*True iff has two-sided hardware lighting*/ 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*/ int topTestColor = 0; /*Top color to test for*/ short uiColors[NUICOLORS][3]; /*Components for the UI colors*/ int uiColorIndex[NUICOLORS]; /*Indices for ui colors*/ PPtr curPalette; /*Current palette*/ int curNColors; /*Current number of colors*/ real curMin, curMax; /*Current min and max values*/ int curBeg; real diffMult; /*Amount to multiply to get difference*/ short3 *curColors; ObjPtr paletteClass; /*Class for a color palette*/ ObjPtr paletteDisplayClass; /*Class for a palette display*/ ObjPtr colorControlClass; ObjPtr colorWheelClass; ObjPtr colorBarClass; #define COLORFAILTIMEOUT 60 /*Color failure timeout in seconds*/ long colorFailTime = 0; /*Time of last color failure*/ #define COLORWHEELHEIGHT 4 /*Height of a color wheel*/ #ifdef PROTO static void SetColorComponent(PPtr palette, int whichColor, int comp, int cc); static int GetColorComponent(PPtr palette, int whichColor, int comp); #endif #ifdef PROTO void OverDraw(Bool whether) #else void OverDraw(whether) Bool whether; #endif /*Sets system into overlay drawing mode, or not*/ { #ifdef GRAPHICS if (whether) { if (!overDraw++) { pushattributes(); drawmode(OVERDRAW); overlay(2); mapcolor(0, 0, 0, 0); mapcolor(1, 255, 0, 0); mapcolor(2, 255, 0, 0); gconfig(); color(1); } } else { if (!--overDraw) { color(0); clear(); drawmode(NORMALDRAW); popattributes(); gconfig(); } } #endif } #ifdef PROTO void MapPalette(ObjPtr p) #else void MapPalette(p) ObjPtr p; #endif /*Maps palette p*/ { #ifdef GRAPHICS int k; if (hasCmap == false) return; if (((PPtr) p) -> beg < 0) return; for (k = 0; k < ((PPtr) p) -> nColors; ++k) { mapcolor(((PPtr) p) -> beg + k, ((PPtr) p) -> colors[k][0], ((PPtr) p) -> colors[k][1], ((PPtr) p) -> colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void MapPaletteColors(PPtr p, int start, int end) #else void MapPaletteColors(p, start, end) PPtr p; int start; int end; #endif /*Maps color from start to end in palette p*/ { #ifdef GRAPHICS int k; if (hasCmap == false) return; if (((PPtr) p) -> beg < 0) return; for (k = start; k < MAX(((PPtr) p) -> nColors, end + 1); ++k) { mapcolor(((PPtr) p) -> beg + k, ((PPtr) p) -> colors[k][0], ((PPtr) p) -> colors[k][1], ((PPtr) p) -> colors[k][2]); TinyDelay(); } #endif } #ifdef PROTO void CopyColorsToComponents(PPtr p, int start, int finish) #else void CopyColorsToComponents(p, start, finish) PPtr p; int start; int finish; #endif /*Copies the colors to components based on color model*/ { ObjPtr var; int cm, k; short3 *colors, *components; real r, g, b, h, s, v, l, y, i, q; var = GetIntVar("CopyColorsToComponents", (ObjPtr) p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } colors = p -> colors; components = p -> components; for (k = start; k <= finish; ++k) { switch (cm) { case CM_RGB: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; case CM_HSV: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2HSV(&h, &s, &v, r, g, b); components[k][0] = h * 255.0 + 0.5; components[k][1] = s * 255.0 + 0.5; components[k][2] = v * 255.0 + 0.5; break; case CM_HLS: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2HLS(&h, &l, &s, r, g, b); components[k][0] = h * 255.0 + 0.5; components[k][1] = l * 255.0 + 0.5; components[k][2] = s * 255.0 + 0.5; break; case CM_YIQ: r = ((real) colors[k][0]) / 255.0; g = ((real) colors[k][1]) / 255.0; b = ((real) colors[k][2]) / 255.0; RGB2YIQ(&y, &i, &q, r, g, b); components[k][0] = y * 255.0 + 0.5; components[k][1] = i * 255.0 + 0.5; components[k][2] = q * 255.0 + 0.5; break; default: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; } } } #ifdef PROTO void CopyComponentsToColors(PPtr p, int start, int finish) #else void CopyComponentsToColors(p, start, finish) PPtr p; int start; int finish; #endif /*Copies the colors to components based on color model*/ { ObjPtr var; int cm, k; short3 *colors, *components; real r, g, b, h, s, v, l, y, i, q; var = GetIntVar("CopyComponentsToColors", (ObjPtr) p, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } colors = p -> colors; components = p -> components; for (k = start; k <= finish; ++k) { switch (cm) { case CM_RGB: colors[k][0] = components[k][0]; colors[k][1] = components[k][1]; colors[k][2] = components[k][2]; break; case CM_HSV: h = ((real) components[k][0]) / 255.0; s = ((real) components[k][1]) / 255.0; v = ((real) components[k][2]) / 255.0; HSV2RGB(&r, &g, &b, h, s, v); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; case CM_HLS: h = ((real) components[k][0]) / 255.0; l = ((real) components[k][1]) / 255.0; s = ((real) components[k][2]) / 255.0; HLS2RGB(&r, &g, &b, h, l, s); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; case CM_YIQ: y = ((real) components[k][0]) / 255.0; i = ((real) components[k][1]) / 255.0; q = ((real) components[k][2]) / 255.0; YIQ2RGB(&r, &g, &b, y, i, q); colors[k][0] = r * 255.0 + 0.5; colors[k][1] = g * 255.0 + 0.5; colors[k][2] = b * 255.0 + 0.5; break; default: components[k][0] = colors[k][0]; components[k][1] = colors[k][1]; components[k][2] = colors[k][2]; break; } } } void CopyColorsToPalette(p, colors) ObjPtr p; short3 *colors; /*Copies the colors into palette p*/ { int k; for (k = 0; k < ((PPtr) p) -> nColors; ++k) { ((PPtr) p) -> colors[k][0] = colors[k][0]; ((PPtr) p) -> colors[k][1] = colors[k][1]; ((PPtr) p) -> colors[k][2] = colors[k][2]; } CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); } void FieldPaletteName(palette, field) ObjPtr palette, field; /*Names a palette based on a field*/ { ObjPtr name; MakeVar(field, NAME); name = GetStringVar("FieldPaletteName", field, NAME); if (!name) { return; } strcpy(tempStr, GetString(name)); strcat(tempStr, " Palette"); SetVar(palette, NAME, NewString(tempStr)); } ObjPtr MakePaletteName(palette) ObjPtr palette; /*Makes a name for a palette*/ { if (GetVar(palette, NAME)) { return ObjFalse; } else { sprintf(tempStr, "Palette %ld", ++paletteSerialNum); SetVar(palette, NAME, NewString(tempStr)); return ObjTrue; } } void AlertColorFailure() /*Alerts the user that a color allocation has failed*/ { WinInfoPtr errWindow; errWindow = AlertUser(UICAUTIONALERT, (WinInfoPtr) 0, "SciAn has run out of color table entries. It will continue to try to find enough \ colors to run normally. Until it does, you may see some unusual colors in \ some windows.", 0, 0, "Oh well"); SetVar((ObjPtr) errWindow, HELPSTRING, NewString("All the windows of SciAn, as well as the windows of other \ processes, share the same color table. When there are several visualizations \ on the screen, SciAn must share the color table between windows. It tries to \ allocate and deallocate chunks of the color table according to need, but \ sometimes the number of visualizations grows so large that there are simply not \ enough colors to go around.\n\ \n\ SciAn will continue to try to allocate colors. You can reduce the number of \ colors you are using by a number of ways. If your computer can do 24-bit RGB, \ you can set some of the visualization windows to Full Color by clicking on the \ Full Color button at the bottom right of the visualization window. You can close \ visualization windows that you are not using. You can color some of the \ visualizations white or increase visualizations colored by datasets to full \ brightness.")); } void SetPalette(p) ObjPtr p; /*Sets the current palette to p*/ { PPtr tp; tp = (PPtr) p; curPalette = tp; curNColors = tp -> nColors; curMin = tp -> min; curMax = tp -> max; #ifdef GRAPHICS if ((tp -> beg < 0) && (false == rgbp)) { /*Allocate some colors on demand*/ tp -> beg = AllocColors(curNColors); if (tp -> beg >= 0) { /*Allocation succeeded*/ MapPalette(p); curBeg = tp -> beg + 2; } else { /*Allocation failed*/ struct tms buffer; long curTime; curTime = times(&buffer) / HEARTBEAT; if (curTime > colorFailTime + COLORFAILTIMEOUT) { colorFailTime = curTime; DoUniqueTask(AlertColorFailure); } curNColors = uiColorIndex[UIWHITE] - uiColorIndex[UIBLACK]; curBeg = uiColorIndex[UIBLACK]; } } else #endif { curBeg = tp -> beg + 2; } curColors = tp -> colors + 2; diffMult = ((real) curNColors - 4) / (curMax - curMin); } #ifdef PROTO void SetPaletteMinMax(ObjPtr p, real min, real max) #else void SetPaletteMinMax(p, min, max) ObjPtr p; real min, max; #endif /*Sets the min and max of palette p to min and max*/ { ((PPtr) p) -> min = min; ((PPtr) p) -> max = max; SetVar(p, CHANGED, ObjTrue); } static void CompactColors() /*Compacts all the colors*/ { ColorRange *runner; if (colorRanges == 0) { ReportError("CompactColors", "No color ranges"); return; } runner = colorRanges; while (runner && runner -> next) { if (runner -> end >= runner -> next -> beg) { /*Compact two adjacent colors*/ ColorRange *next; runner -> end = runner -> next -> end; next = runner -> next -> next; free(runner -> next); runner -> next = next; } else { runner = runner -> next; } } } static int AllocColors(n) int n; /*Allocates n contiguous colors, returns their start or -1*/ { ColorRange **runner, **bestFit; int fit; /*Fit of best fit so far*/ if (colorRanges == 0) { ReportError("AllocColors", "No color ranges"); return -1; } /*Compact the colors*/ CompactColors(); /*Search for best fit*/ fit = 32767; bestFit = (ColorRange **) 0; runner = &colorRanges; while (*runner) { int nAvailable; nAvailable = (*runner) -> end - (*runner) -> beg; if (nAvailable >= n) { if (nAvailable - n < fit) { fit = nAvailable - n; bestFit = runner; } } runner = &((*runner) -> next); } if (bestFit) { int retVal; retVal = (*bestFit) -> beg; if (fit == 0) { /*Must delete this fit*/ ColorRange *thisFit; thisFit = (*bestFit); free(thisFit); (*bestFit) = (*bestFit) -> next; } else { /*Just need to adjust it*/ (*bestFit) -> beg += n; } return retVal; } else { /*Allocation failed*/ return -1; } } static void FreeColors(start, n) int start, n; /*Frees n contiguous colors at start*/ { ColorRange **runner, *next; if (colorRanges == 0) { ReportError("FreeColors", "No color ranges"); return; } /*Add a new color range at the appropriate point*/ runner = &colorRanges; while (*runner && (*runner) -> beg < start + n) { runner = &((*runner) -> next); } next = *runner; *runner = new(ColorRange); (*runner) -> beg = start; (*runner) -> end = start + n; (*runner) -> next = next; } static void MakeUIColor(whichColor, r, g, b) int whichColor; short r, g, b; /*Makes UI color whichColor to r, g, b*/ { #ifdef GRAPHICS r = CVAL(r); g = CVAL(g); b = CVAL(b); #ifdef SCAVENGECOLORS /*Search the existing colors for the best match.*/ { short bestR, bestG, bestB; Colorindex bestC; short testR, testG, testB; Colorindex testC; int bestDist = MAXCDIST + 1; int testDist; for (testC = 0; testC < topTestColor; ++testC) { getmcolor(testC, &testR, &testG, &testB); 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 for a 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; } #endif 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 uiColorIndex[best]; } static ObjPtr DrawColorWheel(object) ObjPtr object; /*Draws an HS control*/ { #ifdef GRAPHICS int left, right, bottom, top; int cx, cy; int width, height, radius; ObjPtr backColor; /*Color of the background*/ FuncTyp drawContents; /*Routine to draw the contents*/ ObjPtr valueArray; real value[2]; Get2DIntBounds(object, &left, &right, &bottom, &top); /*Draw the control frame*/ DrawRaisedRect(left, right, bottom, top, UIGRAY50); /*Draw the color background*/ cx = (left + right) / 2; cy = (bottom + top) / 2; width = right - left; height = top - bottom; if (width > height) { radius = height / 2 - COLORWHEELBORDER; } else { radius = width / 2 - COLORWHEELBORDER; } /*Draw the color wedges*/ FillUIWedge(cx, cy, radius, -30, 30, UIRED); FillUIWedge(cx, cy, radius, 30, 90, UIYELLOW); FillUIWedge(cx, cy, radius, 90, 150, UIGREEN); FillUIWedge(cx, cy, radius, 150, 210, UICYAN); FillUIWedge(cx, cy, radius, 210, 270, UIBLUE); FillUIWedge(cx, cy, radius, 270, 330, UIMAGENTA); FillUIGauzeDisc(cx, cy, (int) radius * 2 / 3, UIWHITE); FillUIDisc(cx, cy, (int) radius / 3, UIWHITE); /*Draw the spot*/ valueArray = GetVar(object, VALUE); if (valueArray) { Array2CArray(value, valueArray); SetUIColor(UIBLACK); cx += radius * value[1] * cos(2.0 * M_PI * value[0]); cy += radius * value[1] * sin(2.0 * M_PI * value[0]); DrawUILine(cx - COLORWHEELSPOTSIZE, cy, cx + COLORWHEELSPOTSIZE, cy, UIBLACK); DrawUILine(cx, cy - COLORWHEELSPOTSIZE, cx, cy + COLORWHEELSPOTSIZE, UIBLACK); } if (!GetPredicate(object, ACTIVATED)) { FillUIGauzeRect(left, right, bottom, top, UIBACKGROUND); } #endif return ObjTrue; } #ifdef PROTO void RGB2YIQ(real *y, real *i, real*q, real r, real g, real b) #else void RGB2YIQ(y, i, q, r, g, b) real *y, *i, *q, r, g, b; #endif /*Converts r, g, b, into y, i, q*/ { *y = RGB2YIQMat[0][0] * r + RGB2YIQMat[0][1] * g + RGB2YIQMat[0][2] * b; *i = RGB2YIQMat[1][0] * r + RGB2YIQMat[1][1] * g + RGB2YIQMat[1][2] * b; *q = RGB2YIQMat[2][0] * r + RGB2YIQMat[2][1] * g + RGB2YIQMat[2][2] * b; *i = (*i + 0.6) / 1.2; *q = (*q + 0.52) / 1.04; if (*y < 0.0) *y = 0.0; if (*y > 1.0) *y = 1.0; if (*i < 0.0) *i = 0.0; if (*i > 1.0) *i = 1.0; if (*q < 0.0) *q = 0.0; if (*q > 1.0) *q = 1.0; } #ifdef PROTO void YIQ2RGB(real *r, real *g, real *b, real y, real i, real q) #else void YIQ2RGB(r, g, b, y, i, q) real y, i, q, *r, *g, *b; #endif /*Converts y, i, q, into r, g, b*/ { i = i * 1.2 - 0.6; q = q * 1.04 - 0.52; *r = YIQ2RGBMat[0][0] * y + YIQ2RGBMat[0][1] * i + YIQ2RGBMat[0][2] * q; *g = YIQ2RGBMat[1][0] * y + YIQ2RGBMat[1][1] * i + YIQ2RGBMat[1][2] * q; *b = YIQ2RGBMat[2][0] * y + YIQ2RGBMat[2][1] * i + YIQ2RGBMat[2][2] * q; if (*r < 0.0) *r = 0.0; if (*r > 1.0) *r = 1.0; if (*g < 0.0) *g = 0.0; if (*g > 1.0) *g = 1.0; if (*b < 0.0) *b = 0.0; if (*b > 1.0) *b = 1.0; } #ifdef PROTO void HSV2RGB(real *r, real *g, real *b, real h, real s, real v) #else void HSV2RGB(r, g, b, h, s, v) real *r, *g, *b, h, s, v; #endif /*Converts h s v into r g b. All within range 0..1 Adapted from Foley & VanDam*/ { int i; real f; real p, q, t; while (h < 0.0) h += 1.0; while (h > 1.0) h -= 1.0; h *= 6; /*h from 0 to 6*/ i = h; f = h - i; /*fractional part of i*/ i %= 6; /*i from 0 to 5*/ p = v * (1.0 - s); q = v * (1.0 - (s * f)); t = v * (1.0 - (s * (1.0 - f))); switch (i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } } #ifdef PROTO real HLSValue(real n1, real n2, real h) #else real HLSValue(n1, n2, h) real n1; real n2; real h; #endif { while (h < 0.0) h += 1.0; while (h > 1.0) h -= 1.0; if (h < 1.0 / 6.0) { return n1 + (n2 - n1) * h * 6.0; } else if (h < 0.5) { return n2; } else if (h < 4.0 / 6.0) { return n1 + (n2 - n1) * (4.0 / 6.0 - h) * 6.0; } else { return n1; } } #ifdef PROTO void HLS2RGB(real *r, real *g, real *b, real h, real l, real s) #else void HLS2RGB(r, g, b, h, l, s) real *r, *g, *b, h, s, l; #endif /*Converts h l s into r g b. All within range 0..1 Adapted from Foley & VanDam*/ { real m1, m2; if (l <= 0.5) { m2 = l * (1.0 + s); } else { m2 = l + s - l * s; } m1 = 2 * l - m2; if (s == 0) { *r = *g = *b = 1.0; } else { *r = HLSValue(m1, m2, h + 1.0 / 3.0); *g = HLSValue(m1, m2, h); *b = HLSValue(m1, m2, h - 1.0 / 3.0); } } #ifdef PROTO void RGB2HSV(real *h, real *s, real *v, real r, real g, real b) #else void RGB2HSV(h, s, v, r, g, b) real r, g, b, *h, *s, *v; #endif /*Converts rgb to hsv. All numbers within range 0 to 1.*/ { real max, min; max = MAX(r, MAX(g, b)); min = MIN(r, MIN(g, b)); *v = max; if (max > 0.0) { *s = (max - min) / max; } else { *s = 0; } if (*s > 0.0) { real rc, gc, bc; rc = (max - r) / (max - min); gc = (max - g) / (max - min); bc = (max - b) / (max - min); if (r == max) { *h = (bc - gc) / 6.0; } else if (g == max) { *h = (2.0 + rc - bc) / 6.0; } else { *h = (4.0 + gc - rc) / 6.0; } } else { *h = 0.0; } if (*h < 0.0) *h += 1.0; } #ifdef PROTO void RGB2HLS(real *h, real *l, real *s, real r, real g, real b) #else void RGB2HLS(h, l, s, r, g, b) real r, g, b, *h, *s, *l; #endif /*Converts rgb to hls. All numbers within range 0 to 1.*/ { real max, min; max = MAX(r, MAX(g, b)); min = MIN(r, MIN(g, b)); *l = (max + min) * 0.5; if (max == min) { *s = 0.0; *h = 0.0; } else { real rc, gc, bc; if (*l <= 0.5) { *s = (max - min) / (max + min); } else { *s = (max - min) / (2 - max - min); } rc = (max - r) / (max - min); gc = (max - g) / (max - min); bc = (max - b) / (max - min); if (r == max) { *h = (bc - gc) / 6.0; } else if (g == max) { *h = (2.0 + rc - bc) / 6.0; } else { *h = (4.0 + gc - rc) / 6.0; } } } static ObjPtr TrackColorWheel(object, mouseX, mouseY, flags) ObjPtr object; int mouseX, mouseY; 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; cx = (left + right) / 2; cy = (bottom + top) / 2; width = right - left; height = top - bottom; if (width > height) { radius = height / 2 - COLORWHEELBORDER; } else { radius = width / 2 - COLORWHEELBORDER; } /*Get the current value of the control*/ valueArray = GetFixedArrayVar("TrackColorWheel", object, VALUE, 1, 2L); if (!valueArray) { return ObjFalse; } Array2CArray(value, valueArray); /*Make laxtX and lastY correspond to value*/ lastX = cx + value[1] * cos(2.0 * M_PI * value[0]); lastY = cy + value[1] * sin(2.0 * M_PI * value[0]); if (flags & F_DOUBLECLICK) { /*Snap current value to closest pure hue*/ if (value[1] < 0.33) { /*White*/ value[1] = 0.0; } else { int testo; /*50 % or 100% saturated something*/ if (value[1] > 0.66) { value[1] = 1.0; } else { value[1] = 0.5; } testo = value[0] * 6.0 + 0.5; value[0] = ((real) testo) / 6.0; } valueArray = NewRealArray(1, 2L); CArray2Array(valueArray, value); SetVar(object, VALUE, valueArray); DrawMe(object); ChangedValue(object); if (logging) { LogControl(object); } return ObjTrue; } dontTrack = GetPredicate(object, TRACKNOT); InhibitLogging(true); while (Mouse(&mouseX, &mouseY)) { if (mouseX != lastX || mouseY != lastY) { real hue, saturation; /*Mouse has moved. Update.*/ sX = mouseX - cx; sY = mouseY - cy; if (sX == 0 && sY == 0) { /*It's at the origin, so choose 0 for h and s*/ hue = 0.0; saturation = 0.0; } else { /*Hue is angle*/ hue = atan2(((double) sY) / ((double) radius), ((double) sX) / ((double) radius)) / (2.0 * M_PI); while (hue < 0.0) hue += 1.0; /*Saturation is radius, clipped*/ saturation = sqrt(((double) sY) * ((double) sY) + ((double) sX) * ((double) sX)) / ((double) radius); if (saturation > 1.0) saturation = 1.0; if (flags & F_SHIFTDOWN) { if (saturation > 0.66) { saturation = 1.0; } else if (saturation > 0.33) { saturation = 0.5; } else { saturation = 0.0; } } } value[0] = hue; value[1] = saturation; valueArray = NewRealArray(1, 2L); CArray2Array(valueArray, value); SetVar(object, VALUE, valueArray); DrawMe(object); if (!dontTrack) { ChangedValue(object); } } } if (dontTrack) { ChangedValue(object); } InhibitLogging(false); if (logging) { LogControl(object); } return ObjTrue; } ObjPtr SetColorWheelVal(object, value) ObjPtr object; ObjPtr value; /*Sets the value of the object to value*/ { if (value == NULLOBJ || (IsRealArray(value) && RANK(value) == 1 && DIMS(value)[0] == 2)) { SetVar(object, VALUE, value); ImInvalid(object); ChangedValue(object); if (logging) { LogControl(object); } return ObjTrue; } else { return ObjFalse; } } static ObjPtr CleanupPalette(palette) ObjPtr palette; /*Cleans up the palette before deleting*/ { PPtr *runner; if (((PPtr) palette) -> beg > 0 && ((PPtr) palette) -> nColors > 0) { /*There are some colors*/ FreeColors(((PPtr) palette) -> beg, ((PPtr) palette) -> nColors); } if (((PPtr) palette) -> colors) { free(((PPtr) palette) -> colors); ((PPtr) palette) -> colors = 0; } if (((PPtr) palette) -> components) { free(((PPtr) palette) -> components); ((PPtr) palette) -> components = 0; } runner = &activePalettes; while (*runner) { if (*runner == (PPtr) palette) { *runner = (*runner) -> next; } else { runner = &((*runner) -> next); } } return ObjTrue; } ObjPtr NewPalette(nColors) int nColors; /*Returns a new palette of nColors, initially set to a grey ramp. Returns 0 if it can't.*/ { int k, colorBeg; PPtr retVal; short3 *colors, *components; colors = (short3 *) malloc(sizeof(short3) * nColors); if (!colors) { OMErr(); return NULLOBJ; } components = (short3 *) malloc(sizeof(short3) * nColors); if (!components) { free(colors); OMErr(); return NULLOBJ; } retVal = (PPtr) NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return (ObjPtr) retVal; } retVal -> next = activePalettes; activePalettes = retVal -> next; SETOBJTYPE(retVal -> thing . flags, PALETTE); retVal -> colors = colors; retVal -> components = components; retVal -> beg = -1; retVal -> nColors = nColors; retVal -> min = -1.0; retVal -> max = 1.0; for (k = 0; k < nColors; ++k) { retVal -> colors[k][0] = retVal -> colors[k][1] = retVal -> colors[k][2] = (k + 1) * 255 / nColors; } CopyColorsToComponents(retVal, k, nColors - 1); return (ObjPtr) retVal; } void CopyPalette(d, s) ObjPtr d, s; /*Copies palette s to d*/ { int k; /*Free the colors*/ if (((PPtr) d) -> beg > 0) { FreeColors(((PPtr) d) -> beg, ((PPtr) d) -> nColors); ((PPtr) d) -> beg = -1; } if (((PPtr) d) -> nColors != ((PPtr) s) -> nColors) { SetVar(d, CHANGED, ObjTrue); free(((PPtr) d) -> colors); free(((PPtr) d) -> components); ((PPtr) d) -> colors = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> components = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> nColors = ((PPtr) s) -> nColors; } ((PPtr) d) -> min = ((PPtr) s) -> min; ((PPtr) d) -> max = ((PPtr) s) -> max; for (k = 0; k < ((PPtr) d) -> nColors; ++k) { ((PPtr) d) -> colors[k][0] = ((PPtr) s) -> colors[k][0]; ((PPtr) d) -> colors[k][1] = ((PPtr) s) -> colors[k][1]; ((PPtr) d) -> colors[k][2] = ((PPtr) s) -> colors[k][2]; ((PPtr) d) -> components[k][0] = ((PPtr) s) -> components[k][0]; ((PPtr) d) -> components[k][1] = ((PPtr) s) -> components[k][1]; ((PPtr) d) -> components[k][2] = ((PPtr) s) -> components[k][2]; } SetVar(d, COLORMODEL, GetVar(s, COLORMODEL)); SetVar(d, JUSTCOLORCHANGE, ObjTrue); MapPalette(d); } void SetPaletteNColors(p, nColors) ObjPtr p; int nColors; /*Sets palette to be a nColors palette, doing any necessary resampling.*/ { short3 *oldColors, *colors; short3 *oldComponents, *components; real beg, end, increment; int s1, s2, i, k, comp; int temp; /*Free the colors*/ if (((PPtr) p) -> beg > 0) { FreeColors(((PPtr) p) -> beg, ((PPtr) p) -> nColors); ((PPtr) p) -> beg = -1; } /*Make a new set of colors*/ oldColors = ((PPtr) p) -> colors; colors = (short3 *) malloc(nColors * sizeof(short3)); /*And a new set of components*/ oldComponents = ((PPtr) p) -> components; components = (short3 *) malloc(nColors * sizeof(short3)); /*Copy ov, und, missing*/ colors[0][0] = oldColors[0][0]; colors[0][1] = oldColors[0][1]; colors[0][2] = oldColors[0][2]; colors[1][0] = oldColors[1][0]; colors[1][1] = oldColors[1][1]; colors[1][2] = oldColors[1][2]; colors[nColors - 1][0] = oldColors[((PPtr) p) -> nColors][0]; colors[nColors - 1][1] = oldColors[((PPtr) p) -> nColors][1]; colors[nColors - 1][2] = oldColors[((PPtr) p) -> nColors][2]; increment = ((real) ((PPtr) p) -> nColors - 3) / ((real) nColors - 3); for (k = 0; k < nColors - 2; ++k) { beg = k * increment; end = beg + increment; for (comp = 0; comp < 3; ++comp) { s1 = beg; s2 = end; if (s1 == s2) { /*Chunk of just one color*/ colors[k + 2][comp] = oldColors[s1 + 2][comp]; } else { /*Chunk of more than one color*/ real cum; /*First one*/ cum = (1.0 - (beg - s1)) * oldColors[s1 + 2][comp]; /*Intermediate ones*/ for (i = s1 + 3; i < s2 + 2; ++i) { cum += oldColors[i][comp]; } /*Last one*/ cum += (end - s2) * oldColors[s2 + 2][comp]; cum /= (end - beg); temp = cum + 0.5; if (temp < 0) temp = 0; else if (temp > 255) temp = 255; colors[k + 2][comp] = temp; } } } /*Update nColors*/ ((PPtr) p) -> nColors = nColors; ((PPtr) p) -> colors = colors; ((PPtr) p) -> components = components; /*Free the old colors*/ free(oldColors); free(oldComponents); CopyColorsToComponents((PPtr) p, 0, nColors - 1); SetVar(p, CHANGED, ObjTrue); } #ifdef PROTO void CopyAttenuatedPalette(ObjPtr d, ObjPtr s, real atten) #else void CopyAttenuatedPalette(d, s, atten) ObjPtr d, s; real atten; #endif /*Copies palette s to d, attenuated by d*/ { int k; /*Free the colors*/ if (((PPtr) d) -> beg > 0) { FreeColors(((PPtr) d) -> beg, ((PPtr) d) -> nColors); ((PPtr) d) -> beg = -1; } if (((PPtr) d) -> nColors != ((PPtr) s) -> nColors) { SetVar(d, CHANGED, ObjTrue); free(((PPtr) d) -> colors); ((PPtr) d) -> colors = malloc(sizeof(short3) * ((PPtr) s) -> nColors); free(((PPtr) d) -> components); ((PPtr) d) -> components = malloc(sizeof(short3) * ((PPtr) s) -> nColors); ((PPtr) d) -> nColors = ((PPtr) s) -> nColors; } ((PPtr) d) -> min = ((PPtr) s) -> min; ((PPtr) d) -> max = ((PPtr) s) -> max; for (k = 0; k < ((PPtr) d) -> nColors; ++k) { ((PPtr) d) -> colors[k][0] = ((PPtr) s) -> colors[k][0] * atten; ((PPtr) d) -> colors[k][1] = ((PPtr) s) -> colors[k][1] * atten; ((PPtr) d) -> colors[k][2] = ((PPtr) s) -> colors[k][2] * atten; } SetVar(d, JUSTCOLORCHANGE, ObjTrue); CopyColorsToComponents((PPtr) d, 0, ((PPtr) d) -> nColors - 1); MapPalette(d); } ObjPtr ClonePalette(oldPalette) ObjPtr oldPalette; /*Clones a new palette*/ { PPtr retVal; short3 *colors, *components; colors = (short3 *) malloc(sizeof(short3) * ((PPtr) oldPalette) -> nColors); if (!colors) { OMErr(); return oldPalette; } components = (short3 *) malloc(sizeof(short3) * ((PPtr) oldPalette) -> nColors); if (!components) { OMErr(); return oldPalette; } retVal = (PPtr) NewObject(paletteClass, sizeof(Palette) - sizeof(Thing)); if (!retVal) { return (ObjPtr) retVal; } retVal -> next = activePalettes; activePalettes = retVal -> next; SETOBJTYPE(retVal -> thing . flags, PALETTE); retVal -> colors = colors; retVal -> components = components; retVal -> beg = -1; retVal -> nColors = ((PPtr) oldPalette) -> nColors; CopyPalette((ObjPtr) retVal, oldPalette); return (ObjPtr) retVal; } void InterpPalette(palette, r1, g1, b1, r2, g2, b2) ObjPtr palette; int r1, g1, b1, r2, g2, b2; /*Makes palette be an interpolation between r1, g1, b1, and r2, g2, b2*/ { int k; int n; n = ((PPtr) palette) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { ((PPtr) palette) -> colors[k + 2][0] = (k + 1) * r2 / n + (n - k) * r1 / n; ((PPtr) palette) -> colors[k + 2][1] = (k + 1) * g2 / n + (n - k) * g1 / n; ((PPtr) palette) -> colors[k + 2][2] = (k + 1) * b2 / n + (n - k) * b1 / n; } /*Fill in missing*/ ((PPtr) palette) -> colors[0][0] = 64; ((PPtr) palette) -> colors[0][1] = 64; ((PPtr) palette) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) palette) -> colors[1][0] = ((PPtr) palette) -> colors[2][0]; ((PPtr) palette) -> colors[1][1] = ((PPtr) palette) -> colors[2][1]; ((PPtr) palette) -> colors[1][2] = ((PPtr) palette) -> colors[2][2]; /*Fill in max*/ ((PPtr) palette) -> colors[n + 2][0] = ((PPtr) palette) -> colors[n + 1][0]; ((PPtr) palette) -> colors[n + 2][1] = ((PPtr) palette) -> colors[n + 1][1]; ((PPtr) palette) -> colors[n + 2][2] = ((PPtr) palette) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) palette, 0, ((PPtr) palette) -> nColors - 1); MapPalette(palette); } void BlueToRedPalette(p) ObjPtr p; /*Makes a blue to red palette in p*/ { int k; real hue, r, g, b; int n; n = ((PPtr) p) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { real v = 1.0; /* hue = (((real)(n - k)) / (real) n) * 1.15 - 0.2; */ /* hue = (((real)(n - k)) / (real) n) * 0.8; */ hue = (((real)(n - k)) / (real) n) * 0.9 - 0.1; if (hue < 0.0) {v = 1.0 + (hue * 3.0); hue = 0.0;} HSV2RGB(&r, &g, &b, hue, 1.0, v); ((PPtr) p) -> colors[k + 2][0] = r * 255; ((PPtr) p) -> colors[k + 2][1] = g * 255; ((PPtr) p) -> colors[k + 2][2] = b * 255; } /*Fill in missing*/ ((PPtr) p) -> colors[0][0] = 64; ((PPtr) p) -> colors[0][1] = 64; ((PPtr) p) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) p) -> colors[1][0] = ((PPtr) p) -> colors[2][0]; ((PPtr) p) -> colors[1][1] = ((PPtr) p) -> colors[2][1]; ((PPtr) p) -> colors[1][2] = ((PPtr) p) -> colors[2][2]; /*Fill in max*/ ((PPtr) p) -> colors[n + 2][0] = ((PPtr) p) -> colors[n + 1][0]; ((PPtr) p) -> colors[n + 2][1] = ((PPtr) p) -> colors[n + 1][1]; ((PPtr) p) -> colors[n + 2][2] = ((PPtr) p) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); MapPalette(p); } void GreenToRedPalette(p) ObjPtr p; /*Makes a green to red palette in p*/ { int k; real hue, r, g, b; int n; n = ((PPtr) p) -> nColors - 3; /*Room for min, max, missing*/ for (k = 0; k < n; ++k) { hue = ((real)(n - k)) / (real) n * 0.35; HSV2RGB(&r, &g, &b, hue, 1.0, 1.0); ((PPtr) p) -> colors[k + 2][0] = r * 255; ((PPtr) p) -> colors[k + 2][1] = g * 255; ((PPtr) p) -> colors[k + 2][2] = b * 255; } /*Fill in missing*/ ((PPtr) p) -> colors[0][0] = 64; ((PPtr) p) -> colors[0][1] = 64; ((PPtr) p) -> colors[0][2] = 64; /*Fill in min*/ ((PPtr) p) -> colors[1][0] = ((PPtr) p) -> colors[2][0]; ((PPtr) p) -> colors[1][1] = ((PPtr) p) -> colors[2][1]; ((PPtr) p) -> colors[1][2] = ((PPtr) p) -> colors[2][2]; /*Fill in max*/ ((PPtr) p) -> colors[n + 2][0] = ((PPtr) p) -> colors[n + 1][0]; ((PPtr) p) -> colors[n + 2][1] = ((PPtr) p) -> colors[n + 1][1]; ((PPtr) p) -> colors[n + 2][2] = ((PPtr) p) -> colors[n + 1][2]; CopyColorsToComponents((PPtr) p, 0, ((PPtr) p) -> nColors - 1); MapPalette(p); } void DisposePalette(palette) ObjPtr palette; /*Disposes of palette*/ { free(palette); } real PSColor() /*Returns a grayscale equivalent for the current color in DRAW_POSTSCRIPT mode*/ { real hue, sat, val; RGB2HSV(&hue, &sat, &val, curRed/255.0, curGreen/255.0, curBlue/255.0); return val; /***/ } void SetUIColor(c) int c; /*Sets the current drawing color to user interface color c, regardless of whether the current window is RGB or colormap*/ { #ifdef GRAPHICS if (drawingMode == DRAW_SCREEN) { if (overDraw) { if (c == UIBLACK) { color(0); } else { color(2); } } else if (rgbp) { /*It's an RGB window*/ lmcolor(LMC_COLOR); #ifdef INDIGOCOLORS if (uiColorIndex[c] >= 0) { color(uiColorIndex[c]); } else #endif c3s(uiColors[c]); } else { /*It's a cmap window*/ color(uiColorIndex[c]); } } else { curRed = uiColors[c][0]; curGreen = uiColors[c][1]; curBlue = uiColors[c][2]; } #endif } ObjPtr NewColorWheel(left, right, bottom, top, name) int left, right, bottom, top; char *name; /*Makes a new hue/saturation control in left, right, bottom, top*/ { real value[2]; ObjPtr valueArray; ObjPtr retVal; value[0] = 0.0; value[1] = 0.0; valueArray = NewRealArray(1, (long) 2); if (valueArray) { CArray2Array(valueArray, value); retVal = NewObject(colorWheelClass, 0); Set2DIntBounds(retVal, left, right, bottom, top); SetVar(retVal, VALUE, valueArray); SetVar(retVal, NAME, NewString(name)); return retVal; } else { return NULLOBJ; } } static int ColorToPixel(colorBar, clr) ObjPtr colorBar; int clr; /*Returns the horizontal pixel for the color value in clr*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (clr == 0) { /*Missing*/ return left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2; } else if (clr == 1) { /*Underflow*/ return left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2; } else if (clr == nColors - 1) { /*Overflow*/ return right - CBRBORDER - CBBOXWIDTH / 2; } else { /*In the center*/ int r, l; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; return ((clr - 2) * (r - l) + (r - l) / 2) / (nColors - 3) + l; } } static Bool ColorToPixels(int *, int *, ObjPtr, int); static Bool ColorToPixels(lPix, rPix, colorBar, clr) ObjPtr colorBar; int clr; int *lPix, *rPix; /*Returns the horizontal pixelx around the color value in clr*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return false; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (clr == 0) { /*Missing*/ *lPix = left + CBLBORDER + CBLTEXTSPACE + 1; *rPix = left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1; return true; } else if (clr == 1) { /*Underflow*/ *lPix = left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1; *rPix = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1; return true; } else if (clr == nColors - 1) { /*Overflow*/ *lPix = right - CBRBORDER - CBBOXWIDTH + 1; *rPix = right - CBRBORDER - 1; return true; } else { /*In the center*/ int r, l; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; if (clr == 2) { *lPix = l; } else { *lPix = l + (clr - 2) * (r - l) / (nColors - 3) + 1; } *rPix = l + (clr - 1) * (r - l) / (nColors - 3); return true; } } static int PixelToColor(colorBar, pix) ObjPtr colorBar; int pix; /*Returns the color for the horizontal pixel pixel*/ { int left, right, bottom, top; PPtr palette; int nColors; /*Get the palette*/ palette = (PPtr) GetPaletteVar("ColorToPixel", colorBar, REPOBJ); if (!palette) { return 0; } Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the stuff from the palette*/ nColors = palette -> nColors; if (pix < left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP / 2) { /*Missing*/ return 0; } else if (pix < left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP) { /*Underflow*/ return 1; } else if (pix > right - CBRBORDER - CBBOXWIDTH) { /*Overflow*/ return nColors - 1; } else { /*In the center*/ int r, l, retVal; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; retVal = ((pix - l) * (nColors - 3) + (nColors - 3) / 2) / (r - l) + 2; if (retVal >= nColors - 1) { retVal = nColors - 2; } if (retVal < 2) { retVal = 2; } return retVal; } } #ifdef PROTO void CalcGoodSteps(double diff, int pixWidth, int minMajorPix, double *majorWidth, int *nMinorSteps) #else void CalcGoodSteps(diff, pixWidth, minMajorPix, majorWidth, nMinorSteps) double diff; int pixWidth; int minMajorPix; double *majorWidth; int *nMinorSteps; #endif /*Calculates good steps for a 10-base scale diff is the difference between minimum and max pixWidth is the width in pixels between minimum and max minMajorPix is the minimum number of pixels between major tics *majorWidth will be the width of a major step *nMinorTics will be the number of minor steps */ { long deltaLog; /*Log of the delta at minimum*/ double minDelta; /*Minimum delta between major tics*/ if (diff <= 0.0) { *majorWidth = 0.0; *nMinorSteps = 1; } minDelta = diff * minMajorPix / pixWidth; deltaLog = ((long) (1000.0 + log10((double) minDelta))) - 1000; *majorWidth = pow((double) 10.0, (double) deltaLog); *nMinorSteps = 1; while (*majorWidth < minDelta) { if (*majorWidth < minDelta) { /*Try 2*/ *majorWidth *= 2.0; *nMinorSteps = 2; } if (*majorWidth < minDelta) { /*Try 5*/ *majorWidth *= 2.5; *nMinorSteps = 5; } if (*majorWidth < minDelta) { /*Try 10*/ *majorWidth *= 2.0; *nMinorSteps = 10; } } } void ResetColorBarTools(colorBar) ObjPtr colorBar; /*Resets the tools associated with a color bar*/ { ObjPtr radio, freeFormButton; InhibitLogging(true); freeFormButton = GetVar(colorBar, FREEFORMBUTTON); radio = GetVar(colorBar, TOOLGROUP); if (radio) { /***UPDATE For some reason, this doesn't work properly.*/ SetValue(radio, NewInt(freeFormButton ? (GetPredicate(freeFormButton, ACTIVATED) ? PT_FREEFORM : -1) : PT_FREEFORM)); } InhibitLogging(false); } ObjPtr SetColorBarVal(object, value) ObjPtr object; ObjPtr value; /*Sets the value of the object to value*/ { if (IsRealArray(value) && RANK(value) == 1 && DIMS(value)[0] == 3) { ObjPtr radio; PPtr repObj; real *elements; elements = ELEMENTS(value); if (elements[0] < 0.0 || elements[0] > 3.0 || elements[1] < 0.0 || elements[2] < 0.0) { ReportError("SetColorBarVal", "Value error"); return ObjFalse; } repObj = (PPtr) GetPaletteVar("SetColorBarVal", object, REPOBJ); if (repObj) { if (elements[1] >= ((real) repObj -> nColors) - 0.5 || elements[2] >= ((real) repObj -> nColors) - 0.5) { ReportError("SetColorBarVal", "Value error"); return ObjFalse; } } SetVar(object, VALUE, value); ImInvalid(object); ChangedValue(object); if (logging) { LogControl(object); } /*Set the edit tool to 0*/ ResetColorBarTools(object); return ObjTrue; } else { ReportError("SetColorBarVal", "Bad value for color bar"); return ObjFalse; } } static ObjPtr ReinitColorBar(colorBar) ObjPtr colorBar; /*Reinitializes a color bar*/ { return ObjTrue; } real GetColorValue(palette, color) ObjPtr palette; int color; /*Gets a field value for center of color color. Ignores missing*/ { return ((PPtr) palette) -> min + (color - 2) * (((PPtr) palette) -> max - ((PPtr) palette) -> min) / (((PPtr) palette) -> nColors - 4); } static int hueColors[7] = { UIRED, UIYELLOW, UIGREEN, UICYAN, UIBLUE, UIMAGENTA, UIRED }; #ifdef PROTO static void ColorModelRect(int left, int right, int bottom, int top, int cm, int k) #else static void ColorModelRect(left, right, bottom, top, cm, k) int left; int right; int bottom; int top; int cm; int k; #endif /*Fills a rectangle within the bounds for color model cm in field k*/ { #ifdef GRAPHICS switch (cm) { case CM_RGB: FillUIRect(left, right, bottom, top, k == 1 ? UIBLUE : k == 2 ? UIGREEN : UIRED); break; case CM_HSV: case CM_HLS: shademodel(GOURAUD); if (k == 3) { /*Hue*/ int c; long v[2]; bgnpolygon(); SetUIColor(UIRED); v[1] = bottom; v[0] = left; v2i(v); v[0] = right + 1; v2i(v); for (c = 1; c < 5; ++c) { SetUIColor(hueColors[c]); v[1] = bottom + (top - bottom) * c / 6; v[0] = right + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v2i(v); v[0] = right + 1; v2i(v); } SetUIColor(hueColors[c]); v[1] = top + 1; v[0] = right + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if ((cm == CM_HSV && k == 2) || (cm == CM_HLS && k == 1)) { /*Saturation*/ long v[2]; bgnpolygon(); SetUIColor(UIWHITE); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if (cm == CM_HSV) { /*Must be value*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else { /*Must be lightness*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = (top + bottom) / 2; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v[0] = left; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIWHITE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } shademodel(FLAT); break; case CM_YIQ: shademodel(GOURAUD); if (k == 3) { /*Must be y*/ long v[2]; bgnpolygon(); SetUIColor(UIBLACK); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UICYAN); v[1] = (top + bottom) / 2; v2i(v); v[0] = left; v2i(v); endpolygon(); bgnpolygon(); v[0] = left; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIWHITE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else if (k == 2) { /*i, cyan/orange index*/ long v[2]; bgnpolygon(); SetUIColor(UICYAN); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIORANGE); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } else { /*q, green/magenta axis*/ long v[2]; bgnpolygon(); SetUIColor(UIGREEN); v[0] = left; v[1] = bottom; v2i(v); v[0] = right + 1; v2i(v); SetUIColor(UIMAGENTA); v[1] = top + 1; v2i(v); v[0] = left; v2i(v); endpolygon(); } shademodel(FLAT); break; } #endif } static ObjPtr DrawColorBar(colorBar) ObjPtr colorBar; /*Draws a color bar*/ { #ifdef GRAPHICS int left, right, bottom, top; int l, r, b, t; int start, diff, comp; PPtr palette; int nColors; short3 *colors; ObjPtr value; /*Value of the control*/ real *elements; ObjPtr var; int highlighted; int k; double majorWidth, minorWidth; /*Width of a major step*/ double ddiff; /*Data difference*/ int nTics; /*Number of minor tics*/ long temp; double halfSpace; int pixel; /*Temporary pixel*/ double curValue; /*Current value for making tics*/ int cm; /*Color model in use*/ Get2DIntBounds(colorBar, &left, &right, &bottom, &top); /*Get the palette*/ palette = (PPtr) GetPaletteVar("DrawColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*Get the stuff from the palette*/ nColors = palette -> nColors; colors = palette -> colors; /*Draw the bump and plateau*/ 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; DrawString( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2 - StrWidth("Missing") / 2, bottom + CBBORDER + CBTEXTUP, "Missing"); DrawUILine( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); DrawString( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2 - StrWidth("Under") / 2, bottom + CBBORDER + CBTEXTUP, "Under"); DrawUILine( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); /*Draw all the tics in the middle*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = palette -> min / majorWidth; curValue = temp * majorWidth; while (curValue > palette -> min) { curValue -= majorWidth; } k = 0; while (curValue < palette -> min) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= palette -> max + ddiff * 1.0E-6) { pixel = l + (curValue - palette -> min) * (r - l) / (ddiff); if (k == 0) { /*Major tic*/ DrawUILine(pixel, b, pixel, b - CBMAJORTICLEN, UIBLACK); sprintf(tempStr, "%lg", curValue); DrawString(pixel - StrWidth(tempStr) / 2, b - CBTEXTSEP, tempStr); } else { /*Minor tic*/ DrawUILine(pixel, b, pixel, b - CBMAJORTICLEN / 2, UIBLACK); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } DrawString( right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2 - StrWidth("Over") / 2, bottom + CBBORDER + CBTEXTUP, "Over"); DrawUILine( right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2, b, right - CBRBORDER - CBBOXWIDTH + CBBOXWIDTH / 2, b - CBMAJORTICLEN, UIBLACK); /*Get the color model*/ var = GetIntVar("DrawColorBar", (ObjPtr) palette, COLORMODEL); if (!var) { return ObjFalse; } cm = GetInt(var); /*Draw the boxes*/ b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; SetupFont(CBBIGTEXTFONT, CBBIGTEXTSIZE); for (k = 0; k < 4; ++k) { t = b + CBCOMPHEIGHT; /*Draw the box outlines*/ /*Draw the missing data box*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH, b, t, UIBLACK); /*Now the underflow box*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP, b, t, UIBLACK); /*Now the middle bit*/ FrameUIRect(left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP, right - CBRBORDER - CBBOXWIDTH - CBHGAP, b, t, UIBLACK); /*Now the overflow box*/ FrameUIRect(right - CBRBORDER - CBBOXWIDTH, right - CBRBORDER, b, t, UIBLACK); /*Draw the background of the boxex*/ /*Draw the missing data box*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, b + 1, t - 1, cm, k); /*Now the underflow box*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, b + 1, t - 1, cm, k); /*Now the middle bit*/ ColorModelRect(left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1, right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1, b + 1, t - 1, cm, k); /*Now the overflow box*/ ColorModelRect(right - CBRBORDER - CBBOXWIDTH + 1, right - CBRBORDER - 1, b + 1, t - 1, cm, k); /*Now the component names*/ if (k) { SetUIColor(UIBLACK); DrawString(left + CBLBORDER, (b + t) / 2 - CBCOMPTEXTDOWN, shortComponentNames[cm][3 - k]); } b = t + CBVGAP; } /*Now the expanded readout*/ FrameUIRect(left + CBLBORDER, right - CBRBORDER, b, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, UIBLACK); b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 1; t = b + CBCOMPHEIGHT - 2; /*Now draw the colors*/ if (rgbp) { /*It's in RGB mode, so we don't have to set the palette*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; /*Do missing data box*/ c3s(colors[0]); rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t); /*Do underflow data box*/ c3s(colors[1]); rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, b, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t); /*Do the colors in the center*/ diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; c3s(colors[k]); rectfi(l, b, r, t); l = r + 1; } /*Do overflow data box*/ c3s(colors[nColors - 1]); rectfi( right - CBRBORDER - CBBOXWIDTH + 1, b, right - CBRBORDER - 1, t); } else { /*It's a color map window, have to set the colors*/ int beg; l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; SetPalette((ObjPtr) palette); beg = palette -> beg; /*Do missing data box*/ color(beg); rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, b, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t); /*Do underflow data box*/ color(beg + 1); rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, b, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t); /*Do the colors in the center*/ diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; color(beg + k); rectfi(l, b, r, t); l = r + 1; } /*Do overflow data box*/ color(beg + nColors - 1); rectfi( right - CBRBORDER - CBBOXWIDTH + 1, b, right - CBRBORDER - 1, t); } b = t + CBVGAP + 2; t = b + CBCOMPHEIGHT - 1; /*Do 3 components*/ for (comp = 2; comp >= 0; --comp) { int height; SetUIColor(UIGRAY62); /*Do missing data box*/ height = GetColorComponent(palette, 0, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi( left + CBLBORDER + CBLTEXTSPACE + 1, t - CBCOMPHEIGHT + height + 1, left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH - 1, t - 1); } /*Do underflow data box*/ height = GetColorComponent(palette, 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi( left + CBLBORDER + CBLTEXTSPACE + CBBOXWIDTH + CBHGAP + 1, t - CBCOMPHEIGHT + height + 1, left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + CBHGAP - 1, t - 1); } /*Do the colors in the center*/ l = left + CBLBORDER + CBLTEXTSPACE + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; diff = r - l; start = l; for (k = 2; k < nColors - 1; ++k) { r = (k - 1) * diff / (nColors - 3) + start; height = GetColorComponent(palette, k, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi(l, t - CBCOMPHEIGHT + height + 1, r, t - 1); } l = r + 1; } /*Overflow*/ height = GetColorComponent(palette, nColors - 1, comp) * (CBCOMPHEIGHT - 1) / 255; if (height < CBCOMPHEIGHT - 1) { rectfi(right - CBRBORDER - CBBOXWIDTH + 1, t - CBCOMPHEIGHT + height + 1, right - CBRBORDER - 1, t - 1); } b = t + CBVGAP + 1; t = b + CBCOMPHEIGHT - 1; } /*Now deal with the value*/ value = GetValue(colorBar); if (!value) { /*Have to give it a value*/ value = NewRealArray(1, 3L); elements = ELEMENTS(value); elements[0] = 0.0; elements[1] = 0.0; elements[2] = 0.0; } else { elements = ELEMENTS(value); } if (elements[0] >= 0.5) { /*Draw the selection in the magnified area*/ int dummy; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + ((int) (elements[0] - 0.5)) * (CBVGAP + CBCOMPHEIGHT); t = b + CBCOMPHEIGHT; ColorToPixels(&l, &dummy, colorBar, (int) (elements[1] + 0.5)); ColorToPixels(&dummy, &r, colorBar, (int) (elements[2] + 0.5)); FrameUIRect(l - 1, r + 3, b - 2, t, UIBLACK); FrameUIRect(l - 2, r + 1, b, t + 1, UIYELLOW); FrameUIRect(l - 3, r + 2, b - 1, t + 2, UIYELLOW); /*Draw the expanded range*/ if (elements[0] == 1.0) { int c1, c2; /*Draw the full color*/ l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; if (rgbp) { /*It's in RGB mode, so we don't have to set the palette*/ /*Do the colors in the center*/ diff = r - l; start = l; c1 = elements[1]; c2 = elements[2]; for (k = c1; k <= c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; c3s(colors[k]); rectfi(l, b, r, t); l = r + 1; } } else { /*It's a color map window, have to set the colors*/ int beg; SetPalette((ObjPtr) palette); beg = palette -> beg; /*Do the colors in the center*/ diff = r - l; start = l; c1 = elements[1]; c2 = elements[2]; for (k = c1; k <=c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; color(beg + k); rectfi(l, b, r, t); l = r + 1; } } } else { int c1, c2; int height; c1 = elements[1]; c2 = elements[2]; comp = 4 - ((int) elements[0]); l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; ColorModelRect(l, r, b, t, cm, (int) elements[0] - 1); SetUIColor(UIGRAY62); /*Do the colors in the center*/ diff = r - l; start = l; for (k = c1; k <= c2; ++k) { r = (k - c1 + 1) * diff / (c2 - c1 + 1) + start; height = GetColorComponent(palette, k, comp) * (t - b) / 255.0 + 0.5; if (height < t - b) { rectfi(l, b + height, r, t); } l = r + 1; } } } /*Draw the tics at the top*/ if (elements[0] > 0.0) { real start, finish, halfSpace; l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP + 4 * CBCOMPHEIGHT + 4 * CBVGAP + 1; if (elements[2] >= elements[1]) { /*It's a range*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, (int) elements[1]) - halfSpace; finish = GetColorValue((ObjPtr) palette, (int) elements[2]) + halfSpace; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = start / majorWidth; curValue = temp * majorWidth; while (curValue > start) { curValue -= majorWidth; } k = 0; while (curValue < start) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } SetupFont(CBBIGTEXTFONT, CBBIGTEXTSIZE); /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= finish + ddiff * 1.0E-6) { int strOff; pixel = l + (curValue - start) * (r - l) / (ddiff); if (k == 0) { /*Major tic*/ DrawUILine(pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP + CBMAJORTICLEN, UIBLACK); sprintf(tempStr, "%lg", curValue); strOff = StrWidth(tempStr) / 2; if (pixel - strOff > l - CBLBORDER && pixel + strOff < r + CBRBORDER) { DrawString(pixel - strOff, top - CBTBORDER - CBTEXTDOWN, tempStr); } } else { /*Minor tic*/ DrawUILine(pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP, pixel, top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP + CBMAJORTICLEN / 2, UIBLACK); } curValue += minorWidth; if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; ++k; if (k >= nTics) k = 0; } /*Draw the function box, if any*/ var = GetVar(colorBar, FUNCTIONBOX); if (var) { int boxL, boxR, boxB, boxT, boxX, boxY; real *elements; elements = ELEMENTS(var); boxL = l + (elements[0] - start) * (r - l) / (ddiff); boxR = l + (elements[1] - start) * (r - l) / (ddiff); boxB = b + elements[2] * (t - b) / 255.0; boxT = b + elements[3] * (t - b) / 255.0; boxX = (boxL + boxR) / 2; boxY = (boxB + boxT) / 2; SetClipRect(left + 3, right - 3, bottom + 3, top - 3); /*Now draw the box and its handles*/ FrameUIRect(boxL + 1, boxR + 2, boxB - 2, boxT - 1, UIBLACK); FrameUIRect(boxL + 1 - CBHANDLESIZE, boxL + 1, boxY - 1 - CBHANDLESIZE / 2, boxY - 1 + CBHANDLESIZE / 2, UIBLACK); FrameUIRect(boxR + 2, boxR + 2 + CBHANDLESIZE, boxY - 1 - CBHANDLESIZE / 2, boxY - 1 + CBHANDLESIZE / 2, UIBLACK); FrameUIRect(boxX + 2 - CBHANDLESIZE / 2, boxX + 2 + CBHANDLESIZE / 2, boxT - 1, boxT - 1 + CBHANDLESIZE, UIBLACK); FrameUIRect(boxX + 2 - CBHANDLESIZE / 2, boxX + 2 + CBHANDLESIZE / 2, boxB - 2 - CBHANDLESIZE, boxB - 2, UIBLACK); FrameUIRect(boxL, boxR, boxB, boxT, UIYELLOW); FrameUIRect(boxL - 1, boxR + 1, boxB - 1, boxT + 1, UIYELLOW); FillUIRect(boxL - 1 - CBHANDLESIZE, boxL, boxY - CBHANDLESIZE / 2, boxY + 1 + CBHANDLESIZE / 2, UIYELLOW); FillUIRect(boxR, boxR + 1 + CBHANDLESIZE, boxY - CBHANDLESIZE / 2, boxY + 1 + CBHANDLESIZE / 2, UIYELLOW); FillUIRect(boxX - CBHANDLESIZE / 2, boxX + 1 + CBHANDLESIZE / 2, boxT, boxT + 1 + CBHANDLESIZE, UIYELLOW); FillUIRect(boxX - CBHANDLESIZE / 2, boxX + 1 + CBHANDLESIZE / 2, boxB - 1 - CBHANDLESIZE, boxB, UIYELLOW); RestoreClipRect(); } } } #endif return ObjTrue; } ObjPtr SetFunctionBox(colorBar, functionBox) ObjPtr colorBar; ObjPtr functionBox; /*Sets the FUNCTIONBOX of colorBar to functionBox, also logs*/ { real *elements; PPtr repObj; if (functionBox && (!IsRealArray(functionBox) || RANK(functionBox) != 1 || DIMS(functionBox)[0] != 4)) { ReportError("SetFunctionBox", "Bad value given"); return ObjFalse; } repObj = (PPtr) GetPaletteVar("SetFunctionBox", colorBar, REPOBJ); if (!repObj) { return ObjFalse; } if (functionBox) { elements = ELEMENTS(functionBox); if (elements[2] < -0.5 || elements[2] >= 255.5 || elements[3] < -0.5 || elements[3] >= 255.5 || elements[2] > elements[3] || elements[0] > elements[1]) { ReportError("SetFunctionBox", "Value out of range"); return ObjFalse; } } SetVar(colorBar, FUNCTIONBOX, functionBox); if (logging) { char cmd[256]; char *s; sprintf(cmd, "set functionbox "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, colorBar); while (*s) ++s; *s++ = ' '; PrintScriptObject(s, functionBox); while (*s) ++s; *s++ = '\n'; *s = 0; Log(cmd); } return ObjTrue; } void LogColorChange(colorBar, colors, newColor) ObjPtr colorBar; short3 *colors; int newColor; /*Logs a change to colors[newColor] within colorBar*/ { if (logging) { char cmd[256]; char *s; sprintf(cmd, "set color "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, colorBar); while (*s) ++s; *s++ = ' '; sprintf(s, "%d %d %d %d\n", newColor, colors[newColor][0], colors[newColor][1], colors[newColor][2]); Log(cmd); } } ObjPtr SetColorBarColor(colorBar, whichColor, r, g, b) ObjPtr colorBar; int whichColor, r, g, b; /*Sets color whichColor from inside a color bar*/ { PPtr palette; short3 *colors; palette = (PPtr) GetPaletteVar("SetColorBarColor", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colors = palette -> colors; colors[whichColor][0] = r; colors[whichColor][1] = g; colors[whichColor][2] = b; ImInvalid(colorBar); LogColorChange(colorBar, colors, whichColor); ChangedValue(colorBar); CopyColorsToComponents(palette, whichColor, whichColor); #ifdef GRAPHICS MapPaletteColors(palette, whichColor, whichColor); #endif SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); return ObjTrue; } static ObjPtr PressColorBar(colorBar, x, y, flags) ObjPtr colorBar; int x, y; long flags; /*Does a press in a color bar beginning at x and y. Returns true iff the press really was in the control.*/ { #ifdef INTERACTIVE int left, right, bottom, top; int l, r, b, t; int k; int cm; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); if (x >= left && x <= right && y >= bottom && y <= top) { real val[3]; ObjPtr value, var; real *origVal; ObjPtr palette; /*Hey! It really was a click in the time control*/ if (TOOL(flags) == T_HELP) { ContextHelp(colorBar); return ObjTrue; } b = bottom + CBBORDER + CBTEXTUP + CBTEXTSEP; if (y < b) { /*Click below*/ val[0] = val[1] = val[2] = 0.0; value = NewRealArray(1, 3L); CArray2Array(value, val); SetValue(colorBar, value); return ObjTrue; } /*Get current value*/ value = GetFixedArrayVar("PressColorBar", colorBar, VALUE, 1, 3L); if (!value) { return ObjFalse; } origVal = (real *) ELEMENTS(value); palette = (ObjPtr) GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } /*Get the color model*/ var = GetIntVar("PressColorBar", (ObjPtr) palette, COLORMODEL); if (!var) { return ObjFalse; } cm = GetInt(var); /*See if it's in one of the components or full color*/ for (k = 0; k < 4; ++k) { t = b + CBCOMPHEIGHT; if (y <= t && y >= b) { ObjPtr radio; int newX, newY; int startColor; int lastColor; int newColor; Bool inp; /*True if inside*/ /*It's a press in track k*/ InhibitLogging(true); if ((flags & F_SHIFTDOWN) || TOOL(flags) == T_ROTATE) { /*Shift click, determine start from farthest*/ newColor = PixelToColor(colorBar, x); if (ABS(newColor - origVal[2]) < ABS(newColor - origVal[1])) { startColor = origVal[1]; } else { startColor = origVal[2]; } } else { startColor = PixelToColor(colorBar, x); } lastColor = -1; val[0] = (real) (k + 1); inp = true; /*Set the edit tool to free form*/ ResetColorBarTools(colorBar); while (Mouse(&newX, &newY)) { if (newY > t + SLOP || newY < b - SLOP || newX < left - SLOP || newX > right + SLOP) { /*It's outside*/ if (inp) { /*Transition from in to out*/ SetVar(colorBar, VALUE, value); ChangedValue(colorBar); inp = false; lastColor = -1; DrawMe(colorBar); } } else { /*It's inside*/ if (!inp) { /*Transition from out to in*/ inp = true; } newColor = PixelToColor(colorBar, newX); if (newColor != lastColor) { ObjPtr var; /*It's a new color, set it*/ if (newColor >= startColor) { val[1] = (real) startColor; val[2] = (real) newColor; } else { val[2] = (real) startColor; val[1] = (real) newColor; } var = NewRealArray(1, 3L); CArray2Array(var, val); SetVar(colorBar, VALUE, var); ChangedValue(colorBar); DrawMe(colorBar); lastColor = newColor; } } } InhibitLogging(false); LogControl(colorBar); return ObjTrue; } b = t + CBVGAP; } /*It wasn't in a component, maybe it's in the readout*/ t = top - CBTBORDER - CBTEXTDOWN - CBTEXTDOWNSEP - 1; l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; if (origVal[0] > 1.0 && y >= b - SLOP && y <= t + SLOP && x >= l - SLOP && x <= r + SLOP) { /*It is! Do stuff based on edit mode*/ int editMode; int lastColor, lastAmp; PPtr palette; int index1, index2; int k; int comp; short3 *colors; int newX, newY, newColor, newAmp; ObjPtr panel, button; palette = (PPtr) GetPaletteVar("PressColorBar", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colors = palette -> colors; comp = 4 - origVal[0]; var = GetIntVar("PressColorBar", colorBar, EDITMODE); if (!var) { return ObjFalse; } editMode = GetInt(var); index1 = origVal[1] + 0.5; index2 = origVal[2] + 0.5; panel = GetVar(colorBar, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } if (editMode == PT_FREEFORM) { int firstAltered, lastAltered; Bool constrainX, constrainY; /*Free form*/ lastColor = lastAmp = -1; firstAltered = index2 + 1; lastAltered = index1 - 1; constrainX = constrainY = false; while (Mouse(&newX, &newY)) { if (newX >= l - SLOP && newX <= r + SLOP && newY >= b - SLOP && newY <= t + SLOP) { if (flags & F_SHIFTDOWN) { if (!constrainX && !constrainY) { int xDiff, yDiff; /*Must make some constraints*/ xDiff = ABS(newX - x); yDiff = ABS(newY - y); if (xDiff >= MINCONSTRAINT && yDiff >= MINCONSTRAINT) { if (yDiff > xDiff) { constrainX = true; } else { constrainY = true; } } } if (constrainX) newX = x; if (constrainY) newY = y; } /*Calculate newAmp*/ newAmp = ((newY - b) + 0.5) * 255.0 / (real) (t - b - 1); if (newAmp < 0) newAmp = 0; else if (newAmp > 255) newAmp = 255; /*Calculate newColor*/ newColor = index1 + ((real) newX - l) * ((real) index2 - index1 + 1) / ((real) (r - l - 1)); if (newColor < index1) newColor = index1; else if (newColor > index2) newColor = index2; if (newColor < firstAltered) { firstAltered = newColor; } if (newColor > lastAltered) { lastAltered = newColor; } if (newAmp != lastAmp || newColor != lastColor) { /*Set the new color to be correct*/ if (lastColor <= -1 || lastColor == newColor) { /*New in this range, just set this color*/ SetColorComponent(palette, newColor, comp, newAmp); #ifdef GRAPHICS MapPaletteColors(palette, newColor, newColor); #endif } else if (newColor > lastColor) { int nc; /*Linearly interpolate up to this color*/ for (k = lastColor + 1; k <= newColor; ++k) { nc = ((newColor - k) * lastAmp + (k - lastColor) * newAmp) / (newColor - lastColor); if (nc < 0) nc = 0; else if (nc > 255) nc = 255; SetColorComponent(palette, k, comp, nc); } #ifdef GRAPHICS MapPaletteColors(palette, lastColor, newColor); #endif } else if (newColor < lastColor) { int nc; /*Linearly interpolate down to this color*/ for (k = lastColor - 1; k >= newColor; --k) { nc = ((k - newColor) * lastAmp + (lastColor - k) * newAmp) / (lastColor - newColor); if (nc < 0) nc = 0; else if (nc > 255) nc = 255; SetColorComponent(palette, k, comp, nc); } #ifdef GRAPHICS MapPaletteColors(palette, lastColor, newColor); #endif } ChangedValue(colorBar); DrawMe(colorBar); lastAmp = newAmp; lastColor = newColor; } } else { lastColor = lastAmp = -1; } } for (k = firstAltered; k <= lastAltered; ++k) { LogColorChange(colorBar, colors, k); } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); } else { /*It's a tool*/ ObjPtr toolBounds; int boxL, boxR, boxB, boxT; int xOffset, yOffset; double start, finish, ddiff, halfSpace; real *elements; real newElements[4]; int whichMove = 0; real lastSide, nextSide; double majorWidth, minorWidth; int nTics; long temp; #define MOVEBOXTOP 1 #define MOVEBOXBOTTOM 2 #define MOVEBOXLEFT 3 #define MOVEBOXRIGHT 4 #define MOVEBOXLR 5 halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, index1) - halfSpace; finish = GetColorValue((ObjPtr) palette, index2) + halfSpace; ddiff = finish - start; toolBounds = GetFixedArrayVar("PressColorBar", colorBar, FUNCTIONBOX, 1, 4L); if (!toolBounds) { return ObjFalse; } elements = ELEMENTS(toolBounds); boxL = l + (elements[0] - start) * (r - l) / (ddiff); boxR = l + (elements[1] - start) * (r - l) / (ddiff); boxB = b + elements[2] * (t - b) / 255.0; boxT = b + elements[3] * (t - b) / 255.0; /*Figure out which side is clicked on*/ whichMove = 0; if (y >= boxB - (CBHANDLESIZE + 2) && y <= boxT + (CBHANDLESIZE + 2)) { if (x >= boxL - (CBHANDLESIZE + 2) && x <= boxL) { whichMove = MOVEBOXLEFT; xOffset = x - boxL; } else if (x >= boxR && x <= boxR + (CBHANDLESIZE + 2)) { whichMove = MOVEBOXRIGHT; xOffset = x - boxR; } } if (x >= boxL - (CBHANDLESIZE + 2) && x <= boxR + (CBHANDLESIZE + 2)) { if (y >= boxB - (CBHANDLESIZE + 2) && y <= boxB) { whichMove = MOVEBOXBOTTOM; yOffset = y - boxB; } else if (y >= boxT && y <= boxT + (CBHANDLESIZE + 2)) { whichMove = MOVEBOXTOP; yOffset = y - boxT; } } if (!whichMove) { whichMove = MOVEBOXLR; xOffset = x - boxL; yOffset = y - (boxT + boxB) / 2; } newElements[0] = elements[0]; newElements[1] = elements[1]; newElements[2] = elements[2]; newElements[3] = elements[3]; if (flags & F_SHIFTDOWN) { /*Constrained motion, have to calc constraint stuff*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, index1) - halfSpace; finish = GetColorValue((ObjPtr) palette, index2) + halfSpace; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; } /*Now do it*/ if (whichMove == MOVEBOXLEFT || whichMove == MOVEBOXRIGHT) { lastSide = newElements[whichMove == MOVEBOXLEFT ? 0 : 1]; while (Mouse(&newX, &newY)) { nextSide = start + (newX - xOffset - l) * (finish - start) / (r - l); if (flags & F_SHIFTDOWN) { /*Constrain*/ temp = nextSide / minorWidth + 0.5; nextSide = temp * minorWidth; } if (nextSide != lastSide) { /*Change it*/ newElements[whichMove == MOVEBOXLEFT ? 0 : 1] = nextSide; if (newElements[1] > newElements[0]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastSide = nextSide; } } } } else if (whichMove == MOVEBOXTOP || whichMove == MOVEBOXBOTTOM) { lastAmp = newElements[whichMove == MOVEBOXBOTTOM ? 2 : 3] + 0.5; while (Mouse(&newX, &newY)) { newAmp = ((newY - yOffset - b) + 0.5) * 255.0 / (real) (t - b - 1); if (newAmp < 0) newAmp = 0; else if (newAmp > 255) newAmp = 255; if (newAmp != lastAmp) { /*Change it*/ newElements[whichMove == MOVEBOXBOTTOM ? 2 : 3] = newAmp; if (newElements[3] > newElements[2]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastAmp = newAmp; } } } } if (whichMove == MOVEBOXLR) { lastSide = newElements[0]; while (Mouse(&newX, &newY)) { nextSide = start + (newX - xOffset - l) * (finish - start) / (r - l); if (flags & F_SHIFTDOWN) { /*Constrain*/ temp = nextSide / minorWidth + 0.5; nextSide = temp * minorWidth; } if (nextSide != lastSide) { /*Change it*/ newElements[0] = nextSide; newElements[1] = nextSide + elements[1] - elements[0]; if (newElements[1] > newElements[0]) { toolBounds = NewRealArray(1, 4L); CArray2Array(toolBounds, newElements); SetFunctionBox(colorBar, toolBounds); InhibitLogging(true); ImposeColorFunction(colorBar); InhibitLogging(false); DrawMe(colorBar); lastSide = nextSide; } } } } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); } } return ObjTrue; } else { return ObjFalse; } #else return ObjFalse; #endif } ObjPtr NewColorBar(left, right, bottom, top, name) int left, right, bottom, top; char *name; /*Makes a new hue/saturation control in left, right, bottom, top*/ { ObjPtr retVal; ObjPtr value; retVal = NewObject(colorBarClass, 0); Set2DIntBounds(retVal, left, right, bottom, top); SetVar(retVal, NAME, NewString(name)); SetVar(retVal, TYPESTRING, NewString("color bar control")); value = NewRealArray(1, 3L); ((real *) ELEMENTS(value))[0] = 1.0; ((real *) ELEMENTS(value))[1] = 0.0; ((real *) ELEMENTS(value))[1] = 0.0; SetVar(retVal, VALUE, value); return retVal; } #ifdef PROTO static void ChoosePaletteSliderValue(ObjPtr, PPtr, int, int, int); #endif static void ChoosePaletteSliderValue(slider, palette, component, index1, index2) ObjPtr slider; PPtr palette; int index1, index2, component; /*Chooses a value for the slider based on colors index1 through index2 of palette. Component is 0 for rgb, 1 for r, 2 for g, and 3 for b, */ { real min, max, testVal; short3 *colors; real hsv[3]; int k; colors = palette -> colors; min = 1.0; max = 0.0; if (component) { for (k = index1; k <= index2; ++k) { testVal = ((real) GetColorComponent(palette, k, component - 1)) / 255.0; if (testVal < min) { min = testVal; } if (testVal > max) { max = testVal; } } } else { for (k = index1; k <= index2; ++k) { RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), ((real) colors[k][0]) / 255.0, ((real) colors[k][1]) / 255.0, ((real) colors[k][2]) / 255.0); testVal = hsv[2]; if (testVal < min) { min = testVal; } if (testVal > max) { max = testVal; } } } testVal = (min + max) * 0.5; if (testVal < 0.0) testVal = 0.0; if (testVal > 1.0) testVal = 1.0; SetSliderValue(slider, testVal); SetVar(slider, INITVALUE, NewReal(testVal)); SetVar(slider, TEMPPALETTE, ClonePalette((ObjPtr) palette)); } static ObjPtr ChangePaletteBar(colorBar) ObjPtr colorBar; /*Changed value for a color bar that controls a palette*/ { ObjPtr colorWheel, slider, button, buttons; ThingListPtr buttonList; PPtr palette; ObjPtr value, newValue; FuncTyp changedValue; real hsv[3]; short3 *colors; int index; real *elements; value = GetFixedArrayVar("ChangePaletteBar", colorBar, VALUE, 1, 3L); colorWheel = GetObjectVar("ChangePaletteBar", colorBar, COLORWHEEL); palette = (PPtr) GetPaletteVar("ChangePaletteBar", colorBar, REPOBJ); slider = GetObjectVar("ChangePaletteBar", colorBar, SLIDER); if (!colorWheel || !palette || !value || !slider) { return ObjFalse; } elements = ELEMENTS(value); if (elements[0] == 1.0) { /*Active color wheel*/ ActivateColorWheel(colorWheel, true); if (elements[1] == elements[2]) { /*Give it a value*/ colors = palette -> colors; /*Update the left slider and color wheel*/ index = elements[1]; RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), ((real) colors[index][0]) / 255.0, ((real) colors[index][1]) / 255.0, ((real) colors[index][2]) / 255.0); if (hsv[2] < 0.0) hsv[2] = 0.0; else if (hsv[2] > 1.0) hsv[2] = 1.0; } else { /*No value*/ newValue = NULLOBJ; } changedValue = GetMethod(colorWheel, CHANGEDVALUE); SetMethod(colorWheel, CHANGEDVALUE, 0); newValue = NewRealArray(1, 2L); ((real *) ELEMENTS(newValue))[0] = hsv[0]; ((real *) ELEMENTS(newValue))[1] = hsv[1]; SetValue(colorWheel, newValue); SetMethod(colorWheel, CHANGEDVALUE, changedValue); } else { ActivateColorWheel(colorWheel, false); } buttons = GetVar(colorBar, FULLCOMPBUTTONS); if (buttons) { buttonList = LISTOF(buttons); } else { buttonList = 0; } if (elements[0] > 0.0) { /*Active Slider and buttons*/ int index1, index2; int comp; changedValue = GetMethod(slider, CHANGEDVALUE); SetMethod(slider, CHANGEDVALUE, 0); ActivateSlider(slider, true); /*Get a value for the slider*/ index1 = elements[1]; index2 = elements[2]; if (elements[0] == 1.0) { comp = 0; } else { comp = 5 - (int) elements[0]; } ChoosePaletteSliderValue(slider, palette, comp, index1, index2); SetMethod(slider, CHANGEDVALUE, changedValue); /*Activate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, true); buttonList = buttonList -> next; } } else { /*Inactive Slider*/ ActivateSlider(slider, false); /*Deactivate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, false); buttonList = buttonList -> next; } } buttons = GetVar(colorBar, COMPBUTTONS); if (buttons) { buttonList = LISTOF(buttons); } else { buttonList = 0; } if (elements[0] > 1.0 && elements[2] > elements[1]) { /*Activate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, true); buttonList = buttonList -> next; } } else { /*Deactivate buttons*/ while (buttonList) { ActivateButton(buttonList -> thing, false); buttonList = buttonList -> next; } } button = GetVar(colorBar, FREEFORMBUTTON); if (elements[0] > 1.0) { if (button) { ActivateButton(button, true); } } else { if (button) { ActivateButton(button, false); } } ImInvalid(colorBar); return ObjTrue; } static ObjPtr ChangePaletteColorWheel(colorWheel) ObjPtr colorWheel; /*Changes a color wheel*/ { ObjPtr slider, colorBar, panel, button; PPtr palette; ObjPtr var; real h, s, v; real r, g, b; int rs, gs, bs; short3 *colors; int index1, index2, k; real *elements; slider = GetObjectVar("ChangePaletteColorWheel", colorWheel, SLIDER); colorBar = GetObjectVar("ChangePaletteColorWheel", colorWheel, COLORBAR); if (!slider || !colorBar) { return ObjFalse; } palette = (PPtr) GetPaletteVar("ChangePaletteColorWheel", colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetValue(colorBar); if (!var) { return ObjFalse; } if (((real *) ELEMENTS(var))[0] != 1.0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; var = GetValue(colorWheel); if (!var) { return ObjFalse; } h = ((real *) ELEMENTS(var))[0]; s = ((real *) ELEMENTS(var))[1]; var = GetValue(slider); if (!var) { return ObjFalse; } v = GetReal(var); HSV2RGB(&r, &g, &b, h, s, v); /*Change the palette. Tricky.*/ rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (rs > 255) rs = 255; else if (rs < 0) rs = 0; if (gs > 255) gs = 255; else if (gs < 0) gs = 0; if (bs > 255) rs = 255; else if (bs < 0) bs = 0; colors = palette -> colors; for (k = index1; k <= index2; ++k) { colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(colorWheel, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } SetVar(slider, TEMPPALETTE, ClonePalette((ObjPtr) palette)); /* interactiveMoving = false;*/ ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } static ObjPtr ChangePaletteSlider(slider) ObjPtr slider; /*Changes a palette's slider*/ { ObjPtr colorBar, panel, button; PPtr palette, tempPalette; ObjPtr var; short rs, gs, bs; short3 *colors, *tempColors; int index1, index2, k, comp; real sliderValue, initValue; real change; ObjPtr radio; ObjPtr colorWheel, hsObj; colorBar = GetObjectVar("ChangePaletteSlider", slider, COLORBAR); tempPalette = (PPtr) GetPaletteVar("ChangePaletteSlider", slider, TEMPPALETTE); if (!colorBar || !tempPalette) { return ObjFalse; } palette = (PPtr) GetPaletteVar("ChangePaletteSlider", colorBar, REPOBJ); if (!palette) { return ObjFalse; } colorWheel = GetObjectVar("ChangePaletteSlider", colorBar, COLORWHEEL); if (!colorWheel) { return ObjFalse; } var = GetRealVar("ChangePaletteSlider", slider, INITVALUE); if (var) { initValue = GetReal(var); } else { return ObjFalse; } var = GetValue(colorBar); if (!var) { return ObjFalse; } comp = 5 - ((real *) ELEMENTS(var))[0]; if (comp == 4) comp = 0; if (comp < 0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; var = GetValue(slider); if (!var) { return ObjFalse; } sliderValue = GetReal(var); colors = palette -> colors; tempColors = tempPalette -> colors; if (sliderValue < initValue) { /*Attenuate value*/ change = sliderValue / initValue; if (comp == 0) { /*Full color*/ real h, s, v, dummy; real r, g, b; for (k = index1; k <= index2; ++k) { r = tempColors[k][0] / 255.0; g = tempColors[k][1] / 255.0; b = tempColors[k][2] / 255.0; RGB2HSV(&h, &s, &v, r, g, b); if (index1 == index2) { hsObj = GetValue(colorWheel); if (!hsObj || !IsRealArray(hsObj) || RANK(hsObj) != 1 || DIMS(hsObj)[0] != 2) { return ObjFalse; } /*Single color, refresh value from wheel*/ h = ((real *) ELEMENTS(hsObj))[0]; s = ((real *) ELEMENTS(hsObj))[1]; v = sliderValue; } else { v *= change; } if (v > 1.0) v = 1.0; if (v < 0.0) v = 0.0; HSV2RGB(&r, &g, &b, h, s, v); rs = r * 255.0 + 0.5; gs = g * 255.0 + 0.5; bs = b * 255.0 + 0.5; colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); } else { real component; for (k = index1; k <= index2; ++k) { component = ((real) GetColorComponent(tempPalette, k, comp - 1)) / 255.0; component *= change; if (component > 1.0) component = 1.0; else if (component < 0.0) component = 0.0; SetColorComponent(palette, k, comp - 1, (int) (component * 255.0 + 0.5)); } CopyComponentsToColors(palette, index1, index2); } #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif } else { /*Brighten value*/ change = (1.0 - sliderValue) / (1.0 - initValue); if (comp == 0) { /*Full color*/ real h, s, v, dummy; real r, g, b; for (k = index1; k <= index2; ++k) { r = tempColors[k][0] / 255.0; g = tempColors[k][1] / 255.0; b = tempColors[k][2] / 255.0; RGB2HSV(&h, &s, &v, r, g, b); if (index1 == index2) { /*Single color, refresh value from wheel*/ hsObj = GetValue(colorWheel); if (!hsObj || !IsRealArray(hsObj) || RANK(hsObj) != 1 || DIMS(hsObj)[0] != 2) { return ObjFalse; } h = ((real *) ELEMENTS(hsObj))[0]; s = ((real *) ELEMENTS(hsObj))[1]; v = sliderValue; } else { v = 1.0 - (1.0 - v) * change; } if (v > 1.0) v = 1.0; if (v < 0.0) v = 0.0; HSV2RGB(&r, &g, &b, h, s, v); rs = r * 255.0 + 0.5; gs = g * 255.0 + 0.5; bs = b * 255.0 + 0.5; colors[k][0] = rs; colors[k][1] = gs; colors[k][2] = bs; } CopyColorsToComponents(palette, index1, index2); } else { real component; for (k = index1; k <= index2; ++k) { component = ((real) GetColorComponent(tempPalette, k, comp - 1)) / 255.0; component = 1.0 - (1.0 - component) * change; if (component > 1.0) component = 1.0; else if (component < 0.0) component = 0.0; SetColorComponent(palette, k, comp - 1, (int) (component * 255.0 + 0.5)); } CopyComponentsToColors(palette, index1, index2); } #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif } ResetColorBarTools(colorBar); SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(slider, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } /* interactiveMoving = false;*/ ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } static ObjPtr RevertButton(button) ObjPtr button; /*Reverts to last palette saved*/ { ObjPtr panel, repObj, keptPalette, colorBar, textBox, radio; repObj = GetPaletteVar("RevertButton", button, REPOBJ); if (!repObj) { return ObjFalse; } keptPalette = GetPaletteVar("RevertButton", repObj, KEPTPALETTE); if (!keptPalette) { return ObjFalse; } CopyPalette(repObj, keptPalette); SetVar(repObj, CHANGED, ObjTrue); ActivateButton(button, false); if (panel = GetObjectVar("RevertButton", button, PARENT)) { if (button = GetObjectVar("RevertButton", panel, KEEPBUTTON)) { ActivateButton(button, false); } } if (colorBar = GetObjectVar("RevertButton", panel, COLORBAR)) { ObjPtr var; real newValue[3]; InhibitLogging(true); newValue[0] = newValue[1] = newValue[2] = 0.0; var = NewRealArray(1, 3L); CArray2Array(var, newValue); SetValue(colorBar, var); InhibitLogging(false); } /*Change the text boxes*/ if (textBox = GetObjectVar("RevertButton", panel, NCOLORBOX)) { sprintf(tempStr, "%d", ((PPtr) repObj) -> nColors); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", panel, MINBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> min); SetValue(textBox, NewString(tempStr)); } if (textBox = GetObjectVar("RevertButton", panel, MAXBOX)) { sprintf(tempStr, "%g", ((PPtr) repObj) -> max); SetValue(textBox, NewString(tempStr)); } if (radio = GetObjectVar("RevertButton", panel, CMODELRADIO)) { FuncTyp method; method = GetMethod(radio, CHANGEDVALUE); SetMethod(radio, CHANGEDVALUE, (FuncTyp) 0); SetValue(radio, GetVar(repObj, COLORMODEL)); SetMethod(radio, CHANGEDVALUE, method); } ForAllVisWindows(ImInvalid); return ObjTrue; } static ObjPtr KeepButton(button) ObjPtr button; /*Reverts to last palette saved*/ { ObjPtr panel, repObj, keptPalette, colorBar; repObj = GetPaletteVar("KeepButton", button, REPOBJ); if (!repObj) { return ObjFalse; } keptPalette = GetPaletteVar("KeepButton", repObj, KEPTPALETTE); if (!keptPalette) { return ObjFalse; } CopyPalette(keptPalette, repObj); ActivateButton(button, false); if (panel = GetObjectVar("KeepButton", button, PARENT)) { if (button = GetObjectVar("KeepButton", panel, REVERTBUTTON)) { ActivateButton(button, false); } } return ObjTrue; } static void SimplePaletteFunction(whichFunc, palette, index1, index2, comp, colorBar) int whichFunc; PPtr palette; int index1, index2, comp; ObjPtr colorBar; /*Does a simple function on palette*/ { int k; real r1, g1, b1, r2, g2, b2, r3, g3, b3, r, g, b, c; int rs, gs, bs, cs; switch (whichFunc) { case PF_RAMP: /*Change the palette to a ramp*/ for (k = index1 + 1; k < index2; ++k) { if (comp == 0 || comp == 1) { c = ((k - index1) * (GetColorComponent(palette, index2, 0) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 0) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 0, cs); } if (comp == 0 || comp == 2) { c = ((k - index1) * (GetColorComponent(palette, index2, 1) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 1) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 1, cs); } if (comp == 0 || comp == 3) { c = ((k - index1) * (GetColorComponent(palette, index2, 2) / 255.0) + (index2 - k) * (GetColorComponent(palette, index1, 2) / 255.0)) / (index2 - index1); cs = c * 255.0; SetColorComponent(palette, k, 2, cs); } } break; case PF_REVERSE: for (k = 0; k < (index2 - index1 + 1) / 2; ++k) { int tempColor; if (comp == 0 || comp == 1) { /*First component*/ tempColor = GetColorComponent(palette, index2 - k, 0); SetColorComponent(palette, index2 - k, 0, GetColorComponent(palette, index1 + k, 0)); SetColorComponent(palette, index1 + k, 0, tempColor); } if (comp == 0 || comp == 2) { /*Secpmd component*/ tempColor = GetColorComponent(palette, index2 - k, 1); SetColorComponent(palette, index2 - k, 1, GetColorComponent(palette, index1 + k, 1)); SetColorComponent(palette, index1 + k, 1, tempColor); } if (comp == 0 || comp == 3) { /*Third component*/ tempColor = GetColorComponent(palette, index2 - k, 2); SetColorComponent(palette, index2 - k, 2, GetColorComponent(palette, index1 + k, 2)); SetColorComponent(palette, index1 + k, 2, tempColor); } } break; case PF_RUFFLE: { int left, right, bottom, top, l, r; long oldQuotient, newQuotient; double ddiff, majorWidth, minorWidth, halfSpace; real val; ObjPtr var; int nTics; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); l = left + CBLBORDER + 2 * CBBOXWIDTH + 2 * CBHGAP + 1; r = right - CBRBORDER - CBBOXWIDTH - CBHGAP - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min + 2 * halfSpace; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); minorWidth = majorWidth / nTics; l = index1; val = (l - 2) * ddiff / (palette -> nColors - 3); oldQuotient = val / minorWidth; for (r = l + 1; r <= index2; ++r) { val = (r - 2) * ddiff / (palette -> nColors - 3); newQuotient = val / minorWidth; if (newQuotient != oldQuotient || r == index2) { /*Time for a reversal*/ if (r == index2) ++r; oldQuotient = newQuotient; for (k = 0; k < (r - l) / 2; ++k) { int tempColor; if (comp == 0 || comp == 1) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 0); SetColorComponent(palette, r - 1 - k, 0, GetColorComponent(palette, l + k, 0)); SetColorComponent(palette, l + k, 0, tempColor); } if (comp == 0 || comp == 2) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 1); SetColorComponent(palette, r - 1 - k, 1, GetColorComponent(palette, l + k, 1)); SetColorComponent(palette, l + k, 1, tempColor); } if (comp == 0 || comp == 3) { /*Component*/ tempColor = GetColorComponent(palette, r - 1 - k, 2); SetColorComponent(palette, r - 1 - k, 2, GetColorComponent(palette, l + k, 2)); SetColorComponent(palette, l + k, 2, tempColor); } } l = r; } } } break; case PF_SMOOTH: if (index2 <= index1) break; r1 = (GetColorComponent(palette, index1, 0) + 0.5) / 255.0; g1 = (GetColorComponent(palette, index1, 1) + 0.5) / 255.0; b1 = (GetColorComponent(palette, index1, 2) + 0.5) / 255.0; r2 = (GetColorComponent(palette, index1 + 1, 0) + 0.5) / 255.0; g2 = (GetColorComponent(palette, index1 + 1, 1) + 0.5) / 255.0; b2 = (GetColorComponent(palette, index1 + 1, 2) + 0.5) / 255.0; for (k = index1 + 2; k < index2; ++k) { r3 = (GetColorComponent(palette, k + 1, 0) + 0.5) / 255.0; g3 = (GetColorComponent(palette, k + 1, 1) + 0.5) / 255.0; b3 = (GetColorComponent(palette, k + 1, 2) + 0.5) / 255.0; r = ((r1 + r3) * 0.5 + r2) * 0.5; g = ((g1 + g3) * 0.5 + g2) * 0.5; b = ((b1 + b3) * 0.5 + b2) * 0.5; rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (comp == 0 || comp == 1) { SetColorComponent(palette, k, 0, rs); } if (comp == 0 || comp == 2) { SetColorComponent(palette, k, 1, gs); } if (comp == 0 || comp == 3) { SetColorComponent(palette, k, 2, bs); } r1 = r2; r2 = r3; g1 = g2; g2 = g3; b1 = b2; b2 = b3; } break; case PF_SHARPEN: if (index2 <= index1) break; r1 = (GetColorComponent(palette, index1, 0) + 0.5) / 255.0; g1 = (GetColorComponent(palette, index1, 1) + 0.5) / 255.0; b1 = (GetColorComponent(palette, index1, 2) + 0.5) / 255.0; r2 = (GetColorComponent(palette, index1 + 1, 0) + 0.5) / 255.0; g2 = (GetColorComponent(palette, index1 + 1, 1) + 0.5) / 255.0; b2 = (GetColorComponent(palette, index1 + 1, 2) + 0.5) / 255.0; for (k = index1 + 2; k < index2; ++k) { r3 = (GetColorComponent(palette, k + 1, 0) + 0.5) / 255.0; g3 = (GetColorComponent(palette, k + 1, 1) + 0.5) / 255.0; b3 = (GetColorComponent(palette, k + 1, 2) + 0.5) / 255.0; r = r2 + (r2 - (r1 + r3) * 0.5) * 2.0; if (r > 1.0) r = 1.0; else if (r < 0.0) r = 0.0; g = g2 + (g2 - (g1 + g3) * 0.5) * 2.0; if (g > 1.0) g = 1.0; else if (g < 0.0) g = 0.0; b = b2 + (b2 - (b1 + b3) * 0.5) * 2.0; if (b > 1.0) b = 1.0; else if (b < 0.0) b = 0.0; rs = r * 255.0; gs = g * 255.0; bs = b * 255.0; if (comp == 0 || comp == 1) { SetColorComponent(palette, k, 0, rs); } if (comp == 0 || comp == 2) { SetColorComponent(palette, k, 1, gs); } if (comp == 0 || comp == 3) { SetColorComponent(palette, k, 2, bs); } r1 = r2; r2 = r3; g1 = g2; g2 = g3; b1 = b2; b2 = b3; } break; } CopyComponentsToColors(palette, index1, index2); } static ObjPtr SimpleFuncButton(button) ObjPtr button; /*Do a simple palette function*/ { ObjPtr colorBar, panel; PPtr palette; ObjPtr var; int whichFunc; int index1, index2, comp, k; colorBar = GetObjectVar("SimpleFuncButton", button, COLORBAR); if (!colorBar) { return ObjFalse; } var = GetIntVar("SimpleFuncButton", button, PALETTEFUNC); if (!var) { return ObjFalse; } whichFunc = GetInt(var); palette = (PPtr) GetPaletteVar("SimpleFuncButton", colorBar, REPOBJ); if (!palette) { return false; } var = GetValue(colorBar); if (!var) { return ObjFalse; } if (((real *) ELEMENTS(var))[0] < 1.0) { return ObjFalse; } index1 = ((real *) ELEMENTS(var))[1]; index2 = ((real *) ELEMENTS(var))[2]; if (((real *) ELEMENTS(var))[0] == 1.0) { comp = 0; } else { comp = 5 - (int) ((real *) ELEMENTS(var))[0]; } SimplePaletteFunction(whichFunc, palette, index1, index2, comp, colorBar); #ifdef GRAPHICS MapPaletteColors(palette, index1, index2); #endif SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); panel = GetVar(button, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } /* interactiveMoving = false;*/ InhibitLogging(true); ChangedValue(colorBar); InhibitLogging(false); ForAllVisWindows(ImInvalid); DrawMe(colorBar); return ObjTrue; } #ifdef PROTO void ActivateColorWheel(ObjPtr wheel, Bool whether) #else void ActivateColorWheel(wheel, whether) ObjPtr wheel; Bool whether; #endif /*Activates a color wheel*/ { SetVar(wheel, ACTIVATED, whether ? ObjTrue : ObjFalse); ImInvalid(wheel); } #ifdef PROTO static int GetColorComponent(PPtr palette, int whichColor, int comp) #else static int GetColorComponent(palette, whichColor, comp) PPtr palette; int whichColor; int comp; #endif /*Gets the color component comp from whichColor in palette*/ { return palette -> components[whichColor][comp]; } #ifdef PROTO static void SetColorComponent(PPtr palette, int whichColor, int comp, int cc) #else static void SetColorComponent(palette, whichColor, comp, cc) PPtr palette, int whichColor; int comp; int cc; #endif /*Changes component comp in whichColor of palette to cc*/ { real rgb[3], hsv[3], hls[3], yiq[3]; palette -> components[whichColor][comp] = cc; CopyComponentsToColors(palette, whichColor, whichColor); } ObjPtr ImposeColorFunction(colorBar) ObjPtr colorBar; /*Imposes a color function on colorBar. Function is given by EDITMODE Box is given by FUNCTIONBOX */ { ObjPtr value, var, palette, panel, button; real *elements; int comp; int index1, index2, k, cc; real beg, end, fieldVal; int min, max; int tool; int cm; value = GetValue(colorBar); if (!value) { return ObjFalse; } palette = GetPaletteVar("ImposeColorFunction", colorBar, REPOBJ); if (!palette) { return ObjFalse; } elements = ELEMENTS(value); if (elements[1] < 1.5) { /*Not on a component*/ return ObjFalse; } var = GetIntVar("ImposeColorFunction", colorBar, EDITMODE); if (!var) { return ObjFalse; } tool = GetInt(var); comp = 4 - elements[0]; index1 = elements[1] + 0.5; index2 = elements[2] + 0.5; var = GetVar(colorBar, FUNCTIONBOX); if (!var) { /*No box around function!*/ return ObjFalse; } elements = ELEMENTS(var); beg = elements[0]; end = elements[1]; min = elements[2] + 0.5; max = elements[3] + 0.5; var = GetVar(palette, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } for (k = index1; k <= index2; ++k) { fieldVal = GetColorValue(palette, k); while (fieldVal < beg) { fieldVal += end - beg; } while (fieldVal > end) { fieldVal -= end - beg; } fieldVal -= beg; fieldVal /= (end - beg); /*Now fieldVal is in [0, 1) */ switch (tool) { case PT_SINE: /*Sine function*/ cc = min + (max - min) * ((1.0 + rsin(fieldVal * 2.0 * M_PI)) * 0.5); break; case PT_TRIANGLE: /*Triangle function*/ if (fieldVal < 0.25) { cc = (max + min) / 2 + fieldVal * 2.0 * (max - min); } else if (fieldVal > 0.75) { cc = min + (fieldVal - 0.75) * 2.0 * (max - min); } else { cc = min + (0.75 - fieldVal) * 2.0 * (max - min); } break; case PT_SAWTOOTH: /*Sawtooth function*/ cc = min + fieldVal * (max - min); break; case PT_TOOTHSAW: /*Toothsaw function*/ cc = max - fieldVal * (max - min); break; case PT_SQUARE: /*Square wave function*/ if (fieldVal < 0.5) { cc = max; } else { cc = min; } break; default: cc = 0; } SetColorComponent((PPtr) palette, k, comp, cc); } CopyComponentsToColors((PPtr) palette, index1, index2); MapPaletteColors((PPtr) palette, index1, index2); panel = GetVar(colorBar, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ChangedValue(colorBar); return ObjTrue; } static ObjPtr ChangeColorTool(group) ObjPtr group; /*Changes a color tool in response to a radio button group*/ { ObjPtr colorBar; PPtr palette; ObjPtr value; ObjPtr var; int tool; ObjPtr selection; real *elements; colorBar = GetObjectVar("ChangeColorTool", group, REPOBJ); if (!colorBar) { return ObjFalse; } selection = GetValue(colorBar); elements = ELEMENTS(selection); palette = (PPtr) GetPaletteVar("ChangeColorTool", colorBar, REPOBJ); if (!palette) { return ObjFalse; } value = GetValue(group); if (!value) { return false; } tool = GetInt(value); var = GetVar(colorBar, EDITMODE); if (var && GetInt(var) == tool) { /*Don't need to do anything*/ return ObjFalse; } SetVar(colorBar, EDITMODE, NewInt(tool)); if (tool > 0) { /*It's a function.*/ var = GetVar(colorBar, FUNCTIONBOX); if (!var) { /*Calculate initial function box*/ int left, right, bottom, top, l, r, b, t; double majorWidth; double halfSpace; double start, finish, middle, ddiff; int nTics; long temp; Get2DIntBounds(colorBar, &left, &right, &bottom, &top); l = left + CBLBORDER + 1; r = right - CBRBORDER - 1; halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; start = GetColorValue((ObjPtr) palette, (int) elements[1]) - halfSpace; finish = GetColorValue((ObjPtr) palette, (int) elements[2]) + halfSpace; middle = (start + finish) * 0.5; ddiff = finish - start; CalcGoodSteps(ddiff, r - l, CBSTEPPIXELS, &majorWidth, &nTics); /*Minor and major tics first*/ temp = middle / majorWidth; start = temp * majorWidth; finish = start + majorWidth; var = NewRealArray(1, 4L); ((real *) ELEMENTS(var))[0] = start - majorWidth; ((real *) ELEMENTS(var))[1] = finish; ((real *) ELEMENTS(var))[2] = 0.0; ((real *) ELEMENTS(var))[3] = 255.0; InhibitLogging(true); SetFunctionBox(colorBar, var); InhibitLogging(false); } InhibitLogging(true); ImposeColorFunction(colorBar); SetVar((ObjPtr) palette, JUSTCOLORCHANGE, ObjTrue); ForAllVisWindows(ImInvalid); InhibitLogging(false); } else { /*No function box*/ InhibitLogging(true); SetFunctionBox(colorBar, NULLOBJ); InhibitLogging(false); } ImInvalid(colorBar); return ObjTrue; } static ObjPtr MakePaletteBarHelp(colorBar, class) ObjPtr colorBar; ObjPtr class; /*Makes help for a color bar*/ { ObjPtr help, temp; ObjPtr var; int editMode; real *elements; help = NewString("This control shows a color palette. The color bar at \ the bottom shows the range of colors in the palette associated with the field \ values, plus colors for missing data, overflow, and underflow values. \ Above the color bar are three bars showing the magnitude of the three components \ of each color, plus a magnified readout at the top.\n\ \n\ You can select a range of colors to edit by clicking in the color bar or one of the \ three component bars and dragging through the colors you want to edit. When you \ select a range, controls in the window that can edit the color will become active. \ Also, the selected range will be expanded to fill the magnified readout at the top of the control. \ When a color component is selected, you can edit it using the Edit Component \ buttons to the left."); var = GetValue(colorBar); if (var) { elements = ELEMENTS(var); if (elements[0] > 1.5) { /*A component is selected*/ var = GetIntVar("MakePaletteBarHelp", colorBar, EDITMODE); if (var) { ObjPtr palette; int cm; editMode = GetInt(var); palette = GetVar(colorBar, REPOBJ); if (!palette) { return ObjFalse; } var = GetVar(palette, COLORMODEL); if (var) { cm = GetInt(var); } else { cm = CM_RGB; } sprintf(tempStr, "\n\nThe %s components of a range of colors are \ currently selected. The Intensity slider on the left lets you change the brightness \ of this component of the range. The buttons at the top of the window let you \ perform some simple functions over the entire range of colors. Use Help In \ Context to find out what each of these buttons does.\n\n", componentNames[cm][4 - (int) (elements[0] + 0.5)]); temp = NewString(tempStr); help = ConcatStrings(help, temp); if (editMode == PT_FREEFORM) { /*Free form tool*/ temp = NewString("The free form tool is selected. \ You can modify the waveform shown at the top of the control by clicking and drawing \ within the box. The Shift key will constrain motion in just the vertical or \ horizontal direction.\n"); help = ConcatStrings(help, temp); } else { /*Waveform tool*/ sprintf(tempStr, "The %s tool is selected. Notice \ that there is a yellow box within the magnified readout at \ the top of the control. This box encloses one period of a %s which is used \ to fill the entire selected range of the component. ", toolNames[editMode], toolNames[editMode]); temp = NewString(tempStr); help = ConcatStrings(help, temp); temp = NewString("Click and drag the square \ handles on the top or bottom to change the minimum and maximum values of the wave. Click \ Click and drag the handles on the left or right to change the beginning and end \ of the wave as well as its wavelength. The Shift key will constrain motion to \ the nearest tic mark. Click and drag within the box to move the entire waveform \ left or right."); help = ConcatStrings(help, temp); } } } else if (elements[0] > 0.5) { temp = NewString("\n\nA range of colors is \ currently selected. The Intensity slider on the left lets you change the brightness \ of this component of the range. The Hue/Saturation color wheel lets you change \ the hue and saturation of the entire range. When you click on this \ control, the entire range will become a single color. \ The buttons at the top of the window let you \ perform some simple functions over the entire range of colors. Use Help In \ Context to find out what each of these buttons does."); help = ConcatStrings(help, temp); } } SetVar(class, HELPSTRING, help); return ObjTrue; } static ObjPtr EnterMin(box) ObjPtr box; /*Enters the minimum value from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; float min; char *s; FuncTyp method; value = GetValue(box); if (!value) { return ObjFalse; } s = GetString(value); if (!ParseReal(&min, s)) { return ObjFalse; } #if 0 if (min <= minusInf || min >= plusInf) { DoUniqueTask(DoInfinityError); return ObjFalse; } #endif if (min == missingData) { DoUniqueTask(DoMissingError); } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (min >= palette -> max) { DoUniqueTask(DoRangeError); return ObjFalse; } palette -> min = min; ReinitColorBar(colorBar); ImInvalid(colorBar); SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } return ObjTrue; } static ObjPtr EnterMax(box) ObjPtr box; /*Enters the max value from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; float max; FuncTyp method; value = GetValue(box); if (!value) { return ObjFalse; } if (!ParseReal(&max, GetString(value))) { DoUniqueTask(DoNumberError); return ObjFalse; } if (max <= minusInf || max >= plusInf) { DoUniqueTask(DoInfinityError); return ObjFalse; } if (max == missingData) { DoUniqueTask(DoMissingError); } colorBar = GetObjectVar("EnterMin", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (max <= palette -> min) { DoUniqueTask(DoRangeError); return ObjFalse; } palette -> max = max; SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); ReinitColorBar(colorBar); ImInvalid(colorBar); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } return ObjTrue; } static ObjPtr EnterNColors(box) ObjPtr box; /*Enters the number of colors from box*/ { ObjPtr value, colorBar, panel, button; PPtr palette; int nColors; real *elements; int oldNColors; value = GetValue(box); if (!value) { return ObjFalse; } if (!ParseInteger(&nColors, GetString(value))) { DoUniqueTask(DoNumberError); return ObjFalse; } colorBar = GetObjectVar("EnterNColors", box, REPOBJ); if (!colorBar) { return ObjFalse; } palette = (PPtr) GetVar(colorBar, REPOBJ); if (!palette) { return ObjTrue; } if (nColors < 5 || nColors > 2048) { DoUniqueTask(DoWrongNColorsError); return ObjFalse; } oldNColors = palette -> nColors; SetPaletteNColors((ObjPtr) palette, nColors); SetVar((ObjPtr) palette, CHANGED, ObjTrue); ForAllVisWindows(ImInvalid); panel = GetVar(box, PARENT); if (panel) { button = GetVar(panel, KEEPBUTTON); if (button) { ActivateButton(button, true); } button = GetVar(panel, REVERTBUTTON); if (button) { ActivateButton(button, true); } } value = GetValue(colorBar); if (value) { real newValue[4]; elements = ELEMENTS(value); newValue[0] = elements[0]; newValue[1] = elements[1]; newValue[2] = elements[2]; newValue[3] = elements[3]; if (elements[0] > 0.5) { int k; for (k = 1; k <=2; ++k) { if (((int) elements[k] + 0.5) >= oldNColors - 1) { newValue[k] = nColors - 1; } else if (((int) elements[k] + 0.5) > 1) { newValue[k] = 2.0 + (elements[k] - 2.0) * (nColors - 3) / (oldNColors - 3); if (((int) newValue[k] + 0.5) >= nColors - 1) { newValue[k] = nColors - 2.0; } if (((int) newValue[k] + 0.5) < 2) { newValue[k] = 2.0; } } } if (newValue[3] <= newValue[2]) newValue[3] += 1.0; } value = NewRealArray(1, 3L); CArray2Array(value, newValue); InhibitLogging(true); SetValue(colorBar, value); InhibitLogging(false); } return ObjTrue; } ObjPtr ChangeTextColorWheel(wheel) ObjPtr wheel; /*Changes text colors according to a color wheel*/ { ObjPtr repObj, slider; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeTextColorWheel", wheel, REPOBJ); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeTextColorWheel", wheel, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, COLOR, value); ImInvalid(repObj); return ObjTrue; } ObjPtr ChangeTextColorSlider(slider) ObjPtr slider; /*Changes text color according to a color slider*/ { ObjPtr repObj, wheel; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeTextColorWheel", slider, REPOBJ); if (!repObj) { return ObjFalse; } wheel = GetObjectVar("ChangeTextColorWheel", slider, COLORWHEEL); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, COLOR, value); ImInvalid(repObj); return ObjTrue; } ObjPtr ChangeBackgroundColorWheel(wheel) ObjPtr wheel; /*Changes text colors according to a color wheel*/ { ObjPtr repObj, slider, checkBox; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorWheel", wheel, REPOBJ); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeBackgroundColorWheel", wheel, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); checkBox = GetVar(wheel, CHECKBOX); if (checkBox) { FuncTyp method; method = GetMethod(checkBox, CHANGEDVALUE); SetMethod(checkBox, CHANGEDVALUE, 0); InhibitLogging(true); SetValue(checkBox, NewInt(0)); InhibitLogging(false); SetMethod(checkBox, CHANGEDVALUE, method); } return ObjTrue; } ObjPtr ChangeBackgroundColorSlider(slider) ObjPtr slider; /*Changes background color according to a color slider*/ { ObjPtr repObj, wheel, checkBox; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorSlider", slider, REPOBJ); if (!repObj) { return ObjFalse; } wheel = GetObjectVar("ChangeBackgroundColorSlider", slider, COLORWHEEL); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); checkBox = GetVar(slider, CHECKBOX); if (checkBox) { FuncTyp method; method = GetMethod(checkBox, CHANGEDVALUE); SetMethod(checkBox, CHANGEDVALUE, 0); InhibitLogging(true); SetValue(checkBox, NewInt(0)); InhibitLogging(false); SetMethod(checkBox, CHANGEDVALUE, method); } return ObjTrue; } static ObjPtr ChangeColorByPalette(checkBox) ObjPtr checkBox; /*Changes an object's COLORBYFIELD according to checkBox*/ { ObjPtr repObj, value; repObj = GetObjectVar("ChangeColorByPalette", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } value = GetValue(checkBox); if (!value) { return ObjFalse; } SetVar(repObj, COLORBYFIELD, value); ImInvalid(repObj); return ObjFalse; } ObjPtr ChangeNoBackground(checkBox) ObjPtr checkBox; /*Changes background color according to a check box*/ { ObjPtr repObj, wheel, slider; ObjPtr value; real hsv[3], rgb[3]; repObj = GetObjectVar("ChangeBackgroundColorSlider", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } value = GetValue(checkBox); if (!value) { return ObjFalse; } if (GetInt(value)) { SetVar(repObj, BACKGROUND, NULLOBJ); ImInvalid(repObj); return ObjTrue; } wheel = GetObjectVar("ChangeBackgroundColorSlider", checkBox, COLORWHEEL); if (!repObj) { return ObjFalse; } slider = GetObjectVar("ChangeBackgroundColorSlider", checkBox, SLIDER); if (!repObj) { return ObjFalse; } value = GetValue(wheel); if (!value) { return ObjFalse; } Array2CArray(hsv, value); value = GetValue(slider); if (!value) { return ObjFalse; } hsv[2] = GetReal(value); HSV2RGB(&(rgb[0]), &(rgb[1]), &(rgb[2]), hsv[0], hsv[1], hsv[2]); value = NewRealArray(1, 3L); CArray2Array(value, rgb); SetVar(repObj, BACKGROUND, value); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowMissing(checkBox) ObjPtr checkBox; /*Changes the SHOWMISSING according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowMissing", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWMISSING, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowOverUnder(checkBox) ObjPtr checkBox; /*Changes the SHOWOVERUNDER according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowOverUnder", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWOVERUNDER, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeShowMinorTics(checkBox) ObjPtr checkBox; /*Changes the SHOWMINORTICS according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeShowMinorTics", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, SHOWMINORTICS, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ChangeNumbersOnly(checkBox) ObjPtr checkBox; /*Changes the NUMBERSONLY according to a checkbox*/ { ObjPtr repObj; repObj = GetObjectVar("ChangeNumbersOnly", checkBox, REPOBJ); if (!repObj) { return ObjFalse; } SetVar(repObj, NUMBERSONLY, GetValue(checkBox)); ImInvalid(repObj); return ObjTrue; } static ObjPtr ShowPaletteDisplayControls(display, 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; real rgb[3], hsv[3]; 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*/ GetWindowBounds(&left, &right, &bottom, &top); panel = NewPanel(greyPanelClass, 0, right - left, 0, top - bottom); 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; /*Get the color for priming the controls*/ var = GetVar(display, COLOR); if (IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3) { Array2CArray(rgb, var); } else if (IsInt(var)) { rgb[0] = uiColors[GetInt(var)][0] / 255.0; rgb[1] = uiColors[GetInt(var)][1] / 255.0; rgb[2] = uiColors[GetInt(var)][2] / 255.0; } else { ReportError("ShowPaletteDisplayControls", "Bad color"); rgb[0] = rgb[1] = rgb[2] = 1.0; } RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), (rgb[0]), (rgb[1]), (rgb[2])); /*Make the color wheel*/ colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH, top, "Text Color"); var = NewRealArray(1, 2L); CArray2Array(var, hsv); SetValue(colorWheel, var); SetVar(colorWheel, PARENT, panel); SetVar(colorWheel, REPOBJ, display); PrefixList(contents, colorWheel); SetMethod(colorWheel, CHANGEDVALUE, ChangeTextColorWheel); 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); SetSliderValue(slider, hsv[2]); SetVar(slider, REPOBJ, display); SetMethod(slider, CHANGEDVALUE, ChangeTextColorSlider); 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 - MINORBORDER, right + MINORBORDER, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Text Value Label", "Value"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); /*Cross link the slider and color wheel*/ SetVar(colorWheel, SLIDER, slider); SetVar(slider, COLORWHEEL, colorWheel); left -= MINORBORDER; right += MINORBORDER; /*Make the check box*/ top -= COLORWHEELWIDTH + TEXTBOXSEP + TEXTBOXHEIGHT + MINORBORDER; checkBox = NewCheckBox(left, right, top - CHECKBOXHEIGHT, top, "Color text by palette", GetPredicate(display, COLORBYFIELD)); SetVar(checkBox, PARENT, panel); SetVar(checkBox, REPOBJ, display); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeColorByPalette); SetVar(colorWheel, 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; /*Get the color for priming the controls*/ var = GetVar(display, BACKGROUND); if (var && IsRealArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3) { Array2CArray(rgb, var); hasBackground = true; } else if (var && IsInt(var)) { rgb[0] = uiColors[GetInt(var)][0] / 255.0; rgb[1] = uiColors[GetInt(var)][1] / 255.0; rgb[2] = uiColors[GetInt(var)][2] / 255.0; hasBackground = true; } else { rgb[0] = rgb[1] = rgb[2] = 0.5; hasBackground = false; } RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), (rgb[0]), (rgb[1]), (rgb[2])); /*Make the color wheel*/ colorWheel = NewColorWheel(left, left + COLORWHEELWIDTH, top - COLORWHEELWIDTH, top, "Background Color"); var = NewRealArray(1, 2L); CArray2Array(var, hsv); SetValue(colorWheel, var); SetVar(colorWheel, PARENT, panel); SetVar(colorWheel, REPOBJ, display); PrefixList(contents, colorWheel); SetMethod(colorWheel, CHANGEDVALUE, ChangeBackgroundColorWheel); 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); SetSliderValue(slider, hsv[2]); SetVar(slider, REPOBJ, display); SetMethod(slider, CHANGEDVALUE, ChangeBackgroundColorSlider); 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 - MINORBORDER, right + MINORBORDER, top - COLORWHEELWIDTH - TEXTBOXSEP - TEXTBOXHEIGHT, top - COLORWHEELWIDTH - TEXTBOXSEP, PLAIN, "Background Value Label", "Value"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, CENTERALIGN); /*Cross link the slider and color wheel*/ SetVar(colorWheel, SLIDER, slider); SetVar(slider, COLORWHEEL, colorWheel); 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); SetVar(checkBox, REPOBJ, display); SetVar(checkBox, SLIDER, slider); SetVar(checkBox, COLORWHEEL, colorWheel); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeNoBackground); 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.")); /*Link the checkbox to the slider and color wheel*/ SetVar(colorWheel, CHECKBOX, checkBox); SetVar(slider, CHECKBOX, checkBox); 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)); SetVar(checkBox, PARENT, panel); SetVar(checkBox, REPOBJ, display); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeShowMissing); SetVar(colorWheel, 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); SetVar(checkBox, REPOBJ, display); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeShowOverUnder); SetVar(colorWheel, 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); SetVar(checkBox, REPOBJ, display); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeShowMinorTics); SetVar(colorWheel, 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); SetVar(checkBox, REPOBJ, display); PrefixList(contents, checkBox); SetMethod(checkBox, CHANGEDVALUE, ChangeNumbersOnly); SetVar(colorWheel, 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; } static ObjPtr ChangeColorModel(radio) ObjPtr radio; /*Changes the color model based on the value of a radio group*/ { ObjPtr colorBar, palette; ObjPtr value; colorBar = GetObjectVar("ChangeColorModel", radio, REPOBJ); if (!colorBar) { return ObjFalse; } palette = GetVar(colorBar, REPOBJ); if (!colorBar) { return ObjFalse; } value = GetValue(radio); if (!value || !IsInt(value)) { return ObjFalse; } SetVar(palette, COLORMODEL, value); CopyColorsToComponents((PPtr) palette, 0, ((PPtr) palette) -> nColors - 1); ChangedValue(colorBar); ImInvalid(colorBar); /*Set the edit tool to free form*/ ResetColorBarTools(colorBar); return ObjTrue; } 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; dialogExists = DialogExists((WinInfoPtr) palette, NewString("Controls")); controlWindow = GetDialog((WinInfoPtr) palette, NewString("Controls"), windowName, PCWINWIDTH, PCWINHEIGHT, PCWINWIDTH, PCWINHEIGHT, WINDBUF + WINRGB + WINFIXEDSIZE); if (!dialogExists) { long info; ObjPtr value; ObjPtr checkBox, icon, name, colorBar, titleBox, textBox, button; ObjPtr colorWheel, slider, fullCompList, compList, radioGroup; char numBuf[200]; int left, right, bottom, top; char *s; /*Add some menu item*/ DefineMenuItem((ObjPtr) controlWindow, FILEMENU, "Save Palette", DoSaveObject); 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*/ GetWindowBounds(&left, &right, &bottom, &top); panel = NewPanel(greyPanelClass, 0, right - left, 0, top - bottom); 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 = NewColorBar(left, right, bottom, top, "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*/ /*Put in the min and max text boxes below*/ sprintf(numBuf, "%g", ((PPtr) palette) -> min); textBox = NewTextBox(left + CBLBORDER + CBLTEXTSPACE + 3 * CBHGAP + 2 * CBBOXWIDTH - PCTEXTBOXLEN / 2, left + CBLBORDER + CBLTEXTSPACE + 3 * CBHGAP + 2 * CBBOXWIDTH + PCTEXTBOXLEN / 2, MAJORBORDER, MAJORBORDER + EDITBOXHEIGHT, EDITABLE + WITH_PIT + ONE_LINE, "Field Min", numBuf); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, REPOBJ, colorBar); SetVar(panel, MINBOX, textBox); 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.")); SetMethod(textBox, CHANGEDVALUE, EnterMin); /*Min legend*/ textBox = NewTextBox(left, left + CBLBORDER + CBLTEXTSPACE + 3 * CBHGAP + 2 * CBBOXWIDTH - PCTEXTBOXLEN / 2 - MINORBORDER, MAJORBORDER, MAJORBORDER + TEXTBOXHEIGHT + 3, 0, "Field Min Legend", "Minimum:"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); /*Max text box*/ sprintf(numBuf, "%g", ((PPtr) palette) -> max); textBox = NewTextBox(right - CBRBORDER - CBHGAP - CBBOXWIDTH - PCTEXTBOXLEN / 2, right - CBRBORDER - CBHGAP - CBBOXWIDTH + PCTEXTBOXLEN / 2, MAJORBORDER, MAJORBORDER + EDITBOXHEIGHT, EDITABLE + WITH_PIT + ONE_LINE, "Field Max", numBuf); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, REPOBJ, colorBar); SetVar(panel, MAXBOX, textBox); 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.")); SetMethod(textBox, CHANGEDVALUE, EnterMax); /*Max legend*/ textBox = NewTextBox(right - CBRBORDER - CBHGAP - CBBOXWIDTH - MINORBORDER - PCTEXTBOXLEN / 2 - PCTEXTBOXLEN, right - CBRBORDER - CBHGAP - CBBOXWIDTH - MINORBORDER - PCTEXTBOXLEN / 2, MAJORBORDER, MAJORBORDER + TEXTBOXHEIGHT + 3, 0, "Field Max Legend", "Maximum:"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); /*nColors text box*/ sprintf(numBuf, "%d", ((PPtr) palette) -> nColors); left = MAJORBORDER; textBox = NewTextBox(left, left + PCTEXTBOXLEN, MAJORBORDER, MAJORBORDER + EDITBOXHEIGHT, EDITABLE + WITH_PIT + ONE_LINE, "N Colors", numBuf); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); SetTextAlign(textBox, RIGHTALIGN); SetVar(textBox, REPOBJ, colorBar); SetVar(panel, NCOLORBOX, textBox); 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.")); SetMethod(textBox, CHANGEDVALUE, EnterNColors); /*nColors legend*/ textBox = NewTextBox(left + PCTEXTBOXLEN + MINORBORDER, left + 2 * PCTEXTBOXLEN, MAJORBORDER, MAJORBORDER + TEXTBOXHEIGHT + 4, 0, "NColors Legend", "Colors"); SetVar(textBox, PARENT, panel); PrefixList(contents, textBox); /*Add in the left color control group*/ left = MAJORBORDER; right = left + PCWINLSIDE; top = PCWINHEIGHT - MAJORBORDER; /*Revert to saved*/ bottom = top - BUTTONHEIGHT; button = NewButton(left, right, bottom, top, "Revert"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetVar(panel, REVERTBUTTON, button); SetVar(button, HELPSTRING, NewString("The palette window saves the original palette. If you have \ made changes that you do not want to keep, press the Revert button to make the \ palette revert back to the way it was. If you have made changes that you are sure \ you want to keep, press the Keep Changes button to keep them. From then on, the \ Revert button will make the palette revert to the palette including the \ changes you have kept.")); SetVar(button, HALTHELP, ObjTrue); ActivateButton(button, false); SetMethod(button, CHANGEDVALUE, RevertButton); top = bottom - MINORBORDER; /*Keep changes*/ bottom = top - BUTTONHEIGHT; button = NewButton(left, right, bottom, top, "Keep Changes"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetVar(panel, KEEPBUTTON, button); SetVar(button, HELPSTRING, NewString("The palette window saves the original palette. If you have \ made changes that you do not want to keep, press the Revert button to make the \ palette revert back to the way it was. If you have made changes that you are sure \ you want to keep, press the Keep Changes button to keep them. From then on, the \ Revert button will make the palette revert to the palette including the \ changes you have kept.")); SetVar(button, HALTHELP, ObjTrue); ActivateButton(button, false); SetMethod(button, CHANGEDVALUE, KeepButton); top = bottom - MAJORBORDER; SetVar(palette, KEPTPALETTE, ClonePalette(palette)); bottom = MAJORBORDER + PCBARUP; top = bottom + COLORWHEELWIDTH + TEXTBOXHEIGHT + TEXTBOXSEP; /*Color wheel*/ colorWheel = NewColorWheel(left + MINORBORDER, left + MINORBORDER + COLORWHEELWIDTH, bottom + TEXTBOXHEIGHT + TEXTBOXSEP, top, "Hue/Saturation"); 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 = NewTextBox( left + MINORBORDER - MAJORBORDER , left + MAJORBORDER + MINORBORDER + COLORWHEELWIDTH, bottom, bottom + TEXTBOXHEIGHT, 0, "HS Text", "Hue/Saturation"); PrefixList(contents, textBox); SetVar(textBox, PARENT, panel); SetTextAlign(textBox, CENTERALIGN); /*Slider*/ slider = NewSlider(right - MINORBORDER - SLIDERWIDTH, right - MINORBORDER, bottom + TEXTBOXHEIGHT + TEXTBOXSEP, top, PLAIN, "Intensity"); 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 = NewTextBox(right - MINORBORDER - MAJORBORDER - SLIDERWIDTH, right - MINORBORDER + MAJORBORDER, bottom, bottom + TEXTBOXHEIGHT, 0, "Intensity Text", "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 + 3 * MINORBORDER + 2 * ICONBUTTONSIZE); titleBox = NewTitleBox(left, right, bottom, top, "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 = NewIconButton(left, left + ICONBUTTONSIZE, top - ICONBUTTONSIZE, top, ICONFREEFORM, UIYELLOW, "Free form", 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 = NewIconButton((right + left - ICONBUTTONSIZE) / 2, (right + left + ICONBUTTONSIZE) / 2, top - ICONBUTTONSIZE, top, ICONSINE, UIYELLOW, "Sine", 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 = NewIconButton(right - ICONBUTTONSIZE, right, top - ICONBUTTONSIZE, top, ICONTRIANGLE, UIYELLOW, "Triangle", 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 = NewIconButton(left, left + ICONBUTTONSIZE, top - 2 * ICONBUTTONSIZE - MINORBORDER, top - ICONBUTTONSIZE - MINORBORDER, ICONSAWTOOTH, UIYELLOW, "Sawtooth", 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 = NewIconButton((right + left - ICONBUTTONSIZE) / 2, (right + left + ICONBUTTONSIZE) / 2, top - 2 * ICONBUTTONSIZE - MINORBORDER, top - ICONBUTTONSIZE - MINORBORDER, ICONTOOTHSAW, UIYELLOW, "Toothsaw", 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 = NewIconButton(right - ICONBUTTONSIZE, right, top - 2 * ICONBUTTONSIZE - MINORBORDER, top - ICONBUTTONSIZE - MINORBORDER, ICONSQUARE, UIYELLOW, "Square", 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); /*Color model controls*/ left -= MINORBORDER; right += MINORBORDER; top = top - 2 * ICONBUTTONSIZE - 3 * MINORBORDER; bottom = top - TITLEBOXTOP - 2 * MINORBORDER - 2 * CHECKBOXHEIGHT - CHECKBOXSPACING; titleBox = NewTitleBox(left, right, bottom, top, "Color Model"); PrefixList(contents, titleBox); SetVar(titleBox, PARENT, panel); /*Create the radio button group*/ radioGroup = NewRadioButtonGroup("Color Models"); SetVar(radioGroup, PARENT, panel); SetVar(panel, CMODELRADIO, radioGroup); PrefixList(contents, radioGroup); SetVar(radioGroup, REPOBJ, colorBar); SetVar(radioGroup, HELPSTRING, NewString("This group controls which color model the palette editor \ uses. It will affect the information shown in the three color component bars \ in the color bar. SciAn always uses the RGB color model internally and converts \ to the selected color model for editing.")); /*And the individual radio buttons*/ left += MINORBORDER; right -= MINORBORDER; top -= TITLEBOXTOP + MINORBORDER; bottom += MINORBORDER; button = NewRadioButton(left, left + (right - left) / 2, top - CHECKBOXHEIGHT, top, "RGB"); AddRadioButton(radioGroup, button); SetVar(button, HELPSTRING, NewString("This button selects the RGB color model. In this model, \ color is composed of red, green, and blue components, which are added together \ to produce the final color.")); button = NewRadioButton(left, left + (right - left) / 2, bottom, bottom + CHECKBOXHEIGHT, "YIQ"); AddRadioButton(radioGroup, button); SetVar(button, HELPSTRING, NewString("This button selects the YIQ color model. This color \ model is exactly the same model used to encode NTSC composite television \ signals. This color model uses properties of the visual system to optimize \ the amount of information that can be transmitted in the fixed bandwidth of \ the NTSC composite signal.\n\nWARNING: Not all possible YIQ combinations encode \ into valid RGB combinations. This will only be apparent after you have edited the \ color components in the YIQ model, switch to another color model, and switch back.")); button = NewRadioButton(left + (right - left) / 2, right, top - CHECKBOXHEIGHT, top, "HSV"); AddRadioButton(radioGroup, button); SetVar(button, HELPSTRING, NewString("This button selects the HSV color model. In this model, \ color is composed of hue, saturation, and value. The hue and saturation control \ the shade of the color, and the value controls its intensity. This color model \ is used by the color wheels and intensity sliders in SciAn.")); button = NewRadioButton(left + (right - left) / 2, right, bottom, bottom + CHECKBOXHEIGHT, "HLS"); AddRadioButton(radioGroup, button); SetVar(button, HELPSTRING, NewString("This button selects the HLS color model. In this model, \ color is composed of hue, lightness, and saturation. Hue and saturation control the \ basic shade of the color. Lightness controls how much black or white is mixed in \ with the color.")); var = GetIntVar("ShowPaletteControls", palette, COLORMODEL); if (var) { SetValue(radioGroup, var); } SetMethod(radioGroup, CHANGEDVALUE, ChangeColorModel); /*Center controls*/ left = PCWINLSIDE + MAJORBORDER * 2; right = PCWINLSIDE + MAJORBORDER * 2 + (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; top = PCWINHEIGHT - MAJORBORDER; bottom = top - BUTTONHEIGHT; /*Ramp button*/ button = NewButton(left, right, bottom, top, "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); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Reverse button*/ button = NewButton(left, right, bottom, top, "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); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Next column of center controls*/ left = PCWINLSIDE + MAJORBORDER * 2 + MINORBORDER + (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; right = PCWINLSIDE + MAJORBORDER * 2 + MINORBORDER + 2 * (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; top = PCWINHEIGHT - MAJORBORDER; bottom = top - BUTTONHEIGHT; /*Smooth button*/ button = NewButton(left, right, bottom, top, "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); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Sharpen button*/ button = NewButton(left, right, bottom, top, "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); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Next column of center controls*/ left = PCWINLSIDE + MAJORBORDER * 2 + 2 * MINORBORDER + 2 * (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; right = PCWINLSIDE + MAJORBORDER * 2 + 2 * MINORBORDER + 3 * (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; top = PCWINHEIGHT - MAJORBORDER; bottom = top - BUTTONHEIGHT; /*Ruffle button*/ button = NewButton(left, right, bottom, top, "Ruffle"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_RUFFLE)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button ruffles the selected colors, which means \ that it reverses short ranges of colors through the selected colors. This produces \ an effect similar to contours while maintaining a range of colors for the entire \ field. It is especially successful in windows set to Color Map mode. \ When a range in the full color bar is \ selected, all components will be ruffled. When a range of a single component \ is selected, just that component will be ruffled.\n")); SetVar(button, HALTHELP, ObjTrue); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; #if 0 /*Extra button*/ button = NewButton(left, right, bottom, top, "Extra"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_RUFFLE)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button performs the whatever function. \ When a range in the full color bar is \ selected, all components will be whatevered. When a range of a single component \ is selected, just that component will be whatevered.\n")); SetVar(button, HALTHELP, ObjTrue); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Last column of center controls*/ left = PCWINLSIDE + MAJORBORDER * 2 + 3 * MINORBORDER + 3 * (PCWINWIDTH - 3 * MAJORBORDER - PCWINLSIDE - 3 * MINORBORDER) / 4; right = PCWINWIDTH - MAJORBORDER; top = PCWINHEIGHT - MAJORBORDER; bottom = top - BUTTONHEIGHT; /*Extra button*/ button = NewButton(left, right, bottom, top, "Extra"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_RUFFLE)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button performs the whatever function. \ When a range in the full color bar is \ selected, all components will be whatevered. When a range of a single component \ is selected, just that component will be whatevered.\n")); SetVar(button, HALTHELP, ObjTrue); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; /*Extra button*/ button = NewButton(left, right, bottom, top, "Extra"); PrefixList(contents, button); SetVar(button, PARENT, panel); SetVar(button, REPOBJ, palette); SetVar(button, COLORBAR, colorBar); SetMethod(button, CHANGEDVALUE, SimpleFuncButton); SetVar(button, PALETTEFUNC, NewInt(PF_RUFFLE)); ActivateButton(button, false); PrefixList(fullCompList, button); SetVar(button, HELPSTRING, NewString("This button performs the whatever function. \ When a range in the full color bar is \ selected, all components will be whatevered. When a range of a single component \ is selected, just that component will be whatevered.\n")); SetVar(button, HALTHELP, ObjTrue); top = bottom - MINORBORDER; bottom = top - BUTTONHEIGHT; #endif /*Now add in the color bar*/ SetMethod(colorBar, MAKE1HELPSTRING, MakePaletteBarHelp); SetVar(colorBar, HALTHELP, ObjTrue); PrefixList(contents, colorBar); SetVar(colorBar, PARENT, (ObjPtr) 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; } void SetObjectColor(col) ObjPtr col; /*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(0); } else { color(2); } } 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; PPtr palette; ObjPtr var; char *textFont; short3 *colors; int beg; int nColors; int textSize; ObjPtr textColor; int minMajorStep; Bool colorByPalette; int boxWidth, boxHeight, stringWidth, stringHeight; Get2DIntBounds(display, &left, &right, &bottom, &top); intLeft = left + PALDISPLAYBORDER; intRight = right - PALDISPLAYBORDER; intBottom = bottom + PALDISPLAYBORDER; intTop = top - PALDISPLAYBORDER; textColor = GetVar(display, COLOR); palette = (PPtr) GetPaletteVar("DrawPaletteDisplay", display, REPOBJ); if (!palette) { return ObjFalse; } colors = ((PPtr) palette) -> colors; beg = ((PPtr) palette) -> beg; nColors = ((PPtr) palette) -> nColors; /*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((ObjPtr) 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 - StrWidth(tempStr)) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(missingData); } DrawString(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 - StrWidth(tempStr)) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(MINUSINF); } DrawString(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 - StrWidth(tempStr)) / 2; break; case RIGHTALIGN: x = r - DSPPALETTESTL - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(PLUSINF); } DrawString(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 + 1; } } SetObjectColor(textColor); r = l - 1; l = intLeft + stringWidth; /*Draw all the tics in the middle*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min; CalcGoodSteps(ddiff, rangeTop - rangeBot, minMajorStep, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = palette -> min / majorWidth; curValue = temp * majorWidth; while (curValue > palette -> min) { curValue -= majorWidth; } k = 0; while (curValue < palette -> min) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= palette -> max + ddiff * 1.0E-6) { pixel = rangeBot + (curValue - palette -> min) * (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 - StrWidth(tempStr)) / 2; break; case RIGHTALIGN: x = l - DSPPALETTESTL - StrWidth(tempStr); break; } } if (colorByPalette) { SetRealColor(curValue); } DrawString(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 - StrWidth(tempStr) / 2; break; case RIGHTALIGN: x = (l + r) / 2 - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(missingData); } DrawString(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 - StrWidth(tempStr) / 2; break; case RIGHTALIGN: x = (l + r) / 2 - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(MINUSINF); } DrawString(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 - StrWidth(tempStr) / 2; break; case RIGHTALIGN: x = (r - boxWidth + r) / 2 - StrWidth(tempStr); break; } if (colorByPalette) { SetRealColor(PLUSINF); } DrawString(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 + 1; } } SetObjectColor(textColor); t = b - 1; b = intBottom + stringHeight + 2; /*Draw all the tics in the middle*/ halfSpace = (palette -> max - palette -> min) / (palette -> nColors - 4) * 0.5; ddiff = palette -> max - palette -> min; CalcGoodSteps(ddiff, rangeRight - rangeLeft, minMajorStep, &majorWidth, &nTics); minorWidth = majorWidth / nTics; /*Minor and major tics first*/ temp = palette -> min / majorWidth; curValue = temp * majorWidth; while (curValue > palette -> min) { curValue -= majorWidth; } k = 0; while (curValue < palette -> min) { ++k; if (k >= nTics) k = 0; curValue += minorWidth; } /*Now actually draw them*/ if (ABS(curValue) < ddiff * 1.0E-6) curValue = 0.0; while (curValue <= palette -> max + ddiff * 1.0E-6) { pixel = rangeLeft + (curValue - palette -> min) * (rangeRight - rangeLeft) / (ddiff); if (k == 0) { /*Major tic*/ if (numbersOnly) { sprintf(tempStr, "%lg", curValue); switch(alignment) { case LEFTALIGN: x = pixel; break; case CENTERALIGN: x = pixel - StrWidth(tempStr) / 2; break; case RIGHTALIGN: x = pixel - StrWidth(tempStr); break; } } else { DrawLine(pixel, b, pixel, t); DrawLine(pixel + 1, b, pixel + 1, t); sprintf(tempStr, "%lg", curValue); switch(alignment) { case LEFTALIGN: x = pixel; break; case CENTERALIGN: x = pixel - StrWidth(tempStr) / 2; break; case RIGHTALIGN: x = pixel - StrWidth(tempStr); break; } } if (colorByPalette) { SetRealColor(curValue); } DrawString(x, 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 */ if (1 || right - left < top - bottom) { #if 0 /*Draw bits for vertical box*/ if (!numbersOnly) { /*First the string end*/ DrawUILine(intLeft + stringWidth, bottom + INSET, intLeft + stringWidth, top - INSET, UIBLACK); DrawUILine(intLeft + stringWidth - 1, bottom + INSET, intLeft + stringWidth - 1, top - INSET, UIBLACK); DrawUILine(intLeft + stringWidth + 1, bottom + INSET, intLeft + stringWidth + 1, top - INSET, UIBLACK); DrawUILine(intLeft + stringWidth - 2, bottom + INSET, intLeft + stringWidth - 2, top - INSET, UIWHITE); DrawUILine(intLeft + stringWidth + 2, bottom + INSET, intLeft + stringWidth + 2, top - INSET, UIWHITE); DrawUILine(intLeft + stringWidth - 3, bottom + INSET, intLeft + stringWidth - 3, top - INSET, UIWHITE); DrawUILine(intLeft + stringWidth + 3, bottom + INSET, intLeft + stringWidth + 3, top - INSET, UIWHITE); /*Now the box end*/ DrawUILine(intRight - boxWidth, bottom + INSET, intRight - boxWidth, top - INSET, UIBLACK); DrawUILine(intRight - boxWidth - 1, bottom + INSET, intRight - boxWidth - 1, top - INSET, UIBLACK); DrawUILine(intRight - boxWidth + 1, bottom + INSET, intRight - boxWidth + 1, top - INSET, UIBLACK); DrawUILine(intRight - boxWidth - 2, bottom + INSET, intRight - boxWidth - 2, top - INSET, UIWHITE); DrawUILine(intRight - boxWidth + 2, bottom + INSET, intRight - boxWidth + 2, top - INSET, UIWHITE); DrawUILine(intRight - boxWidth - 3, bottom + INSET, intRight - boxWidth - 3, top - INSET, UIWHITE); DrawUILine(intRight - boxWidth + 3, bottom + INSET, intRight - boxWidth + 3, top - INSET, UIWHITE); } #endif } 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; } Select(display, true); /* make text box current for editing or adjusting */ DrawMe(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 (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; 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 } ObjPtr NewPaletteDisplay(left, right, bottom, top, name, palette) int left, right, bottom, top; char *name; ObjPtr palette; /*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)); } 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; sprintf(tempStr, "set value Field\\ Min \"%g\"\n", MINUSINF); Log(tempStr); sprintf(tempStr, "set value Field\\ Max \"%g\"\n", ((PPtr) palette) -> max); Log(tempStr); sprintf(tempStr, "set value Field\\ Min \"%g\"\n", ((PPtr) palette) -> min); Log(tempStr); sprintf(tempStr, "set value N\\ Colors \"%d\"\n", ((PPtr) palette) -> nColors); Log(tempStr); for (k = 0; k < ((PPtr) palette) -> nColors; ++k) { sprintf(tempStr, "set color Palette\\ Colors %d %d %d %d\n", k, ((PPtr) palette) -> colors[k][0], ((PPtr) palette) -> colors[k][1], ((PPtr) palette) -> colors[k][2]); Log(tempStr); } } void InitColors() /*Initialize the color system*/ { int k; int colorBeg, colorEnd; int cmapBitPlanes; int rgbTest; ObjPtr var; iconColorPalette = NewIcon(0, 0, ICONCTABLE, "Color Palette"); AddToReferenceList(iconColorPalette); if (getenv("SCIAN_SHOW_CONFIG")) { showConfig = true; } else { showConfig = false; } /*Make a color palette class*/ paletteClass = NewObject(NULLOBJ, sizeof(Palette) - sizeof(Thing)); AddToReferenceList(paletteClass); SETOBJTYPE(paletteClass -> flags, PALETTE); ((PPtr) paletteClass) -> colors = 0; ((PPtr) paletteClass) -> components = 0; ((PPtr) paletteClass) -> beg = 0; ((PPtr) paletteClass) -> nColors = 0; SetVar(paletteClass, DEFAULTICON, iconColorPalette); SetVar(paletteClass, COLORMODEL, NewInt(CM_RGB)); 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, EXTENSION, NewString("pal")); SetMethod(paletteClass, SAVECPANEL, SavePalette); SetMethod(paletteClass, SAVEALLCONTROLS, SavePaletteControls); SetMethod(paletteClass, LOCALCOPY, MakeLocalCopy); if (showConfig) { printf("Calculating machine parameters\n"); } #ifdef GRAPHICS /*Shoot for RGB double buffer*/ hasRGB = true; hasDouble = true; #ifdef GD_BITS_NORM_DBL_RGB rgbTest = getgdesc(GD_BITS_NORM_DBL_RGB); #else #ifdef GD_BITS_NORM_DBL_RED rgbTest = getgdesc(GD_BITS_NORM_DBL_RED) && getgdesc(GD_BITS_NORM_DBL_GREEN) && getgdesc(GD_BITS_NORM_DBL_BLUE); #else !! No double-buffer RGB bits constant is defined #endif #endif /*If not enough bit planes, shoot for single buffer*/ if (!rgbTest) { if (showConfig) { printf("Not enough bit planes for double buffer RGB. Going to single buffer.\n"); } hasDouble = false; #ifdef GD_BITS_NORM_SNG_RGB rgbTest = getgdesc(GD_BITS_NORM_SNG_RGB); #else #ifdef GD_BITS_NORM_SNG_RED rgbTest = getgdesc(GD_BITS_NORM_SNG_RED) & getgdesc(GD_BITS_NORM_SNG_GREEN) & getgdesc(GD_BITS_NORM_SNG_BLUE); #else !! No single-buffer RGB bits constant is defined #endif #endif if (rgbTest) { if (showConfig) { printf("Not enough bit planes for single buffer. Giving up on RGB mode.\n"); } hasRGB = false; hasDouble = true; } else { if (showConfig) { printf("Single buffer RGB OK.\n"); } } } else { if (showConfig) { printf("Double buffer RGB OK.\n"); } } if (getenv("SCIAN_VETO_RGB")) { if (showConfig) { printf("RGB mode vetoed.\n"); } hasRGB = false; } if (getenv("SCIAN_FORCE_RGB")) { if (showConfig) { printf("RGB mode forced.\n"); } hasRGB = true; } /*Now check color map mode*/ hasCmap = true; cmapBitPlanes = getgdesc(hasDouble ? GD_BITS_NORM_DBL_CMODE : GD_BITS_NORM_SNG_CMODE); if (showConfig) { printf("%d double buffer color map bitplanes.\n", cmapBitPlanes); } #if MACHINE == RS6000 cmapBitPlanes = 8; #endif if (cmapBitPlanes < 8) { /*Not enough bit planes for cmap*/ if (hasRGB) { if (showConfig) { printf("Not enough bit planes for color map mode. Giving up on color map mode.\n"); } hasCmap = false; } else { /*Try single buffer*/ if (showConfig) { printf("Not enough bit planes for double buffer color map mode. Trying single.\n"); } hasDouble = false; cmapBitPlanes = getgdesc(GD_BITS_NORM_SNG_CMODE); if (showConfig) { printf("%d double buffer color map bitplanes.\n", cmapBitPlanes); } if (cmapBitPlanes < 8) { printf("Not enough bit planes to do anything useful. Giving up entirely.\n"); exit(-1); } } } else { if (showConfig) { printf("Double buffer color map mode OK.\n"); } } if (getenv("SCIAN_VETO_CMAP")) { if (showConfig) { printf("Color map mode vetoed.\n"); } hasCmap = false; } if (getenv("SCIAN_FORCE_CMAP")) { if (showConfig) { printf("Color map mode forced.\n"); } hasCmap = true; } if (getenv("SCIAN_VETO_DOUBLE")) { if (showConfig) { printf("Double buffer mode vetoed.\n"); } hasDouble = false; } if (getenv("SCIAN_FORCE_DOUBLE")) { if (showConfig) { printf("Double buffer mode forced.\n"); } hasDouble = true; } #ifdef GD_BLEND if (getgdesc(GD_BLEND)) { hasTransparency = true; if (showConfig) { printf("Blending transparency OK.\n"); } } else #endif { hasTransparency = false; if (showConfig) { printf("There is no blending transparency.\n"); } } #ifdef GD_LIGHTING_TWOSIDE if (getgdesc(GD_LIGHTING_TWOSIDE)) { hasTwoSided = true; if (showConfig) { printf("There is hardware two-sided lighting available.\n"); } } else #endif { hasTwoSided = false; if (showConfig) { printf("There is no hardware two-sided lighting.\n"); } } #ifdef GD_BITS_ZBUFFER if (getgdesc(GD_BITS_ZBUFFER) > 0) #else #ifdef GD_BITS_NORM_ZBUFFER if (getgdesc(GD_BITS_NORM_ZBUFFER) > 0) #else !! No Z-buffer constant defined #endif #endif { hasZbuf = true; if (showConfig) { printf("Z-buffer OK.\n"); } } else { hasZbuf = false; if (showConfig) { printf("There is no Z-buffer.\n"); } } /*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 SCAVENGECOLORS topTestColor = colorBeg; #endif } else { #ifdef SCAVENGECOLORS int k, c, bp; bp = getgdesc(GD_BITS_NORM_SNG_CMODE); c = 1; for (k = 0; k < bp; ++k) c *= 2; topTestColor = c; #endif } /*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(UIORANGE, 255, 88, 0); MakeUIColor(UIPURPLE, 100, 0, 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); /*Now colorBeg set to be above NUICOLORS*/ if (hasCmap) { colorBeg = curUIColorIndex; /*Make first color range*/ colorRanges = new(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, TrackColorWheel); #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 SetMethod(colorBarClass, SETVAL, SetColorBarVal); /*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); var = NewRealArray(1, 3L); ((real *) ELEMENTS(var))[0] = 0.75; ((real *) ELEMENTS(var))[1] = 0.75; ((real *) ELEMENTS(var))[2] = 0.75; 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); }