Skip to main content
Engineering LibreTexts

9.3: Composing and Interaction

  • Page ID
    43710
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Reusing Browsers

    One of Glamour’s strengths is to use browsers in place of primitive presentations such as lists and trees. This conveys formidable possibilities to compose and nest browsers.

    The subsequent example defines a class editor as shown in Figure \(\PageIndex{1}\). Panes 1 through 4 are equivalent to those described previously. Pane 5 shows the source code of the method that is currently selected in pane 4.

    Wireframe representation of the editor.
    Figure \(\PageIndex{1}\): Wireframe representation of a Smalltalk class editor.

    A new class PBE2CodeEditor will implement this editor. An editor will delegate the presentation of panes 1 through 4 to the previously implemented PBE2CodeNavigator. To achieve this, we first have to make the existing navigator return the constructed browser.

    PBE2CodeNavigator>>buildBrowser
        ...
        "new line"
        ^ browser
    

    We can then reuse the navigator in the new editor browser as shown below.

    Object subclass: #PBE2CodeEditor
        instanceVariableNames: 'browser'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'PBE2-CodeBrowser'.
    
    PBE2CodeEditor class>>open
        ^ self new open
    
    PBE2CodeEditor>>open
        self buildBrowser.
        browser openOn: self organizer
    
    PBE2CodeEditor>>organizer
        ^ RPackageOrganizer default
    
    PBE2CodeEditor>>buildBrowser
        browser := GLMTabulator new.
        browser
            row: #navigator;
            row: #source.
    
        browser transmit to: #navigator; andShow: [:a | self navigatorIn: a ].
    
    PBE2CodeEditor>>navigatorIn: constructor
        constructor custom: (PBE2CodeNavigator new buildBrowser) 
    

    The listing shows how the browser is used exactly like we would use a list or other type of presentation. In fact, browsers are a type of presentation.

    Evaluating PBE2CodeEditor open opens a browser that embeds the navigator in the upper part and has an empty pane at the lower part. Source code is not displayed yet because no connection has been made between the panes so far. The source code is obtained by wiring the navigator with the text pane: we need both the name of the selected method as well as the class in which it is defined. Since this information is defined only within the navigator browser, we must first export it to the outside world by using sendToOutside:from:. For this we append the following lines to codeNavigator:

    PBE2CodeNavigator>>buildBrowser
        ...
        browser transmit from: #classes; toOutsidePort: #selectedClass.
        browser transmit from: #methods; toOutsidePort: #selectedMethod.
    
        ^ browser 
    

    This will send the selection within classes and methods to the selectedClass and selectedMethod ports of the containing pane. Alternatively, we could have added these lines to the navigatorIn: method in the code editor—it makes no difference to Glamour as follows:

    PBE2CodeEditor>>navigatorIn: constructor
        "Alternative way of adding outside ports. There is no need to use this
        code and the previous one simultaneously."
    
        | navigator |
        navigator := PBE2CodeNavigator new buildBrowser
            sendToOutside: #selectedClass from: #classes -> #selection;
            sendToOutside: #selectedMethod from: #methods -> #selection;
            yourself.
    
    constructor custom: navigator 
    

    However, we consider it sensible to clearly define the interface on the side of the code navigator rather than within the code editor in order to promote the reuse of this interface as well.

    We extend our code editor example as follows:

    PBE2CodeEditor>>buildBrowser
        browser := GLMTabulator new.
        browser
            row: #navigator;
            row: #source.
    
        browser transmit to: #navigator; andShow: [:a | self navigatorIn: a].
        browser transmit
            from: #navigator port: #selectedClass;
            from: #navigator port: #selectedMethod;
            to: #source;
            andShow: [:a | self sourceIn: a].
    
    PBE2CodeEditor>>sourceIn: constructor
        constructor text
            display: [:class :method | class sourceCodeAt: method] 
    

    We can now view the source code of any selected method and have created a modular browser by reusing the class navigator that we had already written earlier. The composed browser described by the listing is shown in Figure \(\PageIndex{2}\).

    Composed browser that reuses the previously described class navigator.
    Figure \(\PageIndex{2}\): Composed browser that reuses the previously described class navigator to show the source of a selected method.

    Actions

    Navigating through the domain is essential to finding useful elements. However, having a proper set of available actions is essential to letting one interact with the domain. Actions may be defined and associated with a presentation. An action is a block that is evaluated when a keyboard shortcut is pressed or when an entry in a context menu is clicked. An action is defined via act:on: sent to a presentation:

    PBE2CodeEditor>>sourceIn: constructor
        constructor text
            display: [:class :method | class sourceCodeAt: method ];
            act: [:presentation :class :method | class compile: presentation text] on: $s.
    

    The argument passed to on: is a character that specifies the keyboard shortcut that should be used to trigger the action when the corresponding presentation has the focus. Whether the character needs to be combined with a meta-key—such as command, control or alt—is platform specific and does not need to be specified. The act: block provides the corresponding presentation as its first argument which can be used to poll its various properties such as the contained text or the current selection. The other block arguments are the incoming origins as defined by from: and are equivalent to the arguments of display: and when:.

    Actions can also be displayed as context menus. For this purpose, Glamour provides the messages act:on:entitled: and act:entitled: where the last argument is a string that should be displayed as the entry in the menu. For example, the following snippet extends the above example to provide a context menu entry to “save” the current method back to the class:

    ...
        act: [:presentation :class :method | class compile: presentation text]
        on: $s
        entitled: 'Save' 
    

    The contextual menu is accessible via the triangle downward-oriented above the text pane, located on the left hand side.

    Multiple Presentations

    Frequently, developers wish to provide more than one presentation of a specific object. In our code browser for example, we may wish to show the classes not only as a list but as a graphical representation as well. Glamour includes support to display and interact with visualizations created using the Mondrian visualization engine (presented in Chapter 12). To add a second presentation, we simply define it in the using: block as well:

    PBE2CodeNavigator>>classesIn: constructor
        constructor list
            when: [:packageName | self organizer includesPackageNamed: packageName ];
            display: [:packageName | (self organizer packageNamed: packageName)
                        definedClasses];
            title: 'Class list'.
    
        constructor mondrian
            when: [:packageName | self organizer includesPackageNamed: packageName];
            painting: [ :view :packageName |
                view nodes: (self organizer packageNamed: packageName)
                            definedClasses.
                view edgesFrom: #superclass.
                view treeLayout];
            title: 'Hierarchy'
    

    Glamour distinguishes multiple presentations on the same pane with the help of a tab layout. The appearance of the Mondrian presentation as embedded in the code editor is shown in Figure \(\PageIndex{3}\). The clause title: sets the name of the tab used to render the presentation.

    Code editor sporting a Mondrian presentation and simple class list.
    Figure \(\PageIndex{3}\): Code editor sporting a Mondrian presentation in addition to a simple class list.

    Other Browsers

    We have essentially used the GLMTabulator which is named after its ability to generate custom layouts using the aforementioned row: and column: keywords. Additional browsers are provided or can be written by the user. Browser implementations can be subdivided into two categories: browsers that have explicit panes, i.e.,, they are declared explicitly by the user—and browsers that have implicit panes.

    The GLMTabulator is an example of a browser that uses explicit panes. With implicit browsers, we do not declare the panes directly but the browser creates them and the connections between them internally. An example of such a browser is the Finder, which has been discussed in Section 10.1. Since the panes are created for us, we need not use the from:to: keywords but can simply specify our presentations:

    browser := GLMFinder new.
    
    browser list
        display: [:class | class subclasses].
    
    browser openOn: Collection
    

    The listing above creates a browser (shown in Figure \(\PageIndex{4}\)) and opens to show a list of subclasses of Collection. Upon selecting an item from the list, the browser expands to the right to show the subclasses of the selected item. This can continue indefinitely as long as something to select remains.

    Subclass navigator.
    Figure \(\PageIndex{4}\): Subclass navigator using Miller Columns style browsing.

    To discover other kinds of browsers, explore the hierarchy of the GLMBrowser class.


    This page titled 9.3: Composing and Interaction is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.