10.11 Using hyper links to relate objects

A hyper is a binary relation between two objects. Hypers are, like connection objects, guarded automatically against destruction of one of the related objects. Special methods allow for easy communication between hypered objects.

Hypers form an adequate answer if objects need to be related that depend temporary and incidentally on each other. It is possible to be informed of the destruction of hypers, which enables a hypered object to keep track of its environment. Good examples for the usage of hypers are to express the relation between multiple frame objects working together to form a single application or maintaining the relation between an application object (persistent object, model) and its visualisation (controller).

Of course relations between objects can be maintained using instance-variables, but this process requires awareness from both related objects as well as significant bookkeeping.

10.11.1 Programming existence dependencies

The example of this section demonstrates a common existence relationship. If the `main' object is destroyed, all related `part' objects should be destroyed too, but if a part is destroyed, the main should not be destroyed. This semantic is expressed using a refinement of class hyper that can be found in library(hyper) of the XPCE/Prolog libraries.

:- pce_begin_class(partof_hyper, hyper,
                   "<-to is a part of <-from").

unlink_from(H) :->
        "->destroy the <-to part"::
        get(H, to, Part),
        (   object(Part),
            send(Part, has_send_method, destroy)
        ->  send(Part, destroy)
        ;   free(Part)
        ),
        free(H).

:- pce_end_class.

This hyper is demonstrated in the following application. We have an application for editing a graphical representation. The colour of the objects can be modified by double-clicking an object and selecting a colour in a dialog window. In this example we do not use a modal dialog and using the hyper serves two purposes. First of all it tells the dialog what object should be changed, but second, it ensures the dialog is destroyed if the box is.

:- use_module(library(hyper)).

:- pce_begin_class(link_demo, picture).

initialise(P) :->
        send_super(P, initialise, 'Link Demo'),
        send(P, recogniser,
             click_gesture(left, '', single,
                           message(P, add_box, @event?position))).

add_box(P, At:point) :->
        send(P, display, new(link_box), At).

:- pce_end_class(link_demo).

:- pce_begin_class(link_box, box).

handle(w/2, 0, link, north).
handle(w/2, h, link, south).
handle(0, h/2, link, west).
handle(w, h/2, link, east).

initialise(B) :->
        send_super(B, initialise, 100, 50),
        send_list(B, recogniser,
                  [ click_gesture(left, '', double,
                                  message(B, edit)),
                    new(connect_gesture),
                    new(move_gesture)
                  ]).

colour(red).
colour(green).
colour(blue).
colour(yellow).

edit(B) :->
        "Allow changing colour"::
        new(D, dialog('Select colour')),
        send(D, append, new(M, menu(colour, choice,
                                    message(?(D, hypered, box),
                                            fill_pattern,
                                            @arg1)))),
        (   colour(Colour),
            send(M, append,
                 menu_item(colour(Colour),
                           @default,
                           pixmap(@nil,
                                  background := Colour,
                                  width := 32,
                                  height := 16))),
            fail
        ;   true
        ),
        send(D, append, button(done, message(D, destroy))),
        new(_, partof_hyper(B, D, dialog, box)),
        get(B, display_position, PosB),
        get(PosB, plus, point(20,100), PosD),
        send(D, open, PosD).

:- pce_end_class(link_box).

Figure 19 : Using a hyper to link a window to an object

10.11.2 Methods for handling hyper objects

10.11.2.1 Methods on class hyper

hyper ->initialise: F:object, T:object, FName:name, TName:[name]
Create a new hyper object. Seen from F, this hyper is called FName; seen from T it is called TName. The default for TName is FName.
hyper ->unlink_from:
Called by the object-management system when the <-from side of the hyper is being destroyed. May be refined.
hyper ->unlink_to:
Called by the object-management system when the <-to side of the hyper is being destroyed. May be refined.

10.11.2.2 Methods on class object

Below are the two most commonly used methods dealing with hypers and defined on class object. XPCE defines various other methods for deleting and inspecting the hyper structure. Use the online manual for details.

object ->send_hyper: Name:[name], Selector:name, Arg:unchecked ...
Broadcast a send-operation to all (named) <-hypered objects. Similar to <-get_hyper, but does not stop if the method is received successfully. Succeeds if at least one hypered object accepted the message.
object <-hypered: Name:[name], Test:[code]
object Find a hyper-related object. Name is the name of the hyper (seen from the side of the receiver). Test is an optional additional test. If present, this test is executed using the arguments given below. The first matching object is returned. See also <-all_hypers.

@arg1 This object
@arg2 The hyper object
@arg3 The object at the other end of the hyper