Search code examples
rebolrebol2

VID layout pane supporting multiple face creations [rebol2]


Please consider this simple rebol2 code to illustrate my problem:

REBOL []
a: make face [
    offset: 0x0
    color: yellow
    size: 20x20
]
b: make face [
    offset: 0x0
    color: red
    size: 60x60
    pane: reduce [
        make a [offset: 0x0]
        make a [offset: 10x10]
        make a [offset: 10x20]
    ]
]
view layout [
    box 200x200 white with [
        pane: reduce [
            make b [offset: 0x30] ;; one 'instance' of b
        ]
    ]
]

The main point here is for a layout (or face) to be able to display a bunch of faces inside its pane block in such a manner that multiple creations of the same face (b in this case) should be possible. The shown code works well, and the only instance (let me call it this way) of b is displayed as it should be.

But now suppose I change the code so I have, say, 2 instances of b:

view  layout [
    box 200x200 white with [
        pane: reduce [
            make b [offset: 0x30]
            make b [offset: 0x10]
        ]
    ]
]

At this point I get the error

** Script Error: Face object reused (in more than one pane): none
** Where: view
** Near: show scr-face
if new [do-events]

From the message I presume here that face b is somehow getting reused and messing exactly what I'm trying to achieve. I've done lots of research on this and at some point I found that it is possible to get around it by cloning (using make) the face to be passed to pane; that's what I thought I was doing, but with no success at all.

Given this scenario, my question is: how can I go about to solve this? is rebol2 ok to provide this "face-instantiation" or it is best to try something else outside rebol2 (perhaps rebol3)?

Any help will be greatly appreciated.


Solution

  • As is already pointed out the problem is that a is reused, not b!

    the layout function uses a field called init for handling things like this. As I understand it init is first bound to the face and then called with do after the face itself is instantiated (at least partially).

    In this case I would be using the style command in layout (still partially using face object a )

    view layout [
        style
            bb box 60x60
            with [
                append init [
                    pane reduce [
                        make a [offset: 0x0]
                        make a [offset: 10x10]
                        make a [offset: 10x20]
                   ]
                ]
            ]
        panel 200x200 white [
            at 30x0 bb
            at 0x0  bb
        ]
    ]
    

    The other alternative, a bit more similar to your would be:

    b: make face [
        offset: 0x0
        color: red
        size: 60x60
        init: [
            pane: reduce [
                make a [offset: 0x0]
                make a [offset: 10x10]
                make a [offset: 10x20]
            ]
        ]
    ]
    view layout [
        box 200x200
        with [
            append init [
                pane: reduce [
                    make b [ offset: 0x0 do init ]
                    make b [ offset: 0x60 do init ]
                ]
            ]
        ]
     ]
    

    Note that init is manually called within the make clause in this case. I'm not all sure why it is needed. Finally the everything could elegantly be solved with style

    view layout [
        style a box yellow 20x20
        style b panel red 60x60 [
            at 0x0 a   ; we can in this style use the just defined a style
            at 10x10 a
            at 10x20 a
        ]
        at 0x0 b
        at 0x60 b
    ]