Skip to main content
Engineering LibreTexts

4.5: Providing More Precise Value Domain

  • Page ID
    43810
  • \( \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}}\)

    By default, the possible value set of a preference is not restricted and is given by the actual type of the preference. For example, for a color preference, the widget allows you to choose whatever color. For a number, the widget allows the user to enter any number. But in some cases, only a particular set of values is desired. As an example, for the standard browser or for the user interface theme settings, the choice must be made among a finite set of classes, for the free type cache size, only a range from 0 to 50,000 is allowed. In these cases, it is much more comfortable if the widget can only accept particular values. To address this issue, the domain value set can be constrained either with a range or with a list of values.

    Declaring a range setting

    As an example, let’s consider the full screen margin preference shown in the Figure \(\PageIndex{1}\). Its value represents the margin size in pixels that is left around a window when it is expanded.

    A range setting.
    Figure \(\PageIndex{1}\): Example of range setting.

    Its value is an integer, but it makes no sense to set -100 or 5000 to it. Instead, a minimum of -5 and a maximum of 100 constitute a good range of values. One can use this range to constrain the setting widget. As shown by the example below, comparing it to a simple setting, the only two differences are that:

    • the new setting node is created with the range: message instead of the setting: message and
    • the valid range is given by sending the range: message to the setting node, an Interval is given as argument;
    screenMarginSettingOn: aBuilder
        <systemsettings>
        (aBuilder range: #fullScreenMargin)
            target: SystemWindow;
            parent: #windows;
            label: 'Full screen margin' translated;
            description: 'Specify the amount of space that is left around a windows when it''s
            opened fullscreen' translated;
            range: (-5 to: 100).
    

    Selecting among a list

    When a preference value is constrained to be one of a particular list of values, it is possible to declare it so that a drop list is used by the settings browser. This drop list is initialized with the predefined valid values. As an example, consider the window position strategy example. The corresponding widget is shown in action within the settings browser by Figure \(\PageIndex{2}\). The allowed values are 'Reverse Stagger', 'Cascade', or 'Standard'.

    A list setting.
    Figure \(\PageIndex{2}\): Example of a list setting.

    The example below shows a simplified declaration for the window position strategy setting.

    windowPositionStrategySettingsOn: aBuilder
        <systemsettings>
        (aBuilder pickOne: #usedStrategy)
            label: 'Window position strategy' translated;
            target: RealEstateAgent;
            domainValues: #(#'Reverse Stagger' #Cascade #Standard) 
    

    comparing to a simple setting, the only two differences are that:

    • the new setting node is created with the pickOne: message instead of the #setting: message and
    • the list of authorized values is given by sending the domainValues: message to the newly declared setting node, a Collection is given as argument (the default value being the first one).

    Concerning this window strategy example, the value set to the preference would be either #’Reverse Stagger’ or #Cascade or #Standard.

    Unfortunately, these values are not very handy. A programmer may expect another value. For example, some kind of strategy object or a Symbol which could directly serve as a selector. In fact, this second solution has been chosen by the RealEstateAgent class maintainers. If you inspect the value returned by RealEstateAgent usedStrategy you will realize that the result is not a Symbol among #’Reverse Stagger’, #Cascade, or #Standard but another symbol. Then, if you look at the way the window position strategy setting is really implemented you will see that the declaration differs from the basic solution given previously: the domainValues: argument is not a simple array of Symbols but an array of Associations as you can see in the declaration below:

    windowPositionStrategySettingsOn: aBuilder
        <systemsettings>
        (aBuilder pickOne: #usedStrategy)
        ...
        domainValues: {'Reverse Stagger' translated -> #staggerFor:initialExtent:world:. '
            Cascade' translated -> #cascadeFor:initialExtent:world:. 'Standard' translated ->
            #standardFor:initialExtent:world:};
    

    From the Settings Browser point of view, the content of the list is exactly the same and the user can not notice any difference because, if an array of Associations is given as argument to domainValues:, then the keys of the Associations are used for the user interface.

    Concerning the value of the preference itself, if you inspect RealEstateAgent usedStrategy, you should notice that the result is a value among #staggerFor:initialExtent:world:, #cascadeFor:initialExtent:world: and #standardFor:initialExtent:world:. In fact, the values of the Associations are used to compute all possible real values for the setting.

    The list of possible values can be of any kind. As another example, let’s take a look at the way the user interface theme setting is declared in the PolymorphSystemSettings class:

    (aBuilder pickOne: #uiThemeClass)
        label: 'User interface theme' translated;
        target: self;
        domainValues: (UITheme allThemeClasses collect: [:c | c themeName -> c]) 
    

    In this example, domainValues: takes an array of associations which is computed each time a Settings Browser is opened. Each association is made of the name of the theme as key and of the class which implements the theme as value.


    This page titled 4.5: Providing More Precise Value Domain 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.