rnso
rnso

Reputation: 24545

How to keep colors of previous lines in Rebol/Red

I am trying to draw lines of different colors in modified paint program:

REBOL [title: "Paint"]
mycol: black
view layout [ size 1100x700
    s: area 1060x600 white feel [
        engage: func [f a e] [
            if a = 'over [append s/effect/draw e/offset  show s]
            if a = 'up [append s/effect/draw 'line]
        ]
    ] effect [draw [pen mycol line]]
    across
    btn "Clear" 100x50 [s/effect/draw: copy [line] show s]
    btn "Red" 100x50 [set [to-word mycol] red]
    btn "blue" 100x50 [set [to-word mycol] blue]
    btn "magenta" 100x50 [set [to-word mycol] magenta]
    btn "green" 100x50 [set [to-word mycol] green]
    btn "yellow" 100x50 [set [to-word mycol] yellow]
    btn "orange" 100x50 [set [to-word mycol] orange]
    btn "Quit" 100x50 [quit]
]

However, when I select a color, all lines in area change color. How can I modify so that earlier lines remain of same color?

Upvotes: 1

Views: 85

Answers (2)

rgchris
rgchris

Reputation: 3718

The Draw dialect is a cumulative description of a drawing. In your example, you only set the pen colour once and all lines thereafter inherit said colour. As you set the pen colour using the word mycol, all your lines are set to whatever colour that word refers to once the face display is updated (show s in your code above).

Can break things down a little here to understand some of the operations:

The Drawing

Let's initiate the drawing in it's own object with the current colour.

drawing: make object! [
    image: []
    color: black
    use: func [new [tuple!]][
        append image reduce ['pen color: new]
    ]
    reset: does [
        clear image
        use color
    ]
    reset
]

Here we have everything we need to manage the settings of the drawing:

image — the drawing itself (in the Draw dialect).

color — the current pen colour.

use — a function to change the current color and apply it to the drawing.

reset — clears the drawing.

The Canvas

Our canvas will be a simple BOX face which will contain the drawing:

box 1060x600 white
effect reduce ['draw drawing/image]

And will react to down and over actions passed via the Engage function:

feel [
    engage: func [face action event] [
        switch action [
            down [append drawing/image 'line]
            over [append drawing/image event/offset show face]
        ]
    ]
]

(I've changed the engage parameters here to their full names—there's little efficiency gained and much expressivity lost in Rebol/Red using one-letter words)

This should work as per the engage function in your example except that new lines are started on a down action.

Actions

Our 'Clear' button engages the drawing object and resets the canvas (the button's oldest sibling):

btn "Clear" 100x50 [
    drawing/reset
    show first face/parent-face/pane
]

Just for a little interface sugar, we'll use toggles to indicate the current colour. You can create a mutual relationship between toggles using the of keyword:

tog of 'color "Red"     100x50 [drawing/use red]
tog of 'color "Blue"    100x50 [drawing/use blue]
tog of 'color "Magenta" 100x50 [drawing/use magenta]
tog of 'color "Green"   100x50 [drawing/use green]
tog of 'color "Yellow"  100x50 [drawing/use yellow]
tog of 'color "Orange"  100x50 [drawing/use orange]

Bringing It Together

Can wrap this up in a script:

Rebol [Title: "Paint"]

drawing: make object! [
    image: []
    color: black
    use: func [new [tuple!]][
        append image reduce ['pen color: new]
    ]
    reset: does [
        clear image
        use color
    ]
    reset
]

view layout [
    box 1060x600 white
    effect reduce ['draw drawing/image]
    feel [
        engage: func [face action event] [
            switch action [
                down [append drawing/image 'line]
                over [append drawing/image event/offset show face]
            ]
        ]
    ]
    across
    btn "Clear" 100x50 [drawing/reset show face/parent-face/pane/1]
    tog of 'color "Red"     100x50 [drawing/use red]
    tog of 'color "Blue"    100x50 [drawing/use blue]
    tog of 'color "Magenta" 100x50 [drawing/use magenta]
    tog of 'color "Green"   100x50 [drawing/use green]
    tog of 'color "Yellow"  100x50 [drawing/use yellow]
    tog of 'color "Orange"  100x50 [drawing/use orange]
    btn "Quit" 100x50 [unview]
]

Upvotes: 4

sqlab
sqlab

Reputation: 6436

A minimal example looks like this

view layout [
    s: area white feel [
        engage: func [f a e] [
            if a = 'over [append s/effect/draw e/offset  show s]
            if a = 'up [append s/effect/draw 'line]
        ]
    ] effect [draw [pen blue line]]
    btn "Clear" [s/effect/draw: copy [line] show s]
    btn "Red" [append s/effect/draw [pen red line]]
]

So your script should be

view layout [ size 1100x700
    s: area 1060x600 white feel [
        engage: func [f a e] [
            if a = 'over [append s/effect/draw e/offset  show s]
            if a = 'up [append s/effect/draw 'line]
        ]
    ] effect [draw [pen black line]]
    across
    btn "Clear" 100x50 [s/effect/draw: copy [line] show s]
    btn "Red" 100x50 [append s/effect/draw [pen red line]]
    btn "blue" 100x50 [append s/effect/draw [pen blue line]]
    btn "magenta" 100x50 [append s/effect/draw [pen magenta line]]
    btn "green" 100x50 [append s/effect/draw [pen gree line]]
    btn "yellow" 100x50 [append s/effect/draw [pen yellow line]]
    btn "orange" 100x50 [append s/effect/draw [pen orange line]]
    btn "Quit" 100x50 [quit]
]

Upvotes: 1

Related Questions