Skip to main content
Engineering LibreTexts

4.4: Organizing Your Settings

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

    Within the Settings Browser, settings are organized in trees where related settings are shown as children of the same parent.

    Declaring a parent

    The simplest way to declare your setting as a child of another setting is to use the parent: message with the identifier of the parent setting passed as argument. In the example below, the parent node is an existing node declared with the #codeEditing identifier.

    CodeHolderSystemSettings class>>caseSensitiveFindsSettingsOn: aBuilder
        <systemsettings>
        (aBuilder setting: #caseSensitiveFinds)
            target: TextEditor;
            label: 'Case sensitive search' translated;
            description: 'If true, then the "find" command in text will always make its searches in
            a case-sensitive fashion' translated;
            parent: #codeEditing.
    

    The #codeEditing node is also declared somewhere in the system. For example, it could be defined as a group as we will see now.

    Declaring a group

    A group is a simple node without any value and which is only used for children grouping. The node identified by #codeEditing is created by sending the group: message to the builder with its identifier passed as argument. Notice also that, as shown in Figure 5.3.1, the #codeEditing node is not at root because it has declared itself as a child of the #codeBrowsing node.

    CodeHolderSystemSettings class>>codeEditingSettingsOn: aBuilder
        <systemsettings>
        (aBuilder group: #codeEditing)
            label: 'Editing' translated;
            parent: #codeBrowsing.
    

    Declaring a sub-tree

    Being able to declare its own settings as a child of a pre-existing node is very useful when a package wants to enrich existing standard settings. But it can also be very tedious for settings which are very application specific.

    Thus, directly declaring a sub-tree of settings in one method is also possible. Typically, a root group is declared for the application settings and the children settings themselves are also declared within the same method. This is simply done through the sending of the with: message to the root group. The with: message takes a block as argument. In this block, all new settings are implicitly declared as children of the root group (the receiver of the with: message).

    Declaring a subtree.
    Figure \(\PageIndex{1}\): Declaring a subtree in one method: the Configurable formatter setting example.

    As an example, take a look at Figure \(\PageIndex{1}\), it shows the settings for the refactoring browser configurable formatter. This sub-tree of settings is fully declared in the method RBConfigurableFormatter class>>settingsOn: given below. You can see that it declares the new root group #configurableFormatter with two children, #formatCommentWithStatements and #indentString:

    RBConfigurableFormatter class>>settingsOn: aBuilder
        <systemsettings>
        (aBuilder group: #configurableFormatter)
            target: self;
            parent: #refactoring;
            label: 'Configurable Formatter' translated;
            description: 'Settings related to the formatter' translated;
            with: [
                (aBuilder setting: #formatCommentWithStatements)
                    label: 'Format comment with statements' translated.
                (aBuilder setting: #indentString)
                    label: 'Indent string' translated]
    

    Optional sub-tree

    Depending on the value of a particular preference, one might want to hide some settings because it doesn’t make sense to show them. As an example, if the background color of the desktop is plain then it doesn’t make sense to show settings which are related to the gradient background. Instead, when the user wants a gradient background, then a second color, the gradient direction, and the gradient origin settings should be presented. Look at the Figure \(\PageIndex{2}\):

    • on the left, the Gradient widget is unchecked, meaning that its actual value is false; in this case, it has no children,
    • on the right, the Gradient widget is checked, then the setting value is set to true and as a consequence, the settings useful to set a gradient background are shown.
    An optional subtree.
    Figure \(\PageIndex{2}\): Example of optional subtree. Right - no gradient is selected. Left - gradient is selected so additional preferences are available.

    To handle such optional settings is simple: optional settings should be declared as children of a boolean parent setting. In this case, children settings are shown only if the parent value is true. Concerning the desktop gradient example, the setting is declared in PolymorphSystemSettings as given below:

    (aBuilder setting: #useDesktopGradientFill)
        label: 'Gradient';
        description: 'If true, then more settings will be available to define the desktop
        background color gradient';
        with: [
            (aBuilder setting: #desktopGradientFillColor)
                label: 'Other color';
                description: 'This is the second color of your gradient (the first one is given by
                the "Color" setting' translated.
            (aBuilder pickOne: #desktopGradientDirection)
                label: 'Direction';
                domainValues: {#Horizontal. #Vertical. #Radial}.
            (aBuilder pickOne: #desktopGradientOrigin)
                label: 'Origin';
                domainValues: {
                    'Top left' translated -> #topLeft. ...
    

    The parent setting value is given by evaluating PolymorphSystemSettings class >>useDesktopGradientFill. If it returns true, then the children #desktopGradientFillColor, #desktopGradientDirection, and #desktopGradientOrigin are shown.

    Ordering your settings

    By default, sibling settings are sorted alphabetically by their label. You may want to change this default behavior. Changing the settings ordering can be done two ways: by simply forbidding the default ordering or by explicitly specifying an order.

    As in the following example of the #appearance group, you can indicate that no ordering should be performed by sending the noOrdering message to the parent node.

    appearanceSettingsOn: aBuilder
        <systemsettings>
        (aBuilder group: #appearance)
            label: 'Appearance' translated;
            description: 'All settings concerned with the look''n feel of your system' translated;
            noOrdering;
            with: [... ]
    

    You can indicate the order of a setting node among its siblings by sending the message order: to it with a number passed as argument. The number can be an Integer or a Float. Nodes with an order number are always placed before others and are sorted according to their respective order number. If an order is given to an item, then no ordering is applied for other siblings.

    As an example, take a look at how the #standardFonts group is declared:

    (aBuilder group: #standardFonts)
        label: 'Standard fonts' translated;
        target: StandardFonts;
        parent: #appearance;
        with: [
            (aBuilder launcher: #updateFromSystem)
                order: 1;
                targetSelector: #current;
                script: #updateFromSystem;
                label: 'Update fonts from system' translated.
            (aBuilder setting: #defaultFont)
                label: 'Default' translated.
            (aBuilder setting: #codeFont)
                label: 'Code' translated.
            (aBuilder setting: #listFont)
        ...
    

    In this example, the launcher #updateFromSystem is declared to be the first node, then other siblings with identifiers #defaultFont, #codeFont, and #listFont are placed according to the declaration order.


    This page titled 4.4: Organizing Your Settings 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.