<> <> <> <> <> DIRECTORY Buttons, CD, CDColors, CDIO, CDMenus, CDSequencer, CDSil, ColorMap, Commander, Containers, Convert, GraphicsBasic, GraphicsColor, Icons, Labels, Process, Real, Rope, Sliders, Terminal, TerminalIO, ViewerOps; CDSil8BitColors: CEDAR PROGRAM IMPORTS Buttons, CDColors, CDIO, CDMenus, CDSequencer, CDSil, ColorMap, Commander, Containers, Convert, Icons, Labels, Process, Real, Rope, Sliders, Terminal, TerminalIO, ViewerOps = BEGIN <<>> <<--**Patterns**************************************>> Init8Patterns: Buttons.ButtonProc = <<--all parameter are discarded >> BEGIN standard: CARDINAL = 1; green: CARDINAL = 2; blue: CARDINAL = 4; pinktr: CARDINAL = 8; red: CARDINAL = 16; yellow: CARDINAL = 32; Checker8: PROC[col1, col2: CARDINAL] RETURNS[REF CDColors.Brick] = BEGIN RETURN[NEW[CDColors.Brick _ [col1*256+col2, col2*256+col1, col1*256+col2, col2*256+col1]]] END; DefineDimmer8: PROC[lev: CD.Layer, color: CARDINAL] = BEGIN CDColors.DefineColor[lev, Checker8[color, 0], bit8, back]; END; Full8: PROC[color: CARDINAL] RETURNS [b: REF CDColors.Brick] = BEGIN RETURN[Checker8[color, color]] END; CDColors.DefineColor[CDSil.xneutral, Full8[standard], bit8]; CDColors.DefineColor[CDSil.xgreen, Full8[green], bit8]; CDColors.DefineColor[CDSil.xcyan, Full8[blue], bit8]; CDColors.DefineColor[CDSil.xpink, Full8[pinktr], bit8]; CDColors.DefineColor[CDSil.xred, Full8[red], bit8]; CDColors.DefineColor[CDSil.xyellow, Full8[yellow], bit8]; CDColors.DefineColor[CD.backGround, NEW[CDColors.Brick _ [8, 0, 256*8, 0]], bit8]; CDColors.DefineColor[CD.highLightError, NEW[CDColors.Brick _ [255, 0, 0, 0]], bit8]; CDColors.DefineColor[CD.highLightShade, NEW[CDColors.Brick_[0, 255,0 , 255]], bit8]; DefineDimmer8[CDSil.xneutral, standard]; DefineDimmer8[CDSil.xgreen, green]; DefineDimmer8[CDSil.xcyan, blue]; DefineDimmer8[CDSil.xpink, pinktr]; DefineDimmer8[CDSil.xred, red]; DefineDimmer8[CDSil.xyellow, yellow]; END; <<>> <<--**end patterns**************************************>> numberOfColors: INT = 7; backgroundColor: INT = 6; Color: TYPE = RECORD[r, g, b, weight: REAL _ 0]; ColorDescRec: TYPE = ARRAY [0..numberOfColors) OF Color; ColorDesc: TYPE = REF ColorDescRec; color: ColorDesc = NEW[ColorDescRec]; <<-- The weights associated with every primary layer color: think of them as the transparency of each layer. The color of an intersection (i.e. standard over blue) is the weighted sum of the rgb of each color. These weights are also optionally loaded from profile and editable by the user.>> indLayer: INT _ 1; previndLayer: INT _ 1; -- to deselect the previous layer button <<>> CoefSlider: TYPE = RECORD [ value: Labels.Label _ NIL, select: Buttons.Button _ NIL, bar: Sliders.Slider _ NIL ]; ColorSlider: TYPE = RECORD [ value: Labels.Label _ NIL, bar: Sliders.Slider _ NIL ]; Handle: TYPE = REF AdjustColorRec; AdjustColorRec: TYPE = RECORD [ outer: Containers.Container _ NIL, coefLayer: ARRAY [0..numberOfColors) OF CoefSlider, potarColor: ARRAY [0..3) OF ColorSlider, height: CARDINAL _ 0 -- height measured from the top of the container ]; DataForSpecialProc: TYPE = REF DataForSpecialProcRec; DataForSpecialProcRec: TYPE = RECORD [ my: Handle, layer: CARDINAL ]; ColorMode8: PROC [] RETURNS [BOOL] = INLINE BEGIN virtual: Terminal.Virtual = Terminal.Current[]; RETURN [virtual.hasColorDisplay AND ~virtual.GetColorMode[].full AND virtual.GetColorMode[].bitsPerPixelChannelA=8]; END; Check8BitMode: PROC [] RETURNS [ok: BOOL] = BEGIN ok _ ColorMode8[]; IF ~ok THEN TRUSTED{Process.Detach[FORK TerminalIO.WriteRope["Put the display in 8 bit per pixel mode first\n"]]}; END; UpdateWeightSlider: Sliders.SliderProc = BEGIN datac: DataForSpecialProc _ NARROW[clientData]; my: Handle _ datac.my; layer: CARDINAL _ datac.layer; IF ~ColorMode8[] THEN RETURN; color[layer].weight _ value; ComputeColors[]; Labels.Set[my.coefLayer[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]]; END; UpdateColorSlider: Sliders.SliderProc = BEGIN data: DataForSpecialProc _ NARROW[clientData]; my: Handle _ data.my; layer: CARDINAL _ data.layer; IF ~ColorMode8[] THEN RETURN; Labels.Set[my.potarColor[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]]; SELECT layer FROM 0 => color[indLayer-1].r _ value; 1 => color[indLayer-1].g _ value; 2 => color[indLayer-1].b _ value; ENDCASE=> ERROR; ComputeColors[]; END; ResetButton: Buttons.ButtonProc = <<--Resets color map;>> <<--does not touch patterns>> BEGIN UpdateAllSliders: PROC [my: Handle] = BEGIN w: Sliders.NormalizedSliderValue; FOR layer: INT IN [0..numberOfColors) DO w _ color[layer].weight; Sliders.SetContents[my.coefLayer[layer].bar, 0]; Sliders.SetContents[my.coefLayer[layer].bar, w]; Labels.Set[my.coefLayer[layer].value, Convert.RopeFromInt[Real.Fix[color[layer].weight*100]]]; ENDLOOP; ButtonProcLayerInternal[0, my]; END; <<>> <<--ResetButton>> IF Check8BitMode[] THEN { SetUserColor[]; ComputeColors[]; UpdateAllSliders[NARROW[clientData, Handle]]; }; END; ButtonProcLayer: Buttons.ButtonProc = BEGIN data: DataForSpecialProc _ NARROW[clientData]; IF Check8BitMode[] THEN { ButtonProcLayerInternal[data.layer, data.my]; } END; ButtonProcLayerInternal: PROC[layer: CARDINAL, my: Handle] = BEGIN SetPotar: PROC[layer: CARDINAL, my: Handle] = BEGIN Sliders.SetContents[my.potarColor[0].bar, color[layer].r]; Sliders.SetContents[my.potarColor[1].bar, color[layer].g]; Sliders.SetContents[my.potarColor[2].bar, color[layer].b]; Labels.Set[my.potarColor[0].value, Convert.RopeFromInt[Real.Fix[color[layer].r*100]]]; Labels.Set[my.potarColor[1].value, Convert.RopeFromInt[Real.Fix[color[layer].g*100]]]; Labels.Set[my.potarColor[2].value, Convert.RopeFromInt[Real.Fix[color[layer].b*100]]]; END; <<>> <<-- ButtonProcLayerInternal>> indLayer _ layer+1; SetPotar[layer, my]; Buttons.SetDisplayStyle[my.coefLayer[previndLayer-1].select, $BlackOnWhite]; Buttons.SetDisplayStyle[my.coefLayer[indLayer-1].select, $WhiteOnBlack]; previndLayer _ indLayer; END; CreateAnInstance: PROC[] = <<--create an icon of the tool;>> <<--does not change any color setup at initialization of the tool>> BEGIN nameLayerButton: ARRAY [0..numberOfColors) OF Rope.ROPE _ ["blk", "grn", "blu", "pin", "red", "yel", "bck"]; nameColorSlider: ARRAY [0..3) OF Rope.ROPE _ ["R", "G", "B"]; coefX: CARDINAL = 10; coefDX: CARDINAL = 25; coefDeltaX: CARDINAL = coefDX+4; coefSelectY: CARDINAL = 5; coefSelectDY: CARDINAL = 15; coefValueY: CARDINAL = coefSelectY+coefSelectDY+3; coefValueDY: CARDINAL = 15; coefBarY: CARDINAL = coefValueY+coefValueDY; firstButtonY: CARDINAL = 10; buttonDY: CARDINAL = 15; interButtonY: CARDINAL = 3; buttonX: CARDINAL = coefX+numberOfColors*coefDeltaX+8; buttonDX: CARDINAL = 80; firstSliderY: CARDINAL = 10; sliderDY: CARDINAL = 20; interSliderY: CARDINAL = 5; labelX: CARDINAL = buttonX+buttonDX+10; -- R, G, B labelDX: CARDINAL = 14; label2X: CARDINAL = labelX+labelDX; -- number label2DX: CARDINAL = 30; sliderX: CARDINAL = label2X+label2DX; caption: Rope.ROPE = "ChiPencil 8 bit color editor"; my: Handle = NEW[AdjustColorRec]; IF ~ColorMode8[] THEN TerminalIO.WriteRope["The 8 bit color tool works only after you put the display in 8 bit mode\n"]; IF ViewerOps.FindViewer[caption]#NIL THEN { TerminalIO.WriteRope[caption]; TerminalIO.WriteRope[" viewer already exits\n"]; RETURN }; my.outer _ Containers.Create[[ name: caption, iconic: TRUE, icon: Icons.NewIconFromFile[CDIO.GetWorkingDirectory[NIL].Cat["Chipndale.icons"], 2], column: left, scrollable: FALSE ]]; my.height _ firstSliderY+3*(sliderDY+interSliderY); <<-- create sliders for weights>> FOR indLayer: INT IN [0..numberOfColors) DO wInit: REAL _ color[indLayer].weight; my.coefLayer[indLayer].select _ Buttons.Create[ info: [ name: nameLayerButton[indLayer], iconic: TRUE, wx: coefX+indLayer*coefDeltaX, wy: coefSelectY, wh: coefSelectDY, ww: coefDX, parent: my.outer, border: TRUE], proc: ButtonProcLayer, clientData: NEW[DataForSpecialProcRec _ [my: my, layer: indLayer]] ]; my.coefLayer[indLayer].value _ Labels.Create[ [ name: Convert.RopeFromInt[Real.Fix[wInit*100]], -- initial contents iconic: TRUE, wx: coefX+indLayer*coefDeltaX, wy: coefValueY, wh: coefValueDY, ww: coefDX, parent: my.outer, border: TRUE ]]; my.coefLayer[indLayer].bar _ Sliders.Create[ info: [ name: nameLayerButton[indLayer], iconic: TRUE, parent: my.outer, wx: coefX+indLayer*coefDeltaX, wy: coefBarY, wh: - 5, --guardY ww: coefDX, border: TRUE], sliderProc: UpdateWeightSlider, orientation: vertical, value: wInit, clientData: NEW[DataForSpecialProcRec _ [my: my, layer: indLayer] ]]; Containers.ChildYBound[my.outer, my.coefLayer[indLayer].bar]; ENDLOOP; <<>> <<-- create command buttons>> [] _ Buttons.Create[ info: [name: "reset map", wx: buttonX, wy: firstButtonY, wh: buttonDY, ww: buttonDX, parent: my.outer, border: TRUE], proc: ResetButton, clientData: my, fork: TRUE ]; [] _ Buttons.Create[ info: [name: "reset pattern", wx: buttonX, wy: firstButtonY+buttonDY+interButtonY, wh: buttonDY, ww: buttonDX, parent: my.outer, border: TRUE], fork: TRUE, proc: Init8Patterns ]; <<>> <<-- create sliders for rgb colors>> FOR iColor: CARDINAL IN [0..3) DO cInit: REAL _ SELECT iColor FROM 0 => color[indLayer-1].r, 1 => color[indLayer-1].g, 2 => color[indLayer-1].b, ENDCASE => ERROR; [] _ Labels.Create[ info: [name: nameColorSlider[iColor], parent: my.outer, wx: labelX, wy: firstSliderY+iColor*(sliderDY+interSliderY), ww: labelDX, wh: sliderDY, border: TRUE ]]; my.potarColor[iColor].bar _ Sliders.Create[ info: [parent: my.outer, wx: sliderX, wy: firstSliderY+iColor*(sliderDY+interSliderY), ww: 10, wh: sliderDY], sliderProc: UpdateColorSlider, orientation: horizontal, value: cInit, clientData: NEW[DataForSpecialProcRec _ [my: my, layer: iColor]] ]; Containers.ChildXBound[my.outer, my.potarColor[iColor].bar]; my.potarColor[iColor].value _ Labels.Create[[ name: Convert.RopeFromInt[Real.Fix[cInit*100]], -- initial contents wx: label2X, wy: firstSliderY+iColor*(sliderDY+interSliderY), ww: label2DX, wh: sliderDY, parent: my.outer, border: TRUE ]]; ENDLOOP; ViewerOps.SetOpenHeight[my.outer, my.height]; -- hint our desired height ViewerOps.PaintViewer[my.outer, all]; -- reflect above change Buttons.SetDisplayStyle[my.coefLayer[0].select, $WhiteOnBlack]; END; ComputeColors: PROC[] = <<--takes a color setting (weights and rgb values) and sets up the device>> BEGIN SetMap: PROC[index: CARDINAL, color: Color] = { ColorMap.SetRGBColor[index, color.r, color.g, color.b] }; Adjust: PROC [value, x: REAL] RETURNS [REAL] = { RETURN[IF x>0 THEN value+((1-value)*x) ELSE value+(value)*x] }; ComposeColor: PROC[c1: Color, ind: CARDINAL] RETURNS [c: Color] = { c _ [ c1.r+color[ind].weight*color[ind].r, c1.g+color[ind].weight*color[ind].g, c1.b+color[ind].weight*color[ind].b, c1.weight+color[ind].weight] }; c: Color; IF ~ColorMode8[] THEN RETURN; <<-- we need a better way, using Basics.* or similar to access the bits of the index>> FOR i0: CARDINAL IN [0..2) DO FOR i1: CARDINAL IN [0..2) DO FOR i2: CARDINAL IN [0..2) DO FOR i3: CARDINAL IN [0..2) DO FOR i4: CARDINAL IN [0..2) DO FOR i5: CARDINAL IN [0..2) DO c _ [0, 0, 0, 0]; <<-- compute the weighted sum of colors>> IF i0=1 THEN {c _ ComposeColor[c, 0]}; IF i1=1 THEN {c _ ComposeColor[c, 1]}; IF i2=1 THEN {c _ ComposeColor[c, 2]}; IF i3=1 THEN {c _ ComposeColor[c, 3]}; IF i4=1 THEN {c _ ComposeColor[c, 4]}; IF i5=1 THEN {c _ ComposeColor[c, 5]}; c _ ComposeColor[c, backgroundColor]; IF c.weight=0 THEN c _ color[backgroundColor] ELSE c _ [c.r/c.weight, c.g/c.weight, c.b/c.weight, c.weight]; SetMap[32*i5+16*i4+8*i3+4*i2+2*i1+i0, c]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; SetMap[index: 64, color: color[6]]; -- [background] SetMap[index: 128, color: [r:0, g:0, b:0]]; -- [channels] SetMap[index: 255, color: [r:1, g:1, b:1]]; -- [white] SetMap[index: 254, color: [r:1, g:0, b:0]]; -- [pure red] SetMap[index: 253, color: [r:0, g:1, b:0]]; -- [pure green] SetMap[index: 252, color: [r:0, g:0, b:1]]; -- [pure blue] SetMap[index: 251, color: [r:1, g:1, b:0]]; -- [pure yellow] [] _ Terminal.SetColorCursorPresentation[Terminal.Current[], onesAreWhite]; END; SetUserColor: PUBLIC PROC [] = <<--makes a default color setup; reads user profile>> <<--does not set up the device>> BEGIN color[0].weight _ 1; color[0].r _ 0; color[0].g _ 0; color[0].b _ 0; color[1].weight _ 1; color[1].r _ 0; color[1].g _ 1; color[1].b _ 0; color[2].weight _ 1; color[2].r _ 0; color[2].g _ 0; color[2].b _ 1; color[3].weight _ 1; color[3].r _ 0.7; color[3].g _ 0.4; color[3].b _ 0.7; color[4].weight _1; color[4].r _ 1; color[4].g _ 0; color[4].b _ 0; color[5].weight _ 1; color[5].r _ 1; color[5].g _ 1; color[5].b _ 0; color[6].weight _ 0; color[6].r _ 0.4; color[6].g _ 0.5; color[6].b _ 0.5; END; CDSilColorCommand: Commander.CommandProc = BEGIN CreateAnInstance[]; END; CDSilColorComm: PROC [comm: CDSequencer.Command] = BEGIN CreateAnInstance[]; END; Init8Patterns[NIL]; SetUserColor[]; ComputeColors[]; CDSequencer.ImplementCommand[$SilColorTool, CDSilColorComm, CDSil.cdsil, dontQueue]; CDMenus.CreateEntry[$DisplayMenu, "sil 8 bit tool", $SilColorTool]; Commander.Register[ key: "CDSilColor", proc: CDSilColorCommand, doc: "cd sil 8 bit color tool" ]; END.