/*:ts=8 */ /* >> PopColours: The amazing colour-set control panel << ** >> From The Transactor - THE Magazine for Commodore Computing << ** ** November 1986, Version 1.0 ** ** - uses proportional gadgets for setting R G B ** and allows alteration of any colour register ** - operates on the TOPMOST OR SECOND SCREEN, so ** lets you change the colours of any currently ** executing program with its own screen ** - only opens up when selected, so it doesn't eat up ** screen space when you're not using it ** ** >> THIS PROGRAM MAY BE FREELY DISTRIBUTED << ** ** (c) 1986, AHA! (Acme Heuristic Applications!) ** ** Written by Chris Zamara and Nick Sullivan */ #include #include #include #include /* defines for defaults, positioning, sizes, etc. */ #define SCREEN2INIT FALSE /* default to topmost screen */ #define GADGHEIGHT 10L /* height of proportional RGB gadgets */ #define RTOP 15L /* y position of top of Red gadget */ #define GTOP 28L /* " " " Green gadget */ #define BTOP 41L /* " " " Blue gadget */ #define CVAL 177L /* x position of colour values */ #define CPOSX 195L /* x position of colour register indicator */ #define CPOSY 63L /* y position of " " ... */ #define RPOSX 115L /* x position of Register text */ #define SCRPOSX 15L /* x position of screen indicator */ #define SCRPOSY 63L /* y position of screen indicator */ #define UPGADGX 197L /* x position of up gadget */ #define UPGADGY 10L /* y position of up gadget */ #define DNGADGX 197L /* x position of down gadget */ #define DNGADGY 32L /* y position of down gadget */ #define COLORGADGET 1 /* ID for RGB gadgets */ #define UPGADGET 2 /* ID for up gadget */ #define DOWNGADGET 3 /* ID for down gadget */ #define SCREENGADGET 4 /* ID for down gadget */ #define ARROWDELAY 5 /* # of ticks before repeating up/down */ #define DELAY 100000 /* pause for "no 2nd scrn" message */ #define POTINC 0x1111 /* amount added to each colour pot per click */ #define RTEXT (RTOP+(GADGHEIGHT >> 1)+2) /* gadget text position */ #define GTEXT (GTOP+(GADGHEIGHT >> 1)+2) #define BTEXT (BTOP+(GADGHEIGHT >> 1)+2) /* global structure declarations */ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct ViewPort *vp; struct RastPort *rp; struct IntuiMessage *GetMsg(), *message; struct Window *OpenWindow(), *gwind, *SmallWind; struct Screen *TheScreen; /* function declarations */ APTR OpenLibrary(); USHORT GetRGB4(); USHORT GadgPressed(); BOOL BigWindow(); /* gadget structures for colour controls */ struct Gadget gadgR, gadgG, gadgB; /* gadget structures for up/down arrows and screen selector */ struct Gadget gadgUp, gadgDown, gadgScreen; /* define NewWindow structure for our window */ struct NewWindow GadgWind = { 400, 16, 233, 72, /* left, top, width, height */ -1, -1, /* use screen colours */ GADGETDOWN /* IDCMP flags */ | GADGETUP | MOUSEBUTTONS | INTUITICKS | INACTIVEWINDOW | CLOSEWINDOW, WINDOWDEPTH /* window flags */ | WINDOWCLOSE | WINDOWDRAG | INACTIVEWINDOW | RMBTRAP | ACTIVATE | SMART_REFRESH, &gadgUp, /* first gadget in list */ NULL, (UBYTE *)"PopColours 1.0", /* window title */ NULL, /* ptr to screen */ NULL, 0, 0, 0, 0, /* sizing limits (non-resizable)*/ WBENCHSCREEN }; /* also make NewWindow structure for small window */ struct NewWindow SWind; /* PropInfo structures for control gadgets */ struct PropInfo propinfR, propinfG, propinfB; /* control knob Image structures */ struct Image knobR, knobG, knobB; /* co-ordinate of points of up/down arrows */ SHORT UpXY[8] = { 13,0, 25,17, 0,17, 13,0 }; SHORT DownXY[8] = { 0,0, 25, 0, 13,17, 0,0 }; /* Border structure for Up-Arrow gadget */ struct Border UpArrow = { 3, 2, 1, 0, JAM1, 4, UpXY, NULL }; /* Border structure for Down-Arrow gadget */ struct Border DownArrow = { 3, 2, 1, 0, JAM1, 4, DownXY, NULL }; /* this next array is for fast'n'easy integer to ASCII conversion */ char *cnum[32] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", }; USHORT colreg = 0; /* current colour register */ BOOL Screen2Flag; /* false=top screen, true=second screen */ BOOL Old2Flag; /* previous value of Screen2Flag */ main (argc, argv) int argc; char *argv[]; { /* open intuition and graphics libraries */ if ( (IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 0L) ) == NULL) exit (0L); if ( (GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", 0L) ) == NULL) { CloseLibrary (IntuitionBase); exit (0L); } /* second arg specifies start-up colour register */ if (argc == 2) colreg = atoi(argv[1]); /* switch between small and big windows until big is closed */ do { SmallWindow(); } while (BigWindow()); /* close everything up before ending */ CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); } BOOL BigWindow () { ULONG msgclass; /* message class from IDCMP */ USHORT msgcode; /* message code from IDCMP */ APTR IAddr; /* pointer to gadget from IDCMP */ USHORT WhichGadg; /* ID of selected gadget */ USHORT TickStart; /* countdown for up/down arrow repeat delay */ BOOL GadgSel = FALSE; /* set when a colour gadget is selected */ BOOL RegSel = FALSE; /* set when up or down gadget is selected */ BOOL window_still_open = TRUE; BOOL window_active = TRUE; GadgSetup(); /* initialize gadget structures */ Screen2Flag = SCREEN2INIT; Old2Flag = !SCREEN2INIT; /* now attempt to open the window containing the gadgets */ if ((gwind = OpenWindow(&GadgWind)) == NULL) { CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); exit(0L); } /* get ptr to rastport for graphics routines */ rp = gwind->RPort; /* set RGB gadget positions to current colours */ SetColrs(); /* put up labels on window display */ WinText(); /* put up colour register number indicator */ RegIndicate(); /*** main event loop ***/ while (window_still_open && window_active) { /* wait politely, except when sliding a colour gadget */ if (! GadgSel) Wait (1L << gwind->UserPort->mp_SigBit); while (message = GetMsg(gwind->UserPort)) { /* get what we need from the message port */ msgclass = message->Class; msgcode = message->Code; IAddr = message->IAddress; ReplyMsg(message); /* reply to message right away */ /* now we can interpret the message */ /* check for gadget selected */ if (msgclass == GADGETDOWN) WhichGadg = GadgPressed(IAddr, &GadgSel, &RegSel, &TickStart); /* check if gadget released, even if off of gadget */ else if ( (msgclass == MOUSEBUTTONS && msgcode == SELECTUP) || msgclass == GADGETUP ) GadgReleased(IAddr, &GadgSel, &RegSel, WhichGadg); /* auto-repeat arrow gadgets after delay */ else if (msgclass == INTUITICKS && RegSel) { /* wait ARROWDELAY ticks before repeating */ if (TickStart++ > ARROWDELAY) UpdateColReg(WhichGadg); } /* finish up if the close gadget is clicked */ else if (msgclass == CLOSEWINDOW) window_still_open = FALSE; /* exit if window made inactive */ else if (msgclass == INACTIVEWINDOW) window_active = FALSE; } if (GadgSel) /* set colour to pot values */ ReadGadg(); } /* update NewWindow struct in case window has been moved */ GadgWind.LeftEdge = gwind->LeftEdge; GadgWind.TopEdge = gwind->TopEdge; CloseWindow(gwind); return(window_still_open); } SmallWindow () { ULONG msgclass; /* message class from IDCMP */ BOOL activated = FALSE; SWind = GadgWind; /* almost like big window, */ /* except for ... */ SWind.Height = 11; SWind.IDCMPFlags = ACTIVEWINDOW; SWind.FirstGadget = NULL; SWind.Flags = WINDOWDEPTH | ACTIVEWINDOW; /* attempt to open the small window */ if ((SmallWind = OpenWindow(&SWind)) == NULL) { CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); exit(0L); } Wait (1L << SmallWind->UserPort->mp_SigBit); while (message = GetMsg(SmallWind->UserPort)) { msgclass = message->Class; ReplyMsg(message); /* reply to message right away */ if (msgclass == ACTIVEWINDOW) activated = TRUE; } /* update NewWindow struct in case window has been moved */ GadgWind.LeftEdge = SmallWind->LeftEdge; GadgWind.TopEdge = SmallWind->TopEdge; CloseWindow(SmallWind); } USHORT GadgPressed (IAddr, GadgSel, RegSel, TickStart) /* set flags and call appropriate routines when a gadget is clicked */ struct Gadget *IAddr; BOOL *GadgSel, *RegSel; USHORT *TickStart; { USHORT WhichGadg; /* get gadget type */ WhichGadg = IAddr->GadgetID; /* rgb gadget? */ if (WhichGadg == COLORGADGET) { *GadgSel = TRUE; /* update settings if 2nd screen gone */ if (Screen2Flag && IntuitionBase->FirstScreen->NextScreen == NULL) UpdateColReg(0); } /* up/down gadget? */ else if (WhichGadg == UPGADGET || WhichGadg == DOWNGADGET) { *RegSel = TRUE; *TickStart = 0; /* start delay timer */ UpdateColReg(WhichGadg); } /* Screen select gadget? */ else if (WhichGadg == SCREENGADGET) { Screen2Flag = !Screen2Flag; UpdateColReg(0); } return (WhichGadg); } GadgReleased (IAddr, GadgSel, RegSel, WhichGadg) /* a gadget has been released - set flags and call appropriate routines */ struct Gadget *IAddr; BOOL *GadgSel, *RegSel; USHORT WhichGadg; { if (WhichGadg == COLORGADGET) { ReadGadg(); if ( ( ((struct PropInfo *)(IAddr->SpecialInfo))->Flags ) & KNOBHIT ) SetColrs(); /* re-position knob if it was moved */ *GadgSel = FALSE; /* colour gadget no longer selected */ } else *RegSel = FALSE; /* ..or other gadget no longer selected */ } ReadGadg () /* read gadget pot values and set colour register 'colreg' accordingly */ { USHORT RedVal, GrnVal, BluVal; RedVal = propinfR.HorizPot / POTINC; GrnVal = propinfG.HorizPot / POTINC; BluVal = propinfB.HorizPot / POTINC; /* get viewport of topmost or second screen */ vp = &(TheScreen->ViewPort); /* change colour register */ SetRGB4(vp, (ULONG)colreg, (ULONG)RedVal, (ULONG)GrnVal, (ULONG)BluVal ); PrintValues(RedVal, GrnVal, BluVal); /* numbers to right */ } PrintValues (R, G, B) /* print colour values to right of gadgets */ USHORT R, G, B; { SetAPen(rp, 1L); Move(rp, CVAL, RTEXT); Text(rp, cnum[R], 2L); Move(rp, CVAL, GTEXT); Text(rp, cnum[G], 2L); Move(rp, CVAL, BTEXT); Text(rp, cnum[B], 2L); } SetColrs () /* set gadget pot values according to rgb in register 'colreg' */ { USHORT C0, R, G, B; ULONG hpR, hpG, hpB; /* get viewport of topmost screen */ ScreenPick(); /* select screen one or two */ vp = &(TheScreen->ViewPort); /* get rgb of specified colour register */ C0 = GetRGB4(vp->ColorMap, (ULONG)(colreg) ); /* convert rgb to HorizPot values */ R = (C0 >> 8) & 0xF; G = (C0 >> 4) & 0xF; B = C0 & 0xF; hpR = R * POTINC; hpG = G * POTINC; hpB = B * POTINC; /* change gadgets to reflect new colours */ ModifyProp(&gadgR, gwind, NULL, (ULONG)propinfR.Flags, hpR, 0L, (ULONG)propinfR.HorizBody, 0L ); ModifyProp(&gadgG, gwind, NULL, (ULONG)propinfG.Flags, hpG, 0L, (ULONG)propinfG.HorizBody, 0L ); ModifyProp(&gadgB, gwind, NULL, (ULONG)propinfB.Flags, hpB, 0L, (ULONG)propinfB.HorizBody, 0L ); PrintValues(R, G, B); /* colour numbers */ } RegIndicate () /* show colour register number */ { ULONG c; /* first print register number */ Move(rp, CPOSX, CPOSY); SetAPen(rp, 1L); Text(rp, cnum[colreg], 2L); /* now display a block in 'colreg' colour if changing this screen */ /* or background colour if changing another screen */ c = (IntuitionBase->ActiveScreen == TheScreen) ? colreg : 0; Move(rp, CPOSX+24, CPOSY); /* move past text */ SetDrMd(rp, INVERSVID); /* inverse mode */ SetAPen(rp, c); /* set colour */ Text(rp, " ", 1L); /* print a space */ SetDrMd(rp, JAM2); /* set mode back to normal */ SetAPen(rp, 1L); } WinText () /* put up various labels on window */ { SetAPen(rp, 1L); Move(rp, 5L, RTEXT); Text(rp, "R", 1L); Move(rp, 5L, GTEXT); Text(rp, "G", 1L); Move(rp, 5L, BTEXT); Text(rp, "B", 1L); Move(rp, RPOSX, CPOSY); Text(rp, " Register", 9L); } UpdateColReg (WhichGadg) /* increment or decrement colour register */ /* if WhichGadg is 0, just display current settings */ USHORT WhichGadg; { USHORT numregs; /* get number of bitplanes of screen */ ScreenPick(); /* set 'TheScreen' */ numregs = 1 << ((TheScreen->ViewPort).RasInfo->BitMap->Depth); /* (whew!) */ /* increment or decrement colour register */ if (WhichGadg == UPGADGET) colreg++; else if (WhichGadg == DOWNGADGET) colreg--; colreg = colreg % numregs; RegIndicate(); SetColrs(); } ScreenPick () /* select top screen if Screen2Flag false ** ** or second screen if true ** ** and update display if necesary ** */ { ULONG d; TheScreen = IntuitionBase->FirstScreen; Move(rp, SCRPOSX, SCRPOSY); SetAPen(rp, 1L); SetBPen(rp, 3L); /* print in different background colour */ if (Screen2Flag) { if (TheScreen->NextScreen == NULL) { /* no second screen, put up temp. message */ Screen2Flag = FALSE; Text(rp, "(no 2nd scrn)", 13L); /* delay the easy way (ok, so we hog a second) */ for(d=0; dNextScreen; if (Old2Flag != Screen2Flag) Text(rp, "SECOND SCREEN", 13L); } } if (!Screen2Flag && Old2Flag) Text(rp, " TOP SCREEN ", 13L); SetBPen(rp, 0L); Old2Flag = Screen2Flag; } GadgSetup () { /* proportional gadget for red */ gadgR.NextGadget = NULL; gadgR.LeftEdge = 16; gadgR.TopEdge = RTOP; gadgR.Width = 155; gadgR.Height = GADGHEIGHT; gadgR.Flags = GADGHNONE | GADGIMAGE; gadgR.Activation = GADGIMMEDIATE | RELVERIFY; gadgR.GadgetType = PROPGADGET; gadgR.GadgetRender = (APTR)&knobR; gadgR.SelectRender = NULL; gadgR.GadgetText = NULL; gadgR.MutualExclude = NULL; gadgR.SpecialInfo = (APTR)&propinfR; gadgR.GadgetID = COLORGADGET; gadgR.UserData = NULL; /* up-arrow for changing colour register */ gadgUp.NextGadget = NULL; gadgUp.LeftEdge = UPGADGX; gadgUp.TopEdge = UPGADGY; gadgUp.Width = 31; gadgUp.Height = 21; gadgUp.Flags = GADGHCOMP; gadgUp.Activation = GADGIMMEDIATE | RELVERIFY; gadgUp.GadgetType = BOOLGADGET; gadgUp.GadgetRender = (APTR)↑ gadgUp.SelectRender = NULL; gadgUp.GadgetText = NULL; gadgUp.MutualExclude = NULL; gadgUp.SpecialInfo = NULL; gadgUp.GadgetID = UPGADGET; gadgUp.UserData = NULL; /* top/second screen indicator/selector */ gadgScreen = gadgUp; gadgScreen.LeftEdge = SCRPOSX; gadgScreen.TopEdge = SCRPOSY-5; gadgScreen.Width = 104; gadgScreen.Height = 11; gadgScreen.Activation = GADGIMMEDIATE; gadgScreen.GadgetRender = NULL; gadgScreen.GadgetID = SCREENGADGET; /* values needed for propinfo structure */ propinfR.Flags = FREEHORIZ | AUTOKNOB; propinfR.HorizBody = 1 << 12; /* body increment (1/16) */ /* propinf structures for R G B gadgets all alike */ propinfG = propinfR; propinfB = propinfR; /* G and B gadgets same as R */ gadgG = gadgR; gadgB = gadgR; /* except for... */ gadgG.TopEdge = GTOP; gadgB.TopEdge = BTOP; gadgG.GadgetRender = (APTR)&knobG; gadgB.GadgetRender = (APTR)&knobB; gadgG.SpecialInfo = (APTR)&propinfG; gadgB.SpecialInfo = (APTR)&propinfB; /* define down gadget in terms of up gadget */ gadgDown = gadgUp; gadgDown.GadgetRender = (APTR)↓ gadgDown.LeftEdge = DNGADGX; gadgDown.TopEdge = DNGADGY; gadgDown.GadgetID = DOWNGADGET; /* link all gadgets by pointers */ gadgUp.NextGadget = &gadgDown; gadgDown.NextGadget = &gadgR; gadgR.NextGadget = &gadgG; gadgG.NextGadget = &gadgB; gadgB.NextGadget = &gadgScreen; }