23.7 Presentation Translators

  • 23.7.1 Defining Presentation Translators
  • 23.7.2 Presentation Translator Functions
  • 23.7.3 Finding Applicable Presentations
  • 23.7.4 Translator Applicability
  • CLIM provides a mechanism for translating between types. In other words, within an input context for presentation type A the translator mechanism allows a programmer to define a translation from presentations of some other type B to objects that are of type A. [annotate]

    Note that the exact representation of a presentation translator has been left explicitly unspecified. [annotate]

    23.7.1 Defining Presentation Translators

    define-presentation-translator  name (from-type to-type command-table &key gesture tester tester-definitive documentation pointer-documentation menu priority) arglist &body body [Macro]
              

    Defines a presentation translator named name that translates from objects of type from-type to objects of type to-type. from-type and to-type are presentation type specifiers, but must not include any presentation type options. from-type and to-type may be presentation type abbreviations. [annotate]

    command-table is a command table designator. The translator created by this invocation of define-presentation-translator will be stored in the command table command-table. [annotate]

    gesture is a gesture name that names a pointer gesture (described in Section 22.3). The body of the translator will be run only if the translator is applicable and gesture used by the user matches the gesture name in the translator. (We will explain applicability, or matching, in detail below.) gesture defaults to :select. [annotate]

    tester is either a function or a list of the form
    (tester-arglist . tester-body)
    where tester-arglist takes the same form as arglist (see below), and tester-body is the body of the tester. The tester must return either true or false. If it returns false, then the translator is definitely not applicable. If it returns true, then the translator might be applicable, and the body of the translator might be run (if tester-definitive is false) in order to definitively decide if the translator is applicable (this is described in more detail below). If no tester is supplied, CLIM supplies a tester that always returns true. [annotate]

    Note: "(this is described in more detail below)", it says. Where? [edit]-- Christophe Rhodes 2007-01-09 12:38Z
     

    When the boolean tester-definitive is true, the body of the translator will never be run in order to decide if the translator is applicable, that is, the tester is assumed to definitively decide whether the translator applies. The default for tester-definitive is false. When there is no explicitly supplied tester, the tester supplied by CLIM is assumed to be definitive. [annotate]

    Both documentation and pointer-documentation are objects that will be used for documenting the translator. pointer-documentation will be used to generate documentation for the pointer documentation window; the documentation generated by pointer-documentation should be very brief and computing it should be very fast and preferably not cons. documentation is used to generate such things as items in the :menu-gesture menu. If the object is a string, the string itself will be used as the documentation. Otherwise, the object must be the name of a function or a list of the form
    (doc-arglist . doc-body)
    where doc-arglist takes the same form as arglist, but includes a named (keyword) stream argument as well (see below), and doc-body is the body of the documentation function. The body of the documentation function should write the documentation to stream. The default for documentation is nil, meaning that there is no explicitly supplied documentation; in this case, CLIM is free to generate the documentation in other ways. The default for pointer-documentation is documentation. [annotate]

    menu must be t or nil. When it is t, the translator will be included in the :menu-gesture menu if it matches. When it is nil, the translator will not be included in the :menu-gesture menu. Other non-nil values are reserved for future extensions to allow multiple presentation translator menus. [annotate]

    priority is either nil (the default, which corresponds to 0) or an integer that represents the priority of the translator. When there are several translators that match for the same gesture, the one with the highest priority is chosen. [annotate]

    arglist, tester-arglist, and doc-arglist are each an argument list that must "match" the following "canonical" argument list.
    (object &key presentation context-type frame event window x y)
    In order to "match" the canonical argument list, there must be a single positional argument that corresponds to the presentation's object, and several named arguments that must match the canonical names above (using string-equal to do the comparison). [annotate]

    Note:

    Keep in mind, that OBJECT is positional and mandatory, while the rest is checked for their canonical name with string-equal and is optional in the *-arglist.

    Also (it's stated above), documentation translator function has additional keyword STREAM.

    [edit]-- Daniel Kochmanski 2016-08-22 11:25Z
     

    In the body of the translator (or the tester), the positional object argument will be bound to the presentation's object. The named arguments presentation will be bound to the presentation that was clicked on, context-type will be bound to the presentation type of the context that actually matched, frame will be bound to the application frame that is currently active (usually *application-frame*), event will be bound to the pointer button event that the user used, window will be bound to the window stream from which the event came, and x and y will be bound to the x and y positions within window that the pointer was at when the event occurred. The special variable *input-context* will be bound to the current input context. Note that, in many implementations context-type and *input-context* will have dynamic extent, so programmers should not store without first copying them. [annotate]

    body is the body of the translator, and is run in the context of the application. body may have zero or more declarations as its first forms. It should return either one, two, or three values. The first value is an object which must be presentation-typep of to-type, and the second value is a presentation type that must be presentation-subtypep of to-type. The consequences are unspecified if the object is not presentation-typep of to-type or the type is not presentation-subtypep of to-type. The first two returned values of body are used, in effect, as the returned values for the call to accept that established the matching input context. [annotate]

    The third value returned by body must either be nil or a list of options (as keyword-value pairs) that will be interpreted by accept. The only option defined so far is :echo, whose value must be either true (the default) or false. If it is true, the object returned by the translator will be "echoed" by accept, which will use presentation-replace-input to insert the textual representation of the object into the input buffer. If it is false, the object will not be echoed. [annotate]

    None of define-presentation-translator's arguments is evaluated. [annotate]

    [annotate]

    define-presentation-to-command-translator  name (from-type command-name command-table &key gesture tester documentation pointer-documentation menu priority echo) arglist &body body [Macro]
              

    This is similar to define-presentation-translator, except that the to-type will be derived to be the command named by command-name in the command table command-table. command-name is the name of the command that this translator will translate to. [annotate]

    The echo option is a boolean value (the default is true) that indicates whether the command line should be echoed when a user invokes the translator. [annotate]

    The other arguments to define-presentation-to-command-translator are the same as for define-presentation-translator. Note that the tester for command translators is always assumed to be definitive, so there is no :tester-definitive option. The default for pointer-documentation is the string command-name with dash characters replaced by spaces, and each word capitalized (as in add-command-to-command-table). [annotate]

    The body of the translator must return a list of the arguments to the command named by command-name. body is run in the context of the application. The returned value of the body, appended to the command name, are eventually passed to execute-frame-command. body may have zero or more declarations as its first forms. [annotate]

    None of define-presentation-to-command-translator's arguments is evaluated. [annotate]

    [annotate]

    define-presentation-action  name (from-type to-type command-table &key gesture tester documentation pointer-documentation menu priority) arglist &body body [Macro]
              

    define-presentation-action is similar to define-presentation-translator, except that the body of the action is not intended to return a value, but should instead side-effect some sort of application state. [annotate]

    A presentation action does not satisfy a request for input the way an ordinary translator does. Instead, an action is something that happens while waiting for input. After the action has been executed, the program continues to wait for the same input that it was waiting for prior to executing the action. [annotate]

    The other arguments to define-presentation-action are the same as for define-presentation-translator. Note that the tester for presentation actions is always assumed to be definitive. [annotate]

    None of define-presentation-action's arguments is evaluated. [annotate]

    [annotate]

    define-drag-and-drop-translator  name (from-type to-type destination-type command-table &key gesture tester documentation pointer-documentation menu priority feedback highlighting) arglist &body body [Macro]
              

    Defines a "drag and drop" (or "direct manipulation") translator named name that translates from objects of type from-type to objects of type to-type when a "from presentation" is "picked up", "dragged" over, and "dropped" on to a "to presentation" having type destination-type. from-type, to-type, and destination-type are presentation type specifiers, but must not include any presentation type options. from-type, to-type and destination-type may be presentation type abbreviations. [annotate]

    The interaction style used by these translators is that a user points to a "from presentation" with the pointer, picks it up by pressing a pointer button matching gesture, drags the "from presentation" to a "to presentation" by moving the pointer, and then drops the "from presentation" onto the "to presentation". The dropping might be accomplished by either releasing the pointer button or clicking again, depending on the frame manager. When the pointer button is released, the translator whose destination-type matches the presentation type of the "to presentation" is chosen. For example, dragging a file to the TrashCan on a Macintosh could be implemented by a drag and drop translator. [annotate]

    While the pointer is being dragged, the function specified by feedback is invoked to provide feedback to the user. The function is called with eight arguments: the application frame object, the "from presentation", the stream, the initial x and y positions of the pointer, the current x and y positions of the pointer, and a feedback state (either :highlight to draw feedback, or :unhighlight to erase it). The feedback function is called to draw some feedback the first time pointer moves, and is then called twice each time the pointer moves thereafter (once to erase the previous feedback, and then to draw the new feedback). It is called a final time to erase the last feedback when the pointer button is released. feedback defaults to frame-drag-and-drop-feedback. [annotate]

    When the "from presentation" is dragged over any other presentation that has a direct manipulation translator, the function specified by highlighting is invoked to highlight that object. The function is called with four arguments: the application frame object, the "to presentation" to be highlighted or unhighlighted, the stream, and a highlighting state (either :highlight or :unhighlight). highlighting defaults to frame-drag-and-drop-highlighting. [annotate]

    Note that it is possible for there to be more than one drag and drop translator that applies to the same from-type, to-type, and gesture. In this case, the exact translator that is chosen for use during the dragging phase is unspecified. If these translators have different feedback, highlighting, documentation, or pointer documentation, the exact behavior is unspecified. [annotate]

    The other arguments to define-drag-and-drop-translator are the same as for define-presentation-translator. [annotate]

    Note:

    This specification does tell how the destination object is passed. If arglist is the same for define-presentation-translator, then it is (object &key  …).

    In "classic" CLIM (according to the comment in a source code), a keyword argument "DESTINATION-PRESENTATION" is passed from which we could take the object. Franz User's Guide specifies arglist to not have &key arguments and only matches them with string-equal. There are object and destination-object arguments covering this.

    McCLIM adopts Franz approach where arguments are matched by name. Both parameters destination-presentation and destination-object are supported.

    [edit]-- Daniel Kochmanski 2019-08-15 08:35Z
     

    [annotate]

    23.7.2 Presentation Translator Functions

    find-presentation-translators  from-type to-type command-table [Function]
              

    Returns a list of all of the translators in the command table command-table that translate from from-type to to-type, without taking into account any type parameters or testers. from-type and to-type are presentation type specifiers, and must not be abbreviations. frame must be an application frame. [annotate]

    Note: Probably "command-table must be a command table designator". [edit]-- DK 2019-05-20 09:10Z
     

    Implementation note: Because find-presentation-translators is called during pointer sensitivity computations (that is, whenever the user mouses the pointer around in any CLIM pane), it should cache its result in order to avoid consing. Therefore, the resulting list of translators should not be modified; the consequences of doing so are unspecified. [annotate]

    Implementation note: The ordering of the list of translators is left unspecified, but implementations may find it convenient to return the list using the ordering specified for find-applicable-translators. [annotate]

    [annotate]

    test-presentation-translator  translator presentation context-type frame window x y &key event modifier-state for-menu [Function]
              

    Returns true if the translator translator applies to the presentation presentation in input context type context-type, otherwise returns false. (There is no from-type argument because it is derived from presentation.) x and y are the x and y positions of the pointer within the window stream window. [annotate]

    event and modifier-state are a pointer button event and modifier state (see event-modifier-key-state), and are compared against the translator's gesture. event defaults to nil, and modifier-state defaults to 0, meaning that no modifier keys are held down. Only one of event or modifier-state may be supplied; it is unspecified what will happen if both are supplied. [annotate]

    If for-menu is true, the comparison against event and modifier-state is not done. [annotate]

    presentation, context-type, frame, window, x, y, and event are passed along to the translator's tester if and when the tester is called. [annotate]

    test-presentation-translator is responsible for matching type parameters and calling the translator's tester. Under some circumstances, test-presentation-translator may also call the body of the translator to ensure that its value matches to-type. [annotate]

    [annotate]

    find-applicable-translators  presentation input-context frame window x y &key event modifier-state for-menu fastp [Function]
              

    Returns a list that describes the translators that definitely apply to the presentation presentation in the input context input-context. Each element in the returned list is of the form
    (translator the-presentation context-type . rest)
    where translator is a presentation translator, the-presentation is the presentation that the translator applies to (and can be different from presentation due to nesting of presentations), context-type is the context type in which the translator applies, and rest is other unspecified data reserved for internal use by CLIM. translator, the-presentation, and context-type can be passed to such functions as call-presentation-translator and document-presentation-translator. [annotate]

    Since input contexts can be nested, find-applicable-translators must iterate over all the contexts in input-context. window, x, and y are as for test-presentation-translator. event and modifier-state (which default to nil and the current modifier state for window, respectively) are used to further restrict the set of applicable translators. (Only one of event or modifier-state may be supplied; it is unspecified what will happen if both are supplied.) [annotate]

    Presentations can also be nested. The ordering of the translators returned by find-applicable-translators is that translators matching inner contexts should precede translators matching outer contexts, and, in the same input context, inner presentations precede outer presentations. [annotate]

    When for-menu is non-nil, this matches the value of for-menu against the presentation's menu specification, and returns only those translators that match. event and modifier-state are disregarded in this case. for-menu defaults to nil. [annotate]

    When the boolean fastp is true, find-applicable-translators will simply return true if there are any translators. fastp defaults to false. [annotate]

    When fastp is false, the list of translators returned by find-applicable-translators must be in order of their "desirability", that is, translators having more specific from-types and/or higher priorities must precede translators having less specific from-types and lower priorities. [annotate]

    The rules used for ordering the translators returned by find-applicable-translators are as follows (in order): [annotate]

    1. Translators with a higher "high order" priority precede translators with a lower "high order" priority. This allows programmers to set the priority of a translator in such a way that it always precedes all other translators. [annotate]
    2. Translators with a more specific "from type" precede translators with a less specific "from type". [annotate]
    3. Translators with a higher "low order" priority precede translators with a lower "low order" priority. This allows programmers to break ties between translators that translate from the same type. [annotate]
    4. Translators from the current command table precede translators inherited from superior command tables. [annotate]

    Implementation note: find-applicable-translators could be implemented by looping over input-context, calling find-presentation-translators to generate all the translators, and then calling test-presentation-translator to filter out the ones that do not apply. The consequences of modifying the returned value are unspecified. Note that the ordering of translators can be done by find-presentation-translators, provided that find-applicable-translators takes care to preserve this ordering. [annotate]

    Minor issue: Describe and implement the class-nondisjoint-classes idea. Be very clear and precise about when the translator body gets run. --- SWM [annotate]

    [annotate]

    presentation-matches-context-type  presentation context-type frame window x y &key event modifier-state [Function]
              

    Returns true if there are any translators that translate from the presentation presentation's type to the input context type context-type, otherwise returns false. (There is no from-type argument because it is derived from presentation.) frame, window, x, y, event, and modifier-state are as for test-presentation-translator. [annotate]

    If there are no applicable translators, presentation-matches-context-type will return false. [annotate]

    [annotate]

    call-presentation-translator  translator presentation context-type frame event window x y [Function]
              

    Calls the function that implements the body of the translator translator on the presentation presentation's object, and passes presentation, context-type, frame, event, window, x, and y to the body of the translator as well. [annotate]

    The returned values are the same as the values returned by the body of the translator, namely, the translated object and the translated type. [annotate]

    [annotate]

    document-presentation-translator  translator presentation context-type frame event window x y &key (stream *standard-output*) documentation-type [Function]
              

    Computes the documentation string for the translator translator and outputs it to the stream stream. presentation, context-type, frame, event, window, x, and y are as for test-presentation-translator. [annotate]

    documentation-type must be either :normal or :pointer. If it is :normal, the usual translator documentation function is called. If it is :pointer, the translator's pointer documentation is called. [annotate]

    [annotate]

    call-presentation-menu  presentation input-context frame window x y &key for-menu label [Function]
              

    Finds all the applicable translators for the presentation presentation in the input context input-context, creates a menu that contains all of the translators, and pops up the menu from which the user can choose a translator. After the translator is chosen, it is called with the arguments supplied to call-presentation-menu and the matching input context that was established by with-input-context is terminated. [annotate]

    window, x, y, and event are as for find-applicable-translators. for-menu, which defaults to t, is used to decide which of the applicable translators will go into the menu; only those translators whose :menu option matches menu will be included. [annotate]

    label is either a string to use as a label for the menu, or is nil (the default), meaning the menu will not be labelled. [annotate]

    [annotate]

    23.7.3 Finding Applicable Presentations

    find-innermost-applicable-presentation  input-context window x y &key frame modifier-state event [Function]
              

    Given an input context input-context, an output recording window stream window, x and y positions x and y, returns the innermost presentation whose sensitivity region contains x and y that matches the innermost input context, using the translator matching algorithm described below. If there is no such presentation, this function will return nil. [annotate]

    event and modifier-state are a pointer button event and modifier state (see event-modifier-key-state). event defaults to nil, and modifier-state defaults to the current modifier state for window. Only one of event or modifier-state may be supplied; it is unspecified what will happen if both are supplied. [annotate]

    frame defaults to the current frame, *application-frame*. [annotate]

    The default method for frame-find-innermost-applicable-presentation will call this function. [annotate]

    [annotate]

    throw-highlighted-presentation  presentation input-context button-press-event [Function]
              

    Given a presentation presentation, input context input-context, and a button press event (which contains the window, pointer, x and y position of the pointer within the window, the button pressed, and the modifier state), find the translator that matches the innermost presentation in the innermost input context, then call the translator to produce an object and a presentation type. Finally, the matching input context that was established by with-input-context will be terminated. [annotate]

    Note that it is possible that more than one translator having the same gesture may be applicable to presentation in the specified input context. In this case, the translator having the highest priority will be chosen. If there is more than one having the same priority, it is unspecified what translator will be chosen. [annotate]

    [annotate]

    highlight-applicable-presentation  frame stream input-context &optional prefer-pointer-window [Function]
              

    This is the core of the "input wait" handler used by with-input-context on behalf of the application frame frame. It is responsible for locating the innermost applicable presentation on stream in the input context input-context, unhighlighting presentations that are not applicable, and highlighting the presentation that is applicable. Typically on entry to highlight-applicable-presentation, input-context will be the value of *input-context* and frame will be the value of *application-frame*. [annotate]

    If prefer-pointer-window is true (the default), CLIM will highlight the applicable presentation on the same window that the pointer is located over. Otherwise, CLIM will highlight an applicable presentation on stream. [annotate]

    Implementation note: This will probably use frame-find-innermost-applicable-presentation-at-position to locate the innermost presentation, and unhighlight-highlighted-presentation and set-highlighted-presentation to unhighlight and highlight presentations. [annotate]

    [annotate]

    set-highlighted-presentation  stream presentation &optional prefer-pointer-window [Function]
              

    Highlights the presentation presentation on stream. This must call highlight-presentation methods if that is appropriate. [annotate]

    prefer-pointer-window is as for highlight-applicable-presentation. [annotate]

    [annotate]

    unhighlight-highlighted-presentation  stream &optional prefer-pointer-window [Function]
              

    Unhighlights any highlighted presentations on stream. [annotate]

    prefer-pointer-window is as for highlight-applicable-presentation. [annotate]

    [annotate]

    23.7.4 Translator Applicability

    The top-level "input wait", which is what you are in when inside of a with-input-context, is responsible for determining what translators are applicable to which presentations in a given input context. This loop both provides feedback in the form of highlighting sensitive presentation, and is responsible for calling the applicable translator when the user presses a pointer button. [annotate]

    Implementation note: with-input-context uses frame-find-innermost-applicable-presentation-at-position (via highlight-applicable-presentation) as its "input wait" handler, and frame-input-context-button-press-handler as its button press "event handler". [annotate]

    Given a presentation, an input context established by with-input-context, and an event corresponding to a user gesture, translator matching proceeds as follows. [annotate]

    The set of candidate translators is initially those translators accessible in the command table in use by the current application. A translator is said to "match" if all of the following are true (in this order): [annotate]

    1. The presentation's type is presentation-subtypep of the translator's from-type, ignoring type parameters. [annotate]
    2. The translator's to-type is presentation-subtypep of the input context type, ignoring type parameters. [annotate]
    3. The translator's gesture is either t, or matches the event corresponding to the user's gesture. [annotate]
    4. If there are parameters in the from-type, the presentation's object must be presentation-typep of the from-type. [annotate]
    5. The translator's tester returned true. If there is no tester, the translator behaves as though there is a tester that always returns true. [annotate]
    6. If there are parameters in the input context type and the tester is not declared to be definitive, the value returned by body of the translator must be presentation-typep of the context type. [annotate]

    Note that the type parameters from the presentation's type have no effect on translator lookup. [annotate]

    find-presentation-translator is responsible for the first two steps of the matching algorithm, and test-presentation-translator is responsible for the remaining steps. [annotate]

    When a single translator is being chosen (such as is done by throw-highlighted-presentation), it is possible that more than one translator having the same gesture may be applicable to the presentation in the specified input context. In this case, the translator having the highest priority will be chosen. If there is more than one having the same priority, it is unspecified what translator will be chosen. [annotate]

    The matching algorithm is somewhat more complicated in face of nested presentations and nested input contexts. In this case, the applicable presentation is the smallest presentation that matches the innermost input context. [annotate]

    Sometimes there may be nested presentations that have exactly the same bounding rectangle. In this case, it is not possible for a user to unambiguously point to just one of the nested presentations. Therefore, when CLIM has located the innermost applicable presentation in the innermost input context, it must then search for outer presentations having exactly the same bounding rectangle, checking to see if there are any applicable translators for those presentations. If there are multiple applicable translators, the one having the highest priority is chosen. find-applicable-translators, call-presentation-menu, throw-highlighted-presentation, and the computation of pointer documentation must all take this situation into account. [annotate]

    The translators are searched in the order that they are returned by find-presentation-translators. The rules for the ordering of the translators are described under that function. [annotate]