Login
  • Username:

    Password:
  • Remember my login on this computer
  • Register

R3 GUI actor overriding techniques

Contents

[edit] R3 GUI Actor overriding techniques

First author: Richard Smolak 4-May-2011/18:07:31 2:00

NOTE: this guide is obsolete, some function in examples are no longer in Rebol3. Read also R3 GUI Actor and Reactor design changes to adapt the example shown to the current code

[edit] Introduction

During the R3 GUI application development there are situations where you may look for a way how to override the default functionality of an actor in a specific style.


There are two possible techniques how to do it depending on your preferences.


[edit] Overriding techniques

We will use a simple example to demonstrate both overriding techniques. Let's have the following layout:


view [
        field
        text-list [
                "Robert"
                "Bolek"
                "Richard"
                "Ladislav"
        ]
]

Image:r3gaot1.jpg

The code above shows a simple field and a list of names in a window. We want to use a matching filter on the names in the list every time the user types some character in the field.


[edit] Overriding actor functionality using the STYLIZE function

This technique is useful in case you want to separate the newly added actor code from the layout dialect or if you plan to derive new styles based on the additional code.


Here is a possible solution:


stylize [
        filter-field: field [
                actors: [
                        on-key: [
                                ;execute the 'original' actor of FIELD style
                                do-style/style face 'on-key arg 'field

                                ;apply the matching filter on my-list
                                val: get-face face
                                set-face/field my-list either empty? val [
                                        [1 [true]]
                                ] [
                                        compose/deep [1 [find/match value (val)]]
                                ] 'filter
                        ]
                ]
        ]
]

view [
        filter-field
        my-list: text-list [
                "Robert"
                "Bolek"
                "Richard"
                "Ladislav"
        ]
]



The example above works well but there is one issue. The my-list name is hardcoded into the definition of the new style ON-KEY actor which is not good, since it can work only in case the MY-LIST name is defined and refers to the list related to the filter field.


We should refine the example to be reusable. For that purpose we can use the attach reactor to achieve a more general and system-friendly functionality:


stylize [
        filter-field: field [
                actors: [
                        on-init: [
                                ;execute the 'original' actor of FIELD style
                                do-style/style face 'on-init arg 'field

                                ;get the attached text-list face
                                foreach cmd face/reactors [
                                        if all [
                                                cmd/1 = 'attach
                                                target: get cmd/2
                                                target/style = 'text-list
                                        ] [
                                                set-facet face 'target target
                                                break
                                        ]
                                ]
                        ]
                        on-key: [
                                ;execute the 'original' actor of FIELD style
                                do-style/style face 'on-key arg 'field

                                if target: get-facet face 'target [
                                        ;apply the matching filter on the target list
                                        val: get-face face
                                        set-face/field target either empty? val [
                                                [1 [true]]
                                        ] [
                                                compose/deep [1 [find/match value (val)]]
                                        ] 'filter
                                ]
                        ]
                ]
        ]
]

view [
        filter-field attach 'my-list
        my-list: text-list [
                "Robert"
                "Bolek"
                "Richard"
                "Ladislav"
        ]
]


The above example works with any text-list face which is attached to a filter-field. Also, the filter-field can be used as a base for new styles. Notice the code used in stylize is also longer and more complex, because in fact we derived a new child style from the FIELD parent style.


[edit] Inline overriding using the layout dialect

Sometimes you don't want to create a new derived style. This can be handy in the following conditions:


  • you intend to use the changed behavior just once, and
  • don't want to use the changed actor behavior as a base for new styles


Here is a possible solution:


match-filter: func [
        list [object!]
        value [string!]
] [
        ;apply the matching filter on my-list
        set-face/field list either empty? value [
                [1 [true]]
        ] [
                compose/deep [1 [find/match value (value)]]
        ] 'filter
]

view [
        field on-key [
                ;execute the 'original' actor of the field
                do-style face 'on-key arg
                ;call the filtering function
                match-filter my-list get-face face
        ]
        my-list: text-list [
                "Robert"
                "Bolek"
                "Richard"
                "Ladislav"
        ]
]


In the above code the ON-KEY word in the layout dialect means you want to override the on-key actor of the FIELD style, i.e., instead of the original actor, the given code will be evaluated.


You can override any other existing actor using the same approach. The actor name is then followed by a block which is used instead of the original ON-KEY actor block defined in the FIELD style.


In this case we don't mind whether the inline block contains any application specific code.


Same as with the original style actor, you are free to put any code into the inline actor block.


For example, you can call the original actor before or after your application-dependent code. Or even don't call the original style actor at all or chain multiple actor calls and so on. It all depends on your needs.