Glimmr Canvas Editor

version 1/100805 by Erik Temple

  • Home page
  • Beginning
  • Previous



  • Chapter - Selecting the color

    A clicking graphlink rule when the current graphlink window is the drawing-window and color-picker mode is true (this is the color-picker clicking rule):
        repeat through the Table of Graphlink Glulx Replacement Commands in reverse order:
            if the current graphlink window is g-win entry:
                if the current graphlink x >= p-left entry and the current graphlink x <= p-right entry and the current graphlink y >= p-top entry and the current graphlink y <= p-bottom entry:
                    change the current graphlink to linkid entry;
                    if the current graphlink is a color-chip:
                        cancel input in main window;
                        [The multiple-stage indexed text manipulation here is needed because a limitation in Inform does not allow us to simply say "change the glulx replacement command to "[current color-picking mode] [tint of the current graphlink in upper case]"]
                        let T be indexed text;
                        let T be "[tint of the current graphlink]";
                        let T be T in upper case;
                        change the glulx replacement command to "[current color-picking mode] [T]";
                    deactivate color-picker mode;
                    follow the window-drawing rules for the drawing-window;
                    rule succeeds;

        
    Chapter - Command for changing the foreground color

    Changing the foreground color is an action applying to one value. Understand "change foreground color to [glulx color value]" or "foreground color [glulx color value]" or "color [glulx color value]" or "element color [glulx color value]" as changing the foreground color.

    Carry out changing the foreground color:
        change the current element color to the glulx color value understood;
        if the number of entries of the element-selection set > 0:
            let count be 0;
            repeat with item running through the element-selection set:
                if item is not a sprite:
                    increase count by 1;
                    change the tint of the item to the current element color;
            if count is 0:
                say "Foreground color for drawing elements changed to [the current element color]. [bracket]Selected items are not drawing elements and were not affected.[close bracket][line break]";
            otherwise:
                say "Foreground color for drawing elements changed to [the current element color][if count > 1] for [count] items[end if].";
        otherwise:
            say "Foreground color changed to [the current element color].";
        if the glulx color value understood is g-placenullcol:
            say "Please note that the color value g-placenullcol indicates no color; in most situations, this will default to black.";
        follow the window-drawing rules for the working window;
        follow the window-drawing rules for the drawing-window.



    Chapter - Command for changing the background color

    Changing the background color is an action applying to one value. Understand "change background color to [glulx color value]" or "background color [glulx color value]" or "element background color [glulx color value]" as changing the background color.

    Carry out changing the background color:
        change the current element background color to the glulx color value understood;
        if the number of entries of the element-selection set > 0:
            let count be 0;
            repeat with item running through the element-selection set:
                if item is a stroked rectangle primitive or item is a rendered string:
                    increase count by 1;
                    change the background tint of the item to the current element background color;
            if count is 0:
                say "Background color for drawing elements changed to [the current element background color]. [bracket]Selected items are not stroked rectangles or strings and were not affected.[close bracket][line break]";
            otherwise:
                say "Background color changed to [the current element background color][if count > 1] for [count] items[end if].";
        otherwise:
            say "Background color for drawing elements changed to [the current element background color].";
        if the glulx color value understood is g-placenullcol:
            say "Please note that the color value g-placenullcol indicates no color. In the case of stroked rectangles, this will cause the stroke color to default to black.";
        follow the window-drawing rules for the working window;
        follow the window-drawing rules for the drawing-window.
        
        

    Part - Selection

    The element-selection set is a list of g-elements that varies. The element-selection set is {}.

    This is the single element selection rule:
        if element-selection set is empty:
            say "Please select an element and try again.";
            rule fails;
        if the number of entries of the element-selection set is greater than 1:
            say "Please select just one element and try again.";
            rule fails;
            
    This is the select at least one element rule:
        if the element-selection set is empty:
            say "Please select at least one element and try again.";
            rule fails;
            

    Chapter - Select Button

    Select-tab clicking is an action applying to nothing. Understand "mode select" or "selection mode" or "select mode" or "s" as select-tab clicking.

    Carry out select-tab clicking:
        actuate select_tab;
        say "The editor is now in SELECT mode. Click on a sprite to select it; click on it again to deselect. You may click on the background to deselect all sprites.";
        now glulx replacement command is "";
        [follow the window-drawing rules for the control-window.]
        

    Chapter - Selecting Elements

    A clicking graphlink rule when the current graphlink window is the working window (this is the element-selection rule):
        if the current tab is select_tab:
            unless the click hit a hot link:
                change the glulx replacement command to "DESELECT ALL";
                rule succeeds;
            otherwise:
                if the current graphlink is listed in the element-selection set:
                    remove current graphlink from the element-selection set;
                otherwise:
                    add current graphlink at entry 1 in the element-selection set;
                now glulx replacement command is "";
                follow the window-drawing rules for the current graphlink window;
                follow the window-drawing rules for the layers-window;
                update the status line;
                rule succeeds;
        now glulx replacement command is "".
        

    Section - Multiple-selection commands

    Selecting all is an action applying to nothing. Understand "select all" or "all" or "a" as selecting all. [Selects all visible elements in the editor window.]

    Carry out selecting all:
        now element-selection set is {};
        let selection-tally be 0;
        repeat with current-element running through the list of display-active in-play g-elements:
            if the current-element is assigned to the working window:
                add current-element to the element-selection set;
                increase selection-tally by 1;
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the layers-window;]
        if selection-tally is greater than 0:
            say "[selection-tally] element(s) selected.";
        otherwise:
            say "No sprites available to be selected.";
        
    Deselecting all is an action applying to nothing. Understand "deselect all" or "deselect" or "none" or "d" as deselecting all. [Deselects all visible sprites in the editor-window.]

    Carry out deselecting all:
        now element-selection set is {};
        say "Elements deselected.";
        update the status line;
        follow the window-drawing rules for the working window.
        [follow the window-drawing rules for the layers-window.]
        
    Selecting by kind is an action applying to nothing. Understand "select same kind" or "same kind" or "select kind" as selecting by kind.

    Check selecting by kind:
        abide by the single element selection rule.
        
    Carry out selecting by kind:
        let the selected-element be entry 1 of the element-selection set;
        change the element-selection set to {};
        let count be 0;
        let the search-kind be indexed text;
        let the target-kind be indexed text;
        unless the of-kind of selected-element is "":
            let the search-kind be the of-kind of the selected-element;
        otherwise:
            let the search-kind be the kind-flag of the selected-element;
        repeat with current-element running through display-active in-play g-elements:
            if the current-element is assigned to the working window:
                unless the of-kind of selected-element is "":
                    let the target-kind be the of-kind of the current-element;
                otherwise:
                    let the target-kind be the kind-flag of the current-element;
                if the search-kind is the target-kind:
                    add the current-element to the element-selection set;
                    increase count by 1;
        if count is 0:
            say "No other elements of kind [italic type][search-kind][roman type] were found.";
            add the selected-element to the element-selection set;
        otherwise:
            say "[count] element(s) of kind [italic type][search-kind][roman type] selected.";
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the layers-window].

    Selecting by layer is an action applying to nothing. Understand "select same layer" or "same layer" or "select layer" as selecting by layer.

    Check selecting by layer:
        abide by the single element selection rule.
        
    Carry out selecting by layer:
        let the selected-element be entry 1 of the element-selection set;
        change the element-selection set to {};
        let count be 0;
        repeat with current-element running through display-active in-play g-elements:
            if the current-element is assigned to the working window:
                if the display-layer of the current-element is the display-layer of the selected-element:
                    add the current-element to the element-selection set;
                    increase count by 1;
        if count is 0:
            say "No other elements were found on layer [display-layer of the selected-element].";
            add the selected-element to the element-selection set;
        otherwise:
            say "[count] element(s) were selected on layer [display-layer of the selected-element].";
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the layers-window].
        
        

    Part - Moving sprites


    Chapter - The Move button

    Move-tab clicking is an action applying to nothing. Understand "mode move" or "movement mode" or "move mode" or "m" as move-tab clicking.

    Carry out move-tab clicking:
        actuate the move_tab;
        say "The editor is now in MOVE mode. Click in the main editor window to move the origin of an element (generally its upper left corner) to that point. You may select multiple elements to move them as a unit. Elements can also be moved by using the nudge controls, or by typing MOVE HORIZONTALLY <DISTANCE IN PIXELS> or MOVE VERTICALLY <DISTANCE IN PIXELS> (negative numbers move left or up, positive down or right)[if element-selection set is empty].[paragraph break]You may use the image library or drawing controls to create an element now, or click on an existing element now to move it[otherwise if the number of entries of element-selection set is greater than 1]. [end if].";
        now glulx replacement command is "";
        [consider the window-drawing rules for the control-window.]
        

    Chapter - Element moving commands

    A clicking graphlink rule when the current graphlink window is the working window (this is the sprite-movement rule):
        unless current tab is move_tab:
            continue the action;[i.e., look at other clicking graphlink rules]
        if the element-selection set is empty:
            if the click hit a hot link:
                add current graphlink at entry 1 in the element-selection set;
                now glulx replacement command is "";
                consider the window-drawing rules for the working window;
                consider the window-drawing rules for the layers-window;
                update the status line;
                rule succeeds;
            otherwise:
                [actuate the select_tab;
                consider the window-drawing rules for the control-window;]
                follow the element-selection rule;
                rule succeeds;
        change the glulx replacement command to "MOVE ELEMENT";
        cancel input in main window;
        rule succeeds;
        
    Element-moving is an action applying to nothing. Understand "move element" or "move sprite" or "move g-element" or "move primitive" or "move string" or "move text" or "move rendered string" as element-moving.

    Check element-moving:
        unless the command is mouse-generated:
            say "[bracket]That command can only be generated by the editor; it cannot be typed. Try MOVE HORIZONTALLY <distance> or MOVE VERTICALLY <distance>.[close bracket][paragraph break]";
            rule fails;
        if the element-selection set is empty:
            rule fails.

    Carry out element-moving:
        let min-x be entry 1 of the origin of entry 1 of the element-selection set;
        let min-y be entry 2 of the origin of entry 1 of the element-selection set;
        let the clicked coordinates be the canvas equivalent of the screen coordinates (current graphlink x) by (current graphlink y) of the current graphlink window;
        repeat with candidate running through the element-selection set:
            if entry 1 of the origin of the candidate < min-x:
                let min-x be entry 1 of the origin of candidate;
            if entry 2 of the origin of the candidate < min-y:
                let min-y be entry 2 of the origin of candidate;
        let delta-x be entry 1 of the clicked coordinates minus min-x;
        let delta-y be entry 2 of the clicked coordinates minus min-y;
        repeat with current-element running through the element-selection set:
            change entry 1 of the origin of the current-element to (entry 1 of the origin of the current-element + delta-x);
            change entry 2 of the origin of the current-element to (entry 2 of the origin of the current-element + delta-y);
            if the current-element is a primitive:
                let x1 be entry 1 of the origin of the current-element;
                let y1 be entry 2 of the origin of the current-element;
                change entry 1 of the endpoint of the current-element to x1 plus (the element-width of the current-element);
                change entry 2 of the endpoint of the current-element to y1 plus (the element-height of the current-element);
            say "Element [element-name of current-element] moved to [origin of the current-element in brace notation].";
        consider the window-drawing rules for the working window;
        update the status line;
        
    Moving manually is an action applying to one thing and one value. Understand "move sprite [any legerdemained thing] [a number]" or "move [any legerdemained thing] [a number]" or "[any legerdemained thing] [a number]" as moving manually.

    Check moving manually:
        abide by the select at least one element rule.
            
    Carry out moving manually (this is the numeric movement rule):
        repeat with current-element running through the element-selection set:
            let the movement-offset be a list of numbers;
            let the movement-offset be {0, 0};
            if the noun is:
                -- horizontally: change entry 1 of the movement-offset to the number understood;
                -- vertically: change entry 2 of the movement-offset to the number understood;
            change the origin of current-element to the origin of current-element offset by the movement-offset;
            [change the origin of current-element to the origin of current-element verified against the background of the working window;]
            if the current-element is a primitive:
                let x1 be entry 1 of the origin of the current-element;
                let y1 be entry 2 of the origin of the current-element;
                change entry 1 of the endpoint of the current-element to x1 plus (the element-width of the current-element);
                change entry 2 of the endpoint of the current-element to y1 plus (the element-height of the current-element);
            say "Element [element-name of current-element] moved to [origin of the current-element in brace notation].";
        consider the window-drawing rules for the working window;
        rule succeeds;
        
    Moving interactively is an action applying to one thing. Understand "move sprite [any legerdemained thing]" or "move [any legerdemained thing]" or "[any legerdemained thing]" as moving interactively.

    The current movement direction is a thing that varies.

    Check moving interactively:
        abide by the select at least one element rule.
        
    Carry out moving interactively:
        now the current movement direction is the noun;
        now the current question is "Indicate the distance in pixels to move the sprite(s). Positive numbers indicate [if noun is horizontally] movement to the right, negative to the left[otherwise] movement downward, negative movement upward[end if].";
        now current prompt is "Enter a number: >";
        now current cancelation message is "[bracket]Movement canceled.[close bracket]";
        ask an open question, in number mode;
        
    A number question rule when the impelling action is moving interactively:
        now the noun is current movement direction;
        follow the numeric movement rule;
        

    Chapter - Nudging Sprites

    Sprite-nudging is an action applying to one value. Understand "nudge [nudge-direction]" as sprite-nudging.

    Understand "nudge" as a mistake ("Please provide a direction (upward, rightward, downward, or leftward), e.g. NUDGE RIGHTWARD.").

    The nudge factor is a number that varies. The nudge factor is usually 1.
    The maximum nudge is a number that varies. The maximum nudge is usually 500.

    Check sprite-nudging:
        abide by the select at least one element rule.

    Carry out sprite-nudging:
        repeat with current-element running through the element-selection set:
            let the nudge-coordinates be a list of numbers;
            let the nudge-coordinates be {0, 0};
            if the nudge-direction understood is:
                -- upward: change entry 2 of the nudge-coordinates to -1 * the nudge factor;
                -- leftward: change entry 1 of the nudge-coordinates to -1 * the nudge factor;
                -- rightward: change entry 1 of the nudge-coordinates to the nudge factor;
                -- downward: change entry 2 of the nudge-coordinates to the nudge factor;
            change the origin of current-element to the origin of current-element offset by the nudge-coordinates;
            if the current-element is a primitive:
                let x1 be entry 1 of the origin of the current-element;
                let y1 be entry 2 of the origin of the current-element;
                change entry 1 of the endpoint of the current-element to x1 plus (the element-width of the current-element);
                change entry 2 of the endpoint of the current-element to y1 plus (the element-height of the current-element);
            say "Sprite [element-name of current-element] moved to [origin of the current-element in brace notation].";
        consider the window-drawing rules for the working window;
        rule succeeds;
        
    Changing the nudge-factor is an action applying to one number. Understand "nudge [a number]" or "change nudge to [a number]" or "change nudge amount to [a number]" or "nudge amount [a number]" as changing the nudge-factor.

    Check changing the nudge-factor (this is the nudge-factor checking rule):
        if the number understood is less than 1 or the number understood is greater than the maximum nudge:
            say "The nudge amount must be a number between 1 and [the maximum nudge].";
            rule fails;
            
    Carry out changing the nudge-factor (this is the nudge-factor changing rule):
        change the nudge factor to the number understood;
        say "Nudge amount changed to [the nudge factor].";
        

    Interactively changing the nudge-factor is an action applying to nothing. Understand "change nudge amount" as interactively changing the nudge-factor.

    Carry out interactively changing the nudge-factor:
        now current question is "Enter the number of pixels that sprites will be moved by each press of the nudge keys.";
        now current prompt is "Enter a number: >";
        now current cancelation message is "[bracket]Nudge customization canceled.[close bracket]";
        ask an open question, in number mode.
        
    A number question rule when the impelling action is interactively changing the nudge-factor:
        consider the nudge-factor checking rule;
        if the rule failed:
            retry;
        abide by the nudge-factor changing rule;
        exit.


    Part - "Deleting" elements
    ["Deleting" in quotes here because the element objects aren't really deleted; instead, they are simply marked as display-inactive.]

    Deleting elements is an action applying to nothing. Understand "delete" or "del" or "delete element" or "delete elements" as deleting elements.

    Check deleting elements:
        if the element-selection set is empty:
            say "Please select one or more elements to delete.";
            rule fails;
            
    Carry out deleting elements:
        repeat with current-element running through the element-selection set:
            fake-delete the current-element, iteratively;
            say "Element [element-name of current-element] deleted.";
        now the element-selection set is {};
        update the status line;
        refresh windows.
        
    To fake-delete (S - a g-element), iteratively:
    [The iteratively phrase option is intended for use when we are looping through the element-selection set. If that is the case, we don't delete the element from the list, because this will cause problems with the looping.]
        unless iteratively:
            remove S from the element-selection set, if present;
        change S to deleted;
        deactivate S.
        

    Part - Hiding and showing elements

    Chapter - Hiding elements

    Hiding elements is an action applying to nothing. Understand "hide" or "hide sprite/sprites" or "mark sprite/sprites as display-inactive" or "mark sprite/sprites as inactive" or "deactivate" or "deactive sprite/sprites" as hiding elements.

    Check hiding elements:
        if the element-selection set is empty:
            say "Please select one or more elements to delete.";
            rule fails;
            
    Carry out hiding elements:
        let L be a list of indexed text;
        repeat with current-element running through the element-selection set:
            deactivate current-element;
            add the element-name of the current-element to L;
        say "The [if the number of entries of the element-selection set is greater than 1]elements[otherwise]element[end if] [L] [if the number of entries of the element-selection set is greater than 1]have been[otherwise]has been[end if] marked as display-inactive, and will appear as such in output source code. To remove sprites entirely from the composition, use the DELETE command.";
        now the element-selection set is {};
        update the status line;
        follow the window-drawing rules for the working window.
        

    Chapter - Showing elements

    The element-disambiguation list is a list of g-elements that varies.

    Showing elements is an action applying to nothing. Understand "show" or "show sprite/sprites" or "mark sprite/sprites as display-active" or "mark sprite/sprites as active" or "activate" or "activate sprite/sprites" as showing elements.

    Carry out showing elements:
        now the element-disambiguation list is {};
        repeat with current-element running through in-play g-elements:
            if current-element is assigned to the working window:
                if current-element is display-inactive and current-element is not deleted:
                    add current-element to the element-disambiguation list;
        if the number of entries of the element-disambiguation list is less than 1:
            say "All elements are currently displayed.";
            rule fails;
        otherwise:
            say "The following elements are currently marked as display-inactive:[paragraph break]";
            let count be 0;
            repeat with current-element running through the element-disambiguation list:
                increase count by 1;
                say "[bracket][count][close bracket] [element-name of current-element] (layer [display-layer of current-element])[line break]";
            say "[line break]";
            now the current question is "Select the number of the element you wish to mark as display-active.";
            now the current prompt is "Enter a number from the list: >";
            now the current cancelation message is "[bracket]Changing element status canceled.[close bracket]";
            ask an open question, in number mode.
        
    A number question rule (this is the select disambiguated sprite rule):
        if the current question is "Select the number of the element you wish to mark as display-active.":
            if the number understood is less than 1 or the number understood is greater than the number of entries of the element-disambiguation list:
                say "Please choose a number from the list.";
                retry;
            let the selected-entry be the number understood;
            let the selected-element be entry (selected-entry) of the element-disambiguation list;
            say "The element [element-name of selected-element] has been marked as display-active.";
            activate the selected-element;
            update the status line;
            follow the window-drawing rules for the working window;
            exit;
        
    Showing all elements is an action applying to nothing. Understand "show all" or "show all element/elements" or "mark all element/elements as display-active" or "mark all element/elements as active" or "activate all" or "activate all element/elements" as showing all elements.

    Carry out showing all elements:
        repeat with current-element running through in-play g-elements assigned to the working window:
            if current-element is assigned to the working window:
                if current-element is display-inactive and current-element is not deleted:
                    activate current-element;
        update the status line;
        follow the window-drawing rules for the working window;
        say "All elements are now displayed.";


    Part - Duplicating elements

    Duplicating an element is an action applying to nothing. Understand "copy" or "duplicate" or "c" as duplicating an element.

    Check duplicating an element:
        abide by the select just one element rule.

    Carry out duplicating an element:
        let current-element be entry 1 of the element-selection set;
        if current-element is a primitive:
            create a duplicate primitive from current-element in the working window;
        otherwise if current-element is a rendered string:
            create a duplicate rendered string from current-element in the working window;
        otherwise:
            create a duplicate sprite from current-element in the working window;
        change the display-layer of entry 1 of the element-selection set to current display-layer;
        update the status line;
        follow the window-drawing rules for the working window;
        rule succeeds.


    To create a duplicate primitive from (X - a g-element) in (win - a g-window):
        increase the instance-counter of X by 1;
        let the new element be a new object cloned from X;
        now the new element is standard;
        change the display status of new element to g-active;
        unlink the element-name of the new element;
        change the element-name of the new element to "[element-name of X]_copy";
        replace the regular expression "\b(\w)(\w*)" in the element-name of the new element with "\u1\l2";
        unlink the of-kind of the new element;
        unlink the tag of the new element;
        unlink the replacement-command of the new element;
        unlink the origin of the new element;
        unlink the endpoint of the new element;
        now the element-selection set is {};
        add the new element to the element-selection set;
        say "Element primitive copied as: [element-name of new element].";


    To create a duplicate rendered string from (X - a rendered string) in (win - a g-window):
        increase the instance-counter of X by 1;
        let the new element be a new object cloned from X;
        now the new element is standard;
        change the display status of new element to g-active;
        unlink the element-name of the new element;
        change the element-name of the new element to "[element-name of X]_copy";
        replace the regular expression "\b(\w)(\w*)" in the element-name of the new element with "\u1\l2";
        unlink the of-kind of the new element;
        unlink the tag of the new element;
        unlink the replacement-command of the new element;
        unlink the origin of the new element;
        unlink the text-string of the new element;
        change element-selection set to {};
        add the new element at entry 1 in the element-selection set;
        say "Rendered string copied as: [element-name of new element].";

    To create a duplicate sprite from (S - a sprite) in (win - a g-window):
        increase the instance-counter of S by 1;
        let the new sprite be a new object cloned from S;
        now the new sprite is standard;
        unlink the element-name of the new sprite;
        change the element-name of the new sprite to "[element-name of S]_copy";
        now the new sprite is standard;
        unlink the of-kind of the new sprite;
        unlink the tag of the new sprite;
        unlink the replacement-command of the new sprite;
        unlink the origin of the new sprite;
        say "Sprite duplicated as: [element-name of new sprite].";
        change element-selection set to {};
        add new sprite at entry 1 in the element-selection set;
        follow the window-drawing rules for win;

        
    Part - Changing element names

    Changing the name of is an action applying to one topic. Understand "rename as [text]" or "rename to [text]" or "change name to [text]" or "rename [text]" as changing the name of.

    Check changing the name of (this is the select just one element rule):
        if the element-selection set is empty:
            say "Please select an element and try again.";
            rule fails;
        if the number of entries of the element-selection set is greater than 1:
            say "Please select just one element and try again.";
            rule fails;

    Carry out changing the name of:
        now the current answer is the topic understood;
        replace the regular expression "\p" in the current answer with "";
        [The "current answer" is used to allow code reuse between the standard and interactive forms; the latter must use the current answer because it is provided by the Questions extension.]
        abide by the changing the name of rule.
        
    This is the changing the name of rule:
        change the element-name of entry 1 of the element-selection set to the current answer;
        say "The name of the element was changed to [italic type][element-name of entry 1 of the element-selection set].[roman type][paragraph break]";
        rule succeeds;
        
    Interactively changing the name of is an action applying to nothing. Understand "rename" or "change name" or "rename element" as interactively changing the name of.

    Check interactively changing the name of:
        abide by the select just one element rule;

    Carry out interactively changing the name of:
        now current question is "What would you like to rename the selected element?";
        now current prompt is "Enter the new name: >";
        now current cancelation message is "[bracket]Renaming canceled.[close bracket]";
        ask an open question, in text mode.

    A text question rule when the impelling action is interactively changing the name of:
        follow the changing the name of rule;
        exit.

        
    Part - Changing element kinds

    Changing the kind of is an action applying to one topic. Understand "change kind to [text]" or "change to [text]" or "kind [text]" as changing the kind of.

    Check changing the kind of:
        abide by the select at least one element rule;
        [if the element-selection set is empty:
            say "Please select at least one element and try again.";
            rule fails;]

    Carry out changing the kind of:
        now the current answer is the topic understood;
        abide by the changing the kind of rule.
        
    This is the changing the kind of rule:
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the of-kind of the current-element to the current answer;
            add the element-name of the current-element to L;
        say "The kind of the [if the number of entries of the element-selection set is greater than 1]elements[otherwise]element[end if] [L] was changed to [italic type][current answer].[roman type][paragraph break]";
        rule succeeds;
        
    Interactively changing the kind of is an action applying to nothing. Understand "change kind" or "kind" or "change element kind" as interactively changing the kind of.

    Check interactively changing the kind of:
        abide by the select at least one element rule.

    Carry out interactively changing the kind of:
        now current question is "Please indicate the name of the kind you wish to change the element to. In the output source, the word element will be automatically added to the name of the kind to prevent namespace conflicts; e.g., [italic type]room-element, item-element[roman type].";
        now current prompt is "Enter the name of the kind: >";
        now current cancelation message is "[bracket]Kind attribution canceled.[close bracket]";
        ask an open question, in text mode.

    A text question rule when the impelling action is interactively changing the kind of:
        follow the changing the kind of rule;
        exit.


    Part - Tags

    The tag type is an indexed text variable. The tag type is usually "text".
    The tag alias is a text variable. The tag alias is usually "tag".

    The tag-surround is text that varies.

    [We add quotation marks if the tag will be used to represent a text or indexed text property]

    When play begins:
        change the tag type to the tag type in lower case;
        if the tag type exactly matches the text "text" or the tag type exactly matches the text "indexed text":
            change the tag-surround to "[quotation mark]";
        otherwise:
            change the tag-surround to "".


    Chapter - Assigning tags

    Tagging is an action applying to one topic. Understand "tag [text]" or "tag as [text]" or "tag element as [text]" or "t [text]" as tagging.

    Check tagging:
        abide by the select at least one element rule.

    Carry out tagging:
        now the current answer is the topic understood;
        [The "current answer" is used to allow code reuse between the standard and interactive forms; the latter must use the current answer because it is provided by the Questions extension.]
        abide by the tagging elements rule.
        
    This is the tagging elements rule:
        repeat with current-element running through the element-selection set:
            change the tag of current-element to the current answer;
        say "The tag of the selected element(s) was changed to [italic type][current answer].[roman type][paragraph break]";
        rule succeeds;


    Interactively tagging is an action applying to nothing. Understand "tag" or "tag element" or "tag sprite" or "t" as interactively tagging.

    Check interactively tagging:
        abide by the select at least one element rule.

    Carry out interactively tagging:
        now current question is "How would you like to tag the selected element?";
        now current prompt is "Enter the tag: >";
        now current cancelation message is "[bracket]Tagging canceled.[close bracket]";
        ask an open question, in text mode.

    A text question rule when the impelling action is interactively tagging:
        follow the tagging elements rule;
        exit.


    Chapter - Removing tags

    Removing tags is an action applying to nothing. Understand "remove tag" or "clear tag" or "delete tag" as removing tags.

    Check removing tags:
        abide by the select at least one element rule.
        
    Carry out removing tags:
        repeat with current-element running through the element-selection set:
            change the tag of current-element to "";
        say "The tag of the selected element(s) was removed.";
        

    Part - Adding and removing graphlinks

    Graphlinking to is an action applying to one topic. Understand "link element with replacement command [text]" or "link [text]" or "link element [text]" or "link with replacement command [text]" or "link with command [text]" as graphlinking to.

    Check graphlinking to:
        abide by the select at least one element rule;

    Carry out graphlinking to (this is the graphlinking rule):
        let T be indexed text;
        let T be the topic understood;
        replace the text "[quotation mark]" in T with "";
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the replacement-command of current-element to T;
            add the element-name of the current-element to L;
        say "The selected [if the number of entries of the element-selection set is greater than 1]elements were[otherwise]element was[end if] graphlinked with the glulx replacement command set to [italic type][T].[roman type][paragraph break]";
        rule succeeds;
        
    Interactive graphlinking is an action applying to nothing. Understand "link" or "add link" as interactive graphlinking.

    Check interactive graphlinking:
        abide by the select at least one element rule;
            
    Carry out interactive graphlinking:
        now current question is "Please type in the command that will be entered when the player clicks on [if the number of entries of the element-selection set is greater than 1]these elements[otherwise]this element[end if].";
        now current prompt is "Enter graphlinked command: >";
        now current cancelation message is "[bracket]Graphlinking canceled.[close bracket]";
        ask an open question, in text mode.
        
    A text question rule when the impelling action is interactive graphlinking:
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the replacement-command of current-element to the current answer;
            add the element-name of the current-element to L;
        say "The selected [if the number of entries of the element-selection set is greater than 1]elements were[otherwise]element was[end if] graphlinked with the glulx replacement command set to [italic type][current answer].[roman type][paragraph break]";
        exit.
        
    Delinking is an action applying to nothing. Understand "delink element" or "delink" or "remove link/links" as delinking.

    Check delinking:
        if the element-selection set is empty:
            say "Please select at least one element and try again.";
            rule fails;

    Carry out delinking (this is the delinking rule):
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the replacement-command of current-element to "";
            add the element-name of the current-element to L;
        say "The selected [if the number of entries of the element-selection set is greater than 1]elements were delinked. They[otherwise]element was delinked. It[end if] will not respond to mouse input.";
        rule succeeds;
        

    Part - Getting element information

    Definition: a g-element (called the-element) is g-unlinked:
        if the replacement-command of the-element is "", yes;
        no.

    Element-querying is an action applying to nothing. Understand "info" or "element information" or "element info" or "information" or "i" as element-querying.

    Before element-querying:
        let percentage be indexed text;
        let percentage be "[scaling factor of the working window real times 100]";
        replace the regular expression "0+$|\.$" in percentage with "";
        say "The canvas measures [canvas-width of the working canvas] by [canvas-height of the working canvas].[line break]The scaling factor of the editor window is [scaling factor of the working window] ([percentage]%)."

    Check element-querying:
        if the element-selection set is empty:
            say "Select at least one element in the editor and try the command again to get specific information about that element.";
            rule fails;

    To decide which number is the absolute value of (N - a number):
        if N is less than 0:
            let N be 0 minus N;
        decide on N.
        
    Carry out element-querying:
        repeat with current-element running through the element-selection set:
            if current-element provides the property endpoint:
                let dim-x be (entry 1 of the endpoint of current-element) - (entry 1 of the origin of current-element);
                let dim-y be (entry 2 of the endpoint of current-element) - (entry 2 of the origin of current-element);
            if current-element is a line primitive:
                let dim-x be the absolute value of dim-x;
                let dim-y be the absolute value of dim-y;
            if current-element is a sprite:
                let dim-x be image-width of the image-ID of the current-element real times the x-scaling factor of the current-element as an integer;
                let dim-y be image-height of the image-ID of the current-element real times the y-scaling factor of the current-element as an integer;
            if current-element is a rendered string:
                let len be the length of the current-element;
            if current-element is an image-rendered string:
                let margin be the background-margin of the associated font of the current-element real times the x-scaling factor of the current-element as an integer;
                let vertical-size be the font-height of the associated font of the current-element real times the x-scaling factor of the current-element as an integer;
                let len be len real times the x-scaling factor of the current-element as an integer;
                let dim-x be len + margin + margin;
                let dim-y be vertical-size + margin + margin;
            if current-element is a bitmap-rendered string:
                let dot-size be bit-size of the current-element real times the x-scaling factor of the current-element as an integer;
                let dim-x be dot-size * len;
                let dim-y be dot-size * (font-height of the associated font of the current-element);
            say "[bold type][element-name of current-element][roman type][line break][kind-flag of current-element][kind descendant arrow][unless of-kind of current-element is null][of-kind of current-element][otherwise](no sub-kind defined)[end if][line break]tag: [if the tag of current-element is null]none[otherwise][tag of current-element][end if][line break]display-layer: [display-layer of current-element][line break]origin: ([entry 1 of origin of current-element],[entry 2 of origin of current-element])[if current-element is not a sprite and current-element is not a rendered string] endpoint: ([entry 1 of endpoint of current-element],[entry 2 of endpoint of current-element])[end if][line break]dimensions: [dim-x] by [dim-y][line break]scaling: [if the x-scaling factor of current-element is the y-scaling factor of current-element][x-scaling factor of current-element][otherwise][x-scaling factor of current-element] (x) by [y-scaling factor of current-element] (y)[end if][if current-element provides the property line-weight][line break]line-weight: [line-weight of current-element][end if][if current-element is a bitmap-rendered string][line break]bit-size: [bit-size of current-element][end if][if current-element is not a sprite][line break]foreground color: [tint of current-element][end if][if current-element is a stroked rectangle primitive or current-element is a rendered string][line break]background color: [background tint of current-element][end if][line break]replacement command: [if the current-element is g-unlinked]N/A[otherwise][replacement-command of current-element][end if]";
            if the current-element is instanced:
                follow the element instances listing rule;
            say paragraph break;


    To say kind descendant arrow:
        if Unicode is supported:
            say "[right-uni-arrow]";
        otherwise:
            say "->".

    To decide whether Unicode is supported:
        (- unicode_gestalt_ok -)

    To say left-bent-uni-arrow:
        (- glk_put_char_uni(8629); -)

    To say right-uni-arrow:
        (- glk_put_char_uni(8594); -)


    Part - Zooming

    Zooming is an action applying to nothing. Understand "zoom" or "zoom in" or "zoom out" or "z" as zooming.

    The zooming action has some text called the zoom-vector.

    The zoom-center is a list of numbers variable. Zoom-center is {0, 0}.

    Check zooming:
        unless zoom is available:
            say "The canvas fits in the window, so zoom is not available.";
            stop the action.

    Carry out zooming when we are zoomed in:
        now the arbitrary scaling factor of the working window is 0.0000;
        now the origin of the working window is {0, 0};
        now the zoom-vector is "out";
        rule succeeds.

    Carry out zooming when we are zoomed out:
        now the arbitrary scaling factor of the working window is 1.0000;
        if the element-selection set is empty:
            change the zoom-center to {-1, -1};
        otherwise:
            change the zoom-center to the center-point of (entry 1 of the element-selection set);
        now the zoom-vector is "in";
        rule succeeds.

    Report zooming:
        carry out the scaling activity with the working window;[we do this to get the proper scaling factor]
        let percentage be indexed text;
        let percentage be "[scaling factor of the working window real times 100]";
        replace the regular expression "0+$" in percentage with "";
        replace the regular expression "\.+$" in percentage with "";
        say "Zooming [zoom-vector] to [scaling factor of the working window] ([percentage]%).";
        follow the window-drawing rules for the working window.
            

    Part - Element scaling


    Chapter - Scale tab

    Scale-tab clicking is an action applying to nothing. Understand "mode scale" or "scale mode" or "scaling mode" or "x" as scale-tab clicking.

    Carry out scale-tab clicking:
        actuate the scale_tab;
        unless element-selection set is empty:
            truncate the element-selection set to 1 entries;
        say "The editor is now in SCALE mode. [if asymmetric-scaling is true]Scaling will be asymmetrical. Click with the mouse where you would like the lower right corner of the element to expand or contract[otherwise]Scaling will be symmetrical. The x-axis of the mouse-click determines the extent of the element's expansion or contraction; the aspect ratio of the original image will be automatically maintained[end if].";
        [consider the window-drawing rules for the control-window;]
        consider the window-drawing rules for the working window;


    Section - Scaling modes

    Asymmetric-scaling is a truth state that varies. Asymmetric-scaling is false.

    To decide if we are scaling asymmetrically:
        decide on asymmetric-scaling.
        
    Asymmetrical scaling mode is an action applying to nothing. Understand "asymmetrical" or "asymmetrical scaling" or "scale asymmetrically" as asymmetrical scaling mode.

    Understand "toggle scaling" or "scaling" as asymmetrical scaling mode when asymmetric-scaling is false.
    Understand "toggle scaling" or "scaling" as symmetrical scaling mode when asymmetric-scaling is true.

    Carry out asymmetrical scaling mode:
        change asymmetric-scaling to true;
        update AsymScale_radio using asymmetric-scaling;
        [follow the window-drawing rules for the control-window;]
        say "Asymmetrical scaling mode active.";
        
    Symmetrical scaling mode is an action applying to nothing. Understand "symmetrical" or "symmetrical scaling" or "equivalent scaling" or "scale asymmetrically" as symmetrical scaling mode.

    Carry out symmetrical scaling mode:
        change asymmetric-scaling to false;
        update AsymScale_radio using asymmetric-scaling;
        [follow the window-drawing rules for the control-window;]
        say "Symmetrical scaling mode active.";


    Section - Scaling validation rules

    This is the check scaling input rule:
        abide by the select at least one element rule;
        abide by the scaling limit validation rule;

    This is the scaling limit validation rule:
        if the real number understood is real less than the lower scaling-limit or the real number understood is real greater than the upper scaling-limit:
            say "The number you entered was not within the permitted range. Please enter a fixed-point number between [the lower scaling-limit] and [the upper scaling-limit].";
            if we are asking a question, retry;
            rule fails;

    The scaling operation cancelation message is text that varies. The scaling operation cancelation message is "[bracket]Scaling operation canceled.[close bracket]".

    To decide whether the player entered a number:
        if the player's command matches the regular expression "\d", decide yes;
        decide no.
        

    Chapter - GUI scaling

    A clicking graphlink rule when the current graphlink window is the working window (this is the element-scaling mouse input rule):
        unless the current tab is scale_tab:
            continue the action;
        if the element-selection set is empty:
            if the click hit a hot link:
                add current graphlink at entry 1 in the element-selection set;
                now glulx replacement command is "";
                consider the window-drawing rules for the current graphlink window;
                update the status line;
                rule succeeds;
            otherwise:
                [actuate select_tab;
                consider the window-drawing rules for the control-window;]
                follow the element-selection rule;
                rule succeeds;
        change glulx replacement command to "SCALE ELEMENT";
        cancel input in main window;
        rule succeeds;
        
    element-scaling is an action applying to nothing. Understand "scale element" as element-scaling.

    Check element-scaling:
        unless entry 1 of the element-selection set is a sprite or entry 1 of the element-selection set is an image-rendered string:
            say "[bracket]GUI scaling is only effective on sprites (images) and on image-based text strings.[close bracket][one of][paragraph break]Scaling of primitives affects only the line-weight, while for bitmapped text it changes the size of the individual pixels (the bit-size). If you wish to set the scaling factor of an element other than a sprite or image-rendered string, enter SCALE AT (a real number, such as 0.[run paragraph on][8 times (10 to the power precision minus 1)]).[or][stopping][line break]";
            rule fails;
        if the command is mouse-generated:
            continue the action;
        otherwise:
            say "[bracket]That command is reserved for the editor.[close bracket][paragraph break]You may:[line break](1) Enter SCALE AT (a real number, such as 0.[run paragraph on][8 times (10 to the power precision minus 1)]) to scale symmetrically;[line break](2) Enter SCALE HORIZONTALLY/VERTICALLY AT (a real number, such as 0.[run paragraph on][8 times (10 to the power precision minus 1)]) to scale asymmetrically[if current tab is Select_tab][line break](3) Click in the main element window to scale the selected element[otherwise][line break](3) Select the [bold type]scale[roman type] tab and scale using the mouse[end if].[line break]";
            rule fails;

    Carry out element-scaling:
        let current-element be entry 1 of the element-selection set;
        let orig-x be entry 1 of the origin of the current-element;
        let orig-y be entry 2 of the origin of the current-element;
        let the clicked coordinates be the canvas equivalent of the screen coordinates current graphlink x by current graphlink y of the current graphlink window;
        let desired-x be entry 1 of the clicked coordinates;
        let desired-y be entry 2 of the clicked coordinates;
        [say "Clicked x: [desired-x][line break]Clicked y: [desired-y][line break]";]
        if desired-x is less than orig-x or desired-y is less than orig-y:
            say "Click to the right of and below the origin point (upper left-hand corner) of the element to resize it.";
            rule succeeds;
        if current-element is an image-rendered string:
            let width be the length of the current-element plus (2 * background-margin of the associated font of the current-element);
            let height be the font-height of the associated font of the current-element plus (2 * background-margin of the associated font of the current-element);
        otherwise:
            let width be the image-width of the image-ID of the current-element;
            let height be the image-height of the image-ID of the current-element;
        let width-fixe be width as a fixed point number;
        let height-fixe be height as a fixed point number;
        let desired-width be desired-x minus orig-x as a fixed point number;
        let desired-height be desired-y minus orig-y as a fixed point number;
        let width-factor be desired-width real divided by width-fixe;
        let height-factor be desired-height real divided by height-fixe;
        [say "Width: [width-factor][line break]Height: [height-factor][line break]";]
        if we are scaling asymmetrically:
            change the x-scaling factor of the current-element to the width-factor;
            change the y-scaling factor of the current-element to the height-factor;
        otherwise:
            change the x-scaling factor of the current-element to the width-factor;
            change the y-scaling factor of the current-element to the width-factor;
        say "Element [element-name of current-element] [if we are scaling asymmetrically]asymmetrically scaled to [width-factor] by [height-factor][otherwise]symmetrically scaled to [width-factor] of its original size[end if].";
        follow the window-drawing rules for the working window;
        if there is a linkid of current-element in the Table of Graphlink Glulx Replacement Commands:
            choose row with linkid of current-element in the Table of Graphlink Glulx Replacement Commands;
            draw a box (color highlight-color) in the working window from (p-left entry) by (p-top entry) to (current graphlink x) by (current graphlink y) with 2 pixel line-weight, outlined;
        rule succeeds;


    Chapter - Default scaling factor


    Section - Setting the default scaling factor

    The default scaling factor is a real number that varies. The default scaling factor is usually 1.0000.

    Setting the scaling factor is an action applying to one value. Understand "set default scale at [a real number]" or "set default scale to [a real number]" or "default [real number]" or "default scale [real number]" or "set scale at [real number]" or "set scale to [real number]" or "scaling [real number]" as setting the scaling factor.

    Understand "scale [real number]" or "x [real number]" as setting the scaling factor when the number of entries of the element-selection set is 0.

    Check setting the scaling factor:
        abide by the scaling limit validation rule.

    Carry out setting the scaling factor (this is the default scaling factor rule):
        change the default scaling factor to the real number understood;
        say "Newly created elements will be scaled at a ratio of [the real number understood].";
        

    Section - Interactively setting the default scaling factor
        
    Interactively setting the scaling factor is an action applying to nothing. Understand "set default scale" as interactively setting the scaling factor.

    Carry out interactively setting the scaling factor:
        now the current question is "Enter the desired scaling ratio to be used as the default. Each new element created will be scaled at this ratio.";
        now the current prompt is "Enter the scaling ratio (e.g., 0.[run paragraph on][8 times (10 to the power precision minus 1)]): >";
        now the current cancelation message is "[scaling operation cancelation message]";
        ask an open question in real number mode;
        
    A real number question rule when the impelling action is interactively setting the scaling factor:
        abide by the scaling limit validation rule;
        follow the default scaling factor rule;
        exit;
        

    Chapter - Basic element scaling commands


    Section - Symmetrical scaling

    Scaling elements is an action applying to one real number. Understand "scale at [real number]" or "scale element/elements at [real number]" or "scale to [real number]" or "scale element/elements to [real number]" as scaling elements.

    Understand "scale [real number]" or "x [real number]" as scaling elements when the number of entries of the element-selection set > 0.

    Check scaling elements:
        abide by the check scaling input rule;
        
    Carry out scaling elements (this is the numeric symmetrical scaling rule):
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the x-scaling factor of the current-element to the real number understood;
            change the y-scaling factor of the current-element to the real number understood;
            add the element-name of the current-element to L;
        say "[if the number of entries of L is greater than 1]Elements[otherwise]Element[end if] [L] [if the number of entries of L is greater than 1]were[otherwise]was[end if] scaled to [the real number understood] of [if the number of entries of L is greater than 1]their original sizes[otherwise]the original size[end if].";
        follow the window-drawing rules for the working window;
        rule succeeds;
        

    Section - Interactive symmetrical scaling
        
    Interactive symmetrical scaling is an action applying to nothing. Understand "scale symmetrically" as interactive symmetrical scaling.

    Check interactive symmetrical scaling:
        abide by the select at least one element rule;

    Carry out interactive symmetrical scaling:
        now the current question is "";
        now current prompt is "Enter the scaling ratio (e.g., 0.[run paragraph on][8 times (10 to the power precision minus 1)]): >";
        now the current cancelation message is "[scaling operation cancelation message]";
        ask an open question in real number mode.
        
    A real number question rule when the impelling action is interactive symmetrical scaling:
        follow the numeric symmetrical scaling rule;
        exit.


    Chapter - Asymmetrical element scaling command

    horizontally is in Fake-room_x. It is legerdemained.
    vertically is in Fake-room_x. It is legerdemained. [Making these values would be better practice, but Inform only allows one value to be entered in a player's command, and we need that value to be the real number for scaling.]


    Section - Asymmetrical scaling

    Asymmetrically scaling elements is an action applying to one thing and one real number. Understand "scale [any legerdemained thing] at [real number]" or "scale element/elements [any legerdemained thing] at [real number]" or "scale [any legerdemained thing] to [real number]" or "scale element/elements [any legerdemained thing] to [real number]" or "scale [any legerdemained thing] [real number]" as asymmetrically scaling elements.

    Check asymmetrically scaling elements:
        Abide by the check scaling input rule.
        
    Carry out asymmetrically scaling elements (this is the asymmetric scale rule):
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            if the noun is horizontally:
                change the x-scaling factor of the current-element to the real number understood;
            otherwise if the noun is vertically:
                change the y-scaling factor of the current-element to the real number understood;
            add the element-name of the current-element to L;
        follow the window-drawing rules for the working window;
        say "[if the number of entries of L is greater than 1]Elements[otherwise]Element[end if] [L] [if the number of entries of L is greater than 1]were[otherwise]was[end if] scaled [noun] to [the real number understood] of [if the number of entries of L is greater than 1]their original sizes[otherwise]the original size[end if].";
        rule succeeds;


    Section - Interactive asymmetrical scaling

    Interactive asymmetrical scaling is an action applying to one thing. Understand "scale [any legerdemained thing]" or "scale element/elements [any legerdemained thing]" as interactive asymmetrical scaling.

    The current scaling direction is a thing that varies.

    Carry out interactive asymmetrical scaling:
        now the current scaling direction is the noun;
        now the current question is "Indicate the ratio at which the element should be scaled [current scaling direction]. The ratio must be expressed as a decimal with [precision in words]-digit precision; e.g., 0.[run paragraph on][8 times (10 to the power precision minus 1)] represents 80%.";
        now current prompt is "Enter a scaling ratio: >";
        now the current cancelation message is "[bracket]Scaling canceled.[close bracket]";
        ask an open question in real number mode;
        
    A real number question rule when the impelling action is interactive asymmetrical scaling:
        abide by the scaling limit validation rule;
        now the noun is current scaling direction;
        follow the asymmetric scale rule;


    Part - Changing the canvas


    Chapter - Changing the canvas dimensions
        
    Changing the canvas width is an action applying to one value. Understand "change canvas width to [a number]" or "set canvas width to [a number]" or "canvas width [a number]" or "width [a number]" as changing the canvas width.

    Carry out changing the canvas width:
        change the canvas-width of the associated canvas of the working window to the number understood;
        say "The canvas is now [canvas-width of the associated canvas of the working window] pixels wide.";
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the control-window.]
        
    Changing the canvas height is an action applying to one value. Understand "change canvas height to [a number]" or "set canvas height to [a number]" or "canvas height [a number]" or "height [a number]" as changing the canvas height.

    Carry out changing the canvas height:
        change the canvas-height of the associated canvas of the working window to the number understood;
        say "The canvas is now [canvas-height of the associated canvas of the working window] pixels high.";
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the control-window.]
        

    Section - Resizing the canvas

    The current command section is a snippet that varies.

    Resizing the canvas is an action applying to one topic. Understand "resize canvas [text]" as resizing the canvas.

    Carry out resizing the canvas:
        change the current command section to the topic understood;
        if the current command section includes "to [a number]":
            let x be the number understood;
        otherwise:
            say "Width measurement not detected. The proper phrasing is RESIZE CANVAS TO <width> BY <height>. Please try again.";
            rule fails;
        if the current command section includes "by [a number]" or the current command section includes "x [a number]":
            let y be the number understood;
        otherwise:
            say "Height measurement not detected. The proper phrasing is RESIZE CANVAS TO <width> BY <height>. Please try again.";
            rule fails;
        change the canvas-width of the associated canvas of the working window to x;
        change the canvas-height of the associated canvas of the working window to y;
        say "The canvas now measures [canvas-width of the associated canvas of the working window] pixels wide by [canvas-height of the associated canvas of the working window] pixels high.";
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the control-window.]
        

    Chapter - Assigning the background image

    Assigning the background image is an action applying to nothing. Understand "assign background image" or "assign sprite to background" or "assign sprite as background" or "make background" or "make background image" as assigning the background image.

    Check assigning the background image:
        if the number of entries of the element-selection set is greater than 1:
            say "Please select just one sprite.";
            rule fails;
        if the element-selection set is empty or entry 1 of the element-selection set is not a sprite:
            say "Please select a sprite and try again.";
            rule fails;
        unless entry 1 of the element-selection set is a sprite:
            say "The background image is required to be an image. Please select an image from the Image Library and try again.";
            rule fails.
            
    Carry out assigning the background image:
        let selected-image be the image-ID of entry 1 of the element-selection set;
        change the background image of the working canvas to the selected-image;
        change the canvas-width of the working canvas to the image-width of selected-image;
        change the canvas-height of the working canvas to the image-height of selected-image;
        [change the working window to image-backgrounded;]
        say "[selected-image] is now being used as the background image. The size of the canvas is determined by the size of the image, and is [canvas-width of the working canvas] pixels wide by [canvas-height of the working canvas] pixels high.[paragraph break]You may type REMOVE BACKGROUND IMAGE to remove the image, or RESIZE CANVAS TO <width> BY <height> to set the canvas dimensions independently of the image.";
        fake-delete entry 1 of the element-selection set;
        update the status line;
        consider the window-drawing rules for the working window;
        [follow the window-drawing rules for the control-window.]
        

    Chapter - Removing the background image
        
    Removing the background image is an action applying to nothing. Understand "delete background" or "remove background" or "delete background image" or "remove background image" or "delete canvas background image" or "remove canvas background image" or "delete canvas background" or "remove canvas background" as removing the background image.

    Check removing the background image:
        if the background image of the working canvas is Figure of Null:
            say "There is currently no background picture defined. To assign one, select a sprite and type ASSIGN TO BACKGROUND.";
            rule fails.
            
    Carry out removing the background image:
        now the background image of the working canvas is Figure of Null;
        refresh windows;
        say "The background image has been removed."


    Chapter - Rebuilding windows

    Rebuilding windows is an action applying to nothing. Understand "rebuild windows" or "rebuild" as rebuilding windows.

    Carry out rebuilding windows:
        say "Closing windows...[line break]";
        close editor windows;
        if canvas-height of working canvas > canvas-width of working canvas:
            now portrait orientation is true;
            set windows to portrait orientation;
        otherwise:
            now portrait orientation is false;
            set windows to landscape orientation;
        say "Reopening windows...[line break]";
        open editor windows;
        say "Windows rebuilt."

    To set windows to landscape orientation:
        now the measurement of the library-window is 20;
        now the measurement of the editor-window is 60;
        now the position of the editor-window is g-placeabove;
        now the position of the control-window is g-placeleft;
        now the measurement of the layers-window is 3;
        now the measurement of the help-window is 15.

    To close editor windows:
        if the library-window is g-present:
            shut down the library-window;
        shut down the editor-window;
        shut down the control-window.


    Part - Layer Commands

    The current display-layer is a number that varies. The current display-layer is 1.
    Maximum display-layer is a number that varies. Maximum display-layer is 24.


    Chapter - Changing the current display-layer

    Changing the current display-layer is an action applying to one number. Understand "change default layer to [number]" or "default layer [number]" as changing the current display-layer.

    Understand "layer [number]" or "l [number]" as changing the current display-layer when the number of entries of the element-selection set is 0.

    Check changing the current display-layer:
        if the number understood is less than 1 or the number understood is greater than the maximum display-layer:
            say "Please enter a number between 1 and [maximum display-layer].";
            rule fails;

    Carry out changing the current display-layer:
        change the current display-layer to the number understood;
        if the number understood is greater than indicated layers:
            now indicated layers is the number understood;
        follow the window-drawing rules for the working window;
        [follow the window-drawing rules for the control-window;]
        [follow the window-drawing rules for the layers-window];
        say "New elements will be created on display-layer [current display-layer].";
        

    Chapter - Moving elements between display-layers
        
    Changing the display-layer is an action applying to one number. Understand "move to layer [number]" or "move to display-layer [number]" or "change display-layer to [number]" or "change display-layer to [number]" or "display-layer [a number]" as changing the display-layer.

    Understand "layer [number]" or "l [number]" as changing the display-layer when the number of entries of the element-selection set is greater than 0.

    Check changing the display-layer:
        if the number of entries of the element-selection set < 1:
            say "Please select at least one element and try again.";
            rule fails;
        if the number understood is less than 1 or the number understood is greater than the maximum display-layer:
            say "Please enter a number between 1 and [maximum display-layer].";
            rule fails;
            
    Carry out changing the display-layer (this is the moving between layers rule):
        let L be a list of indexed text;
        let L be {};
        repeat with current-element running through the element-selection set:
            change the display-layer of the current-element to the number understood;
            add the element-name of the current-element to L;
        if the number understood is greater than indicated layers:
            now indicated layers is the number understood;
        [follow the window-drawing rules for the layers-window];
        follow the window-drawing rules for the working window;
        say "[if the number of entries of L is greater than 1]Elements[otherwise]Element[end if] [L] [if the number of entries of L is greater than 1]were[otherwise]was[end if] moved to display-layer [the number understood].";
        rule succeeds;

    Interactively changing the display-layer is an action applying to nothing. Understand "move to new layer" as interactively changing the display-layer.

    Check interactively changing the display-layer:
        if the number of entries of the element-selection set < 1:
            say "Please select at least one element and try again.";
            rule fails;

    Carry out interactively changing the display-layer:
        Now current question is "Which layer do you wish to move the selected element(s) to? There are currently [indicated layers] layers in use, and up to [maximum display-layer] available.";
        Now current prompt is "Enter a number from 1 to [maximum display-layer]: >";
        Now current cancelation message is "[bracket]Layer reassignment canceled[close bracket]";
        Ask an open question, in number mode;
        
    A number question rule when the impelling action is interactively changing the display-layer:
        if the number understood is less than 1 or the number understood is greater than the maximum display-layer:
            say "Please enter a number between 1 and [maximum display-layer].";
            retry;
        follow the moving between layers rule;
        exit.


    Chapter - Reveal/Conceal Layers command

    Layer-revelation is a truth state that varies. Layer-revelation is false.
        
    To append layer numbers:
        repeat through the Table of Graphlink Glulx Replacement Commands:
            if g-win entry is the working window:
                repeat with current-layer running through layer-elements:
                    let current-element be linkid entry;
                    if the display-layer of current-element is the layer-index of current-layer:
                        let image-ID be image-ID of current-layer;
                        let x be p-left entry;
                        let y be p-top entry;
                        display image-ID in the working window at x by y;

    Revealing layers is an action applying to nothing. Understand "reveal layers" or "reveal" as revealing layers.

    Understand "layers" as revealing layers when layer-revelation is false.
    Understand "layers" as concealing layers when layer-revelation is true.

    Carry out revealing layers:
        now layer-revelation is true;
        update layer_reveal_modal using layer-revelation;
        [follow the window-drawing rules for the control-window;]
        [follow the window-drawing rules for the layers-window;]
        follow the window-drawing rules for the working window;
        say "Layer-reveal mode is now active. The display-layer of each element in the editor window is identified by a number in the upper-left corner of the element.";
        
    Concealing layers is an action applying to nothing. Understand "hide layers" or "conceal layers" as concealing layers.

    Carry out concealing layers:
        now layer-revelation is false;
        update layer_reveal_modal using layer-revelation;
        [follow the window-drawing rules for the control-window;]
        [follow the window-drawing rules for the layers-window;]
        follow the window-drawing rules for the working window;
        say "Layer-reveal mode deactivated.";


    Part - Instanced Elements

    An instance is a kind of thing. An instance has a g-element called the instance-pointer. An instance has an indexed text called the instance-ref. An instance has an indexed text called the instance-kind. An instance has a list of numbers called the instance-origin. An instance has a number called the instance-layer. An instance has a real number called the instance x-scale. An instance has a real number called the instance y-scale. An instance has a figure name called the instance-identity. An instance has an indexed text called the instance-command.

    An instance has a list of numbers called the instance-endpoint. An instance has a number called the instance-line-weight. An instance has a glulx color value called the instance-foreground. An instance has a glulx color value called the instance-background.

    The mother-instance is an instance. The instance-pointer is the mother-sprite. The instance-ref is "". The instance-origin is {0, 0}. The instance-layer is 0. The instance x-scale is 1.0000. The instance y-scale is 1.0000. The instance-identity is Figure of Error. The instance-command is "". The instance-kind is "". The instance-endpoint is {0, 0}. The instance-line-weight is 0. The instance-foreground is g-black. The instance-background is g-black.

    The current instance is an instance that varies. The current instance is the mother-instance.

    Table of Current Element Instances
    instance-number instance-name
    number an instance
    with 10 blank rows


    Chapter - Registering an element instance

    Registering an element instance is an action applying to one topic. Understand "register [text]" or "record [text]" or "register as [text]" or "record as [text]" or "r [text]" as registering an element instance.

    Check registering an element instance:
        abide by the single sprite selection rule.
        
    This is the single sprite selection rule:
        let sprite-count be 0;
        let sprite-presence be false;
        repeat with current-selection running through the element-selection set:
            let sprite-count be sprite-count + 1;
            if current-selection is a sprite:
                let sprite-presence be true;
                break;
        if element-selection set is empty or sprite-presence is false:
            say "Please select one sprite and try again. (Note that, currently, only sprites can be instanced.)";
            rule fails;
        if the number of entries of the element-selection set is greater than 1 and sprite-presence is true:
            say "(Only the first selected sprite will be instanced.)";
        change entry 1 of the element-selection set to entry sprite-count of the element-selection set;
        truncate the element-selection set to 1 entries;
        follow the window-drawing rules for the working window.
            
    Carry out registering an element instance:
        now the current answer is the topic understood;
        replace the text "[quotation mark]" in the current answer with "";
        abide by the element instance registration rule.
        
    This is the element instance registration rule:
        let the selected-element be entry 1 of the element-selection set;
        now the selected-element is instanced;
        let the new instance be a new object cloned from the mother-instance;
        unlink the instance-ref of the new instance;
        unlink the instance-command of the new instance;
        unlink the instance-origin of the new instance;
        unlink the instance-kind of the new instance;
        change the instance-pointer of the new instance to the selected-element;
        change the instance-ref of the new instance to the current answer;
        if the selected-element is a sprite:
            change the instance-identity of the new instance to the image-ID of the selected-element;
        change the instance-origin of the new instance to the origin of the selected-element;
        change the instance-layer of the new instance to the display-layer of the selected-element;
        change the instance x-scale of the new instance to the x-scaling factor of the selected-element;
        change the instance y-scale of the new instance to the y-scaling factor of the selected-element;
        change the instance-command of the new instance to the replacement-command of the selected-element;
        if the selected-element is not a sprite:
            if the selected-element is a primitive:
                unlink the instance-endpoint of the new instance;
                change the instance-endpoint of the new instance to the endpoint of the selected-element;
            unless the selected-element is an image-rendered string:
                change the instance-foreground of the new instance to the tint of the selected-element;
            unless the selected-element is a rendered string:
                change the instance-line-weight of the new instance to the line-weight of the selected-element;
            if the selected-element is a bitmap-rendered string:
                change the instance-line-weight of the new instance to the bit-size of the selected-element;
            if the selected-element is a stroked rectangle primitive or the selected-element is a bitmap-rendered string:
                change the instance-background of the new instance to the background tint of the selected-element;
        say "The element [element-name of selected-element] has been recorded at [origin of selected-element in brace notation], layer [display-layer of selected-element], scaled at [x-scaling factor of the selected-element][if we are scaling asymmetrically] x [y-scaling factor of the selected-element][end if], with the reference [italic type][the current answer][roman type]. (Note that all properties of an element are saved, not just those listed here.)";
        
    Indicating an element instance is an action applying to nothing. Understand "register" or "register instance" or "register element instance"or "record" or "r" as indicating an element instance.

    Check indicating an element instance:
        abide by the single sprite selection rule.
        
    Carry out indicating an element instance:
        Now the current question is "Please provide a reference ID for this instance of the element. The reference ID can be a word, phrase, or number that will allow you to distinguish between instances in your source code.";
        Now the current prompt is "Reference ID: >";
        now the current cancelation message is "[bracket]Element instance registration canceled.[close bracket]";
        Ask an open question, in text mode;
        
    A text question rule when the impelling action is indicating an element instance:
        abide by the element instance registration rule;
        exit.
        

    Chapter - Show element instances

    Listing element instances is an action applying to nothing. Understand "instances" or "list instances" as listing element instances.

    Check listing element instances:
        abide by the single element selection rule.
        
    Carry out listing element instances:
        abide by the element instances listing rule;
        say "[paragraph break]";
        say "To delete an element instance, type DELETE INSTANCE. To create a new element having the same characteristics as one of these instances, type LOAD INSTANCE.";
        
    This is the element instances listing rule:
        let the selected-element be entry 1 of the element-selection set;
        if the selected-element is not instanced:
            say "The selected element has no recorded instances.";
            rule fails;
        say "The following instances are recorded for [element-name of the selected-element]:[line break]";
        let count be 0;
        repeat through the Table of Current Element Instances:
            blank out the whole row;
        repeat with item running through the list of instances:
            if the selected-element is the instance-pointer of item:
                increase count by 1;
                unless the instance-kind of item is the of-kind of the selected-element:
                    change the instance-kind of the item to the of-kind of the selected-element;
                say "[line break][bracket][count][close bracket] [italic type][instance-ref of item]:[roman type] layer [instance-layer of item]; [instance-origin of item in brace notation]; scale [instance x-scale of item][if we are scaling asymmetrically] x [instance y-scale of item][end if]";
                if the number of blank rows in the Table of Current Element Instances < 2:
                    let N be the number of rows in the Table of Current Element Instances;
                    change the Table of Current Element Instances to have N + 2 rows;
                choose a blank row in the Table of Current Element Instances;
                change instance-number entry to count;
                change instance-name entry to item;
                

    Chapter - Deleting an element instance

    Deleting an element instance is an action applying to nothing. Understand "delete instance" or "delete element instance" as deleting an element instance.

    Check deleting an element instance:
        abide by the single element selection rule.
        
    Carry out deleting an element instance:
        abide by the element instances listing rule;
        say "[paragraph break]";
        now the current question is "Type the number of the instance you would like to delete.";
        now the current prompt is "Enter a number from the list: >";
        now the current cancelation message is "[bracket]Operation canceled.[close bracket]";
        ask an open question, in number mode;
        
    This is the instance menu input validation rule:
        unless there is an instance-number of the number understood in the Table of Current Element Instances:
            say "Type the number corresponding to one of the instances listed above, or any other command to cancel.";
            retry;
        
    A number question rule when the impelling action is deleting an element instance:
        abide by the instance menu input validation rule;
        now the current instance is the instance-name corresponding to an instance-number of the number understood in the Table of Current Element Instances;
        now the instance-pointer of the current instance is the mother-sprite;
        let the selected-element be entry 1 of the element-selection set;
        repeat with item running through the list of instances:
            if the instance-pointer of item is the selected-element:
                let instanced-element be true;
                break;
            let instanced-element be false;
        if instanced-element is false:
            now the selected-element is standard;
        if instanced-element is true:
            now the selected-element is instanced;
        say "Instance deleted.";
        exit.

        

    Chapter - Loading an element instance

    Loading an element instance is an action applying to nothing. Understand "load instance" or "load element instance" as loading an element instance.

    Check loading an element instance:
        abide by the single element selection rule.
        
    Carry out loading an element instance:
        abide by the element instances listing rule;
        say "[paragraph break]";
        now the current question is "Type the number of the instance you would like to load. This will create a new element with the characteristics of the selected instance.";
        now the current prompt is "Enter a number from the list: >";
        now the current cancelation message is "[bracket]Operation canceled.[close bracket]";
        ask an open question, in number mode;
        
    A number question rule when the impelling action is loading an element instance:
        abide by the instance menu input validation rule;
        now the current instance is the instance-name corresponding to an instance-number of the number understood in the Table of Current Element Instances;
        let the new element be a new object cloned from the instance-pointer of the current instance;
        now the new element is standard;
        unlink the element-name of the new element;
        now the element-name of the new element is "[element-name of the instance-pointer of the current instance]_[instance-ref of the current instance]";
        unlink the of-kind of the new element;
        unlink the replacement-command of the new element;
        change the replacement-command of the new element to the instance-command of the current instance;
        change the x-scaling factor of the new element to the instance x-scale of the current instance;
        change the y-scaling factor of the new element to the instance y-scale of the current instance;
        change the display-layer of the new element to the instance-layer of the current instance;
        unlink the origin of the new element;
        change the origin of the new element to the instance-origin of the current instance;
        change the image-ID of the new element to the instance-identity of the current instance;
        say "Loaded instance [element-name of the new element].";
        follow the window-drawing rules for the working window;
        follow the window-drawing rules for the layers-window;
        exit.


    Part - Changing the image-ID

    The identity reassignment mode is a truth state that varies. Identity reassignment mode is false.

    Reassigning the element identity is an action applying to nothing. Understand "reassign sprite identity" or "reassign image-ID" or "change sprite ID" or "change image-ID" or "reassign" or "identity" or "image-ID" as reassigning the element identity.

    Check reassigning the element identity:
        unless entry 1 of the element-selection set is a sprite:
            say "Please select a sprite and try again.";
            rule fails;
        abide by the single element selection rule.

    Carry out reassigning the element identity:
        unless identity reassignment mode is true:
            say "Please click on an element in the library to change the image-ID of the sprite selected in the editor. Cancel by clicking on any other button.";
            now identity reassignment mode is true;
            rule succeeds;


    Part - Alignment commands


    Chapter - The center command

    The center-overlay mode is a truth state that varies. Center-overlay mode is false.

    Centering elements on is an action applying to nothing. Understand "center" or "center element" or "center element on" or "center on" as centering elements on.

    Check centering elements on:
        abide by the single element selection rule.
        
    Carry out centering elements on:
        say "Please click on a element in the editor window to center the selected element on that element. Cancel by clicking on any other button.";
        now center-overlay mode is true;
        [actuate the Select_tab;]
        [follow the window-drawing rules for the control-window;]
        
    To center (A - a g-element) on (B - a g-element):
        [This phrase is called by the element select rule for clicking in the working window]
        if A is a linkid listed in the Table of Graphlink Glulx Replacement Commands:
            let L be the canvas equivalent of the screen coordinates p-right entry by p-bottom entry of the working window;
            let AR be entry 1 of L;
            let AB be entry 2 of L;
            let A-width be AR minus entry 1 of the origin of A;
            let A-height be AB minus entry 2 of the origin of A;
        otherwise:
            say "***Error: Selected element not found.";
            rule fails;
        if B is a linkid listed in the Table of Graphlink Glulx Replacement Commands:
            let L be the canvas equivalent of the screen coordinates p-right entry by p-bottom entry of the working window;
            let BR be entry 1 of L;
            let BB be entry 2 of L;
            let B-width be BR minus entry 1 of the origin of B;
            let B-height be BB minus entry 2 of the origin of B;
        otherwise:
            say "***Error: Target element not found.";
        let x be (B-width minus A-width) divided by 2;
        if A is left-aligned:
            let x be x plus entry 1 of the origin of B;
        if A is center-aligned:
            let x be entry 1 of the origin of B + (B-width / 2);
        if A is right-aligned:
            do nothing;
            [let x be BR - (B-width / 2) + (length of A / 2);]
        let y be (B-height minus A-height) divided by 2;
        let y be y plus entry 2 of the origin of B;
        change entry 1 of the origin of A to x;
        change entry 2 of the origin of A to y;
        if A is a primitive:
            let x1 be entry 1 of the origin of A;
            let y1 be entry 2 of the origin of A;
            change entry 1 of the endpoint of A to x1 plus (the element-width of A);
            change entry 2 of the endpoint of A to y1 plus (the element-height of A);
        now center-overlay mode is false;
        consider the window-drawing rules for the current graphlink window;


    Chapter - The align command

    A border-name is a kind of value. The border-names are top, bottom, right, and left.

    The alignment mode is a truth state that varies. Alignment mode is false.

    Aligning elements is an action applying to one value. Understand "align [a border-name]" or "align to [a border-name]" or "align element to [a border-name]" as aligning elements.

    Check aligning elements:
        abide by the single element selection rule.

    Carry out aligning elements:
        say "Please click on an element in the editor window to align the selected element to the [border-name understood] of that element. Cancel by clicking on any other button.";
        now alignment mode is true;
        [actuate the Select_tab;]
        [follow the window-drawing rules for the control-window;]

    To align (A - a g-element) to the (B - a g-element) according to (target side - a border-name):
        [This phrase is called by the element select rule for clicking in the working window]
        if A is a linkid listed in the Table of Graphlink Glulx Replacement Commands:
            let L be the canvas equivalent of the screen coordinates p-right entry by p-bottom entry of the working window;
            let AR be entry 1 of L;
            let AB be entry 2 of L;
            let A-width be AR minus entry 1 of the origin of A;
            let A-height be AB minus entry 2 of the origin of A;
        otherwise:
            say "***Error: Selected element not found.";
            rule fails;
        if B is a linkid listed in the Table of Graphlink Glulx Replacement Commands:
            let L be the canvas equivalent of the screen coordinates p-right entry by p-bottom entry of the working window;
            let BR be entry 1 of L;
            let BB be entry 2 of L;
            let B-width be BR minus entry 1 of the origin of B;
            let B-height be BB minus entry 2 of the origin of B;
            if the target side is top:
                let y be entry 2 of the origin of B minus A-height;
                let x be (B-width minus A-width) divided by 2;
                let x be x plus entry 1 of the origin of B;
            if the target side is left:
                let x be entry 1 of the origin of B minus A-width;
                let y be (B-height minus A-height) divided by 2;
                let y be y plus entry 2 of the origin of B;
            if the target side is right:
                let x be BR;
                let y be (B-height minus A-height) divided by 2;
                let y be y plus entry 2 of the origin of B;
            if the target side is bottom:
                let y be BB;
                let x be (B-width minus A-width) divided by 2;
                let x be x plus entry 1 of the origin of B;
        otherwise:
            say "***Error: Target element not found.";
        change entry 1 of the origin of A to x;
        change entry 2 of the origin of A to y;
        if A is a primitive:
            change entry 1 of the endpoint of A to x plus (the element-width of A);
            change entry 2 of the endpoint of A to y plus (the element-height of A);
        now alignment mode is false;
        consider the window-drawing rules for the current graphlink window;


    Part - Source code generation and settings


    Chapter - Selecting the style of source code output

    Styling the output as tabular is an action applying to nothing. Understand "tabular output" as styling the output as tabular.

    Carry out styling the output as tabular (this is the tabular styling rule):
        Say "Source code output will use tables where appropriate.";
        now table-option is true;
        update tabular_source_radio using table-option;
        [follow the window-drawing rules for the control-window;]
        
    Styling the output as paragraphed is an action applying to nothing. Understand "paragraph output" or "standard output" or "paragraphed output" as styling the output as paragraphed.

    Carry out styling the output as paragraphed (this is the paragraphed styling rule):
        Say "Source code output will be styled using paragraphs.";
        now table-option is false;
        update tabular_source_radio using table-option;
        [follow the window-drawing rules for the control-window;]
        
    Toggling the output style is an action applying to nothing. Understand "toggle output style" as toggling the output style.

    Carry out toggling the output style:
        if table-option is true:
            follow the paragraphed styling rule;
        otherwise:
            follow the tabular styling rule;
        

    Chapter - Changing the name of the Flexible Windows target window

    Renaming the targeted canvas is an action applying to one topic. Understand "rename the target canvas [text]" or "rename canvas [text]" or "rename the canvas [text]" or "canvas [text]" or "rename target canvas [text]" as renaming the targeted canvas.
            
    Carry out renaming the targeted canvas:
        let T be indexed text;
        let T be the topic understood;
        replace the text "[quotation mark]" in T with "";
        change the targeted canvas to T;
        say "Source code will be generated targeting the canvas [italic type][targeted canvas][roman type]".
        

    Chapter - Generating source code

    The file of Output is called "GlimmrSource".

    The kind-parsed omnibus is a list of lists of objects that varies.
    The numbered-kinds index is a list of numbers that varies. [This list exists as part of an elaborate workaround for a bug in 5Z71 that prevented Inform from sorting lists of objects on indexed text properties.]

    The kinds-count is a number that varies.

    The graphlink_active is a thing. The graphlink_absent is a thing. [These are dummy objects that will occupy the first position in each of the parsed lists; graphlink_present indicates that *all* of the sprites of a given kind have graphlinks.]

    To say tab:
        if the current action is generating source code:
            say direct-character placement tab;
        otherwise:
            say " ".
        

    Section - The generating source code action

    Generating source code is an action applying to nothing. Understand "generate source" or "generate source code" or "source code" or "source" as generating source code.

    Check generating source code (this is the check for defined elements rule):
        if the number of entries of the list of standard g-elements plus the number of entries of the list of instanced g-elements is less than 1:
            say "You have not yet defined any canvas elements. To get started, click on an image in the library window to the right to spawn a sprite in the main graphics window, or use the drawing tools to create a primitive or text element. (If the drawing toolbar is not visible, click on the pencil icon in the control panel to bring it up).";
            rule fails.
            
    Carry out generating source code:
        follow the source code generation rule.
        
    After generating source code:
        say "Source code output to file. Please check your hard drive for the text file, or type PREVIEW SOURCE CODE to see the source in the game window. (Inform cannot print tabs to the window, so previewed code will use spaces instead, and the code will not compile when pasted into the IDE. You should use the GENERATE SOURCE CODE command when you are ready to copy source for compilation.)";
        

    Section - Generating the source
        
    This is the source code generation rule:
        write "[quotation mark][story title][quotation mark][unless story author is null] by [story author][end if][paragraph break]" to the file of Output;
        append "[bracket]Source code generated automatically by Glimmr Canvas Editor.[close bracket][paragraph break]" to the file of Output;
        write preamble;
        unless the user-specified source text is "":
            append "[user-specified source text][paragraph break]" to the file of Output;
        index element-kinds for parsing;[workaround; see below]
        evaluate element-kinds;
        parse element-kinds;
        if we have asymmetrical elements, append "Use asymmetrical scaling.[paragraph break]" to the file of Output;
        unless table-option is true:
            write paragraphed source code;
        otherwise:
            write tabulated source code;
        if we have instanced elements, write listings for instances.

    The user-specified source text is a text variable.
        

    Section - Summarization phrases

    To decide whether we have graphic links:
        repeat with current-element running through g-elements displayed on the working canvas:
            unless the current-element is deleted:
                unless the replacement-command of the current-element is "":
                    decide yes;
        decide no;

    To decide whether we have instanced elements:
        if the number of entries of list of instanced g-elements is greater than 0, decide yes;
        decide no.
        
    To decide whether we have asymmetrical elements:
        [asymmetrical scaling affects only sprites, so we only look at dynamic sprites.]
        repeat with current-element running through dynamic-sprites:
            if the associated canvas of the current-element is the working canvas:
                unless the current-element is deleted:
                    unless the x-scaling factor of the current-element is the y-scaling factor of the current-element:
                        decide yes;
        decide no;
        
    To decide if (S - a g-element) is graphic-linked:
        unless the replacement-command of S is "":
            decide yes;
        decide no;
        
    To decide whether we have primitives:
        repeat with item running through the list of in-play primitives assigned to the working window:
            unless item is deleted:
                decide yes;
        decide no;
        
    To decide whether we have rendered strings:
        repeat with item running through the list of in-play rendered strings assigned to the working window:
            unless item is deleted:
                decide yes;
        decide no;

    To decide whether we have tags:
        repeat with item running through the list of in-play g-elements assigned to the working window:
            if the tag of item is not "":
                decide yes;
        decide no.

    To decide whether we have a map:
        let L be the list of rooms;
        remove fake-room_x from L;
        if the number of entries of L > 0:
            decide yes;
        decide no.

    To decide whether we have customized colors:
        repeat with current-hue running through the drawing colors:
            if current-hue is not a glulx color value listed in the Table of Default Color Values:
                decide yes;
        if the back-colour of the working window is not a glulx color value listed in the Table of Default Color Values:
            decide yes;
        decide no.

        
    Table of Default Color Values
    glulx color value
    g-black
    g-dark-grey
    g-medium-grey
    g-light-grey
    g-white
    g-placenullcol
    g-darkgreen
    g-green
    g-lime
    g-midnightblue
    g-steelblue
    g-terracotta
    g-navy
    g-mediumblue
    g-blue
    g-indigo
    g-cornflowerblue
    g-mediumslateblue
    g-maroon
    g-red
    g-deeppink
    g-brown
    g-darkviolet
    g-khaki
    g-silver
    g-crimson
    g-orangered
    g-gold
    g-darkorange
    g-lavender
    g-yellow
    g-pink
        

    Section - Writing inclusions and graphics window code to the source

    To write the/-- preamble:
        append "Include Glimmr Canvas-Based Drawing by Erik Temple.[if we have rendered strings][line break]Include Glimmr Text-Painting Elements by Erik Temple.[font extensions][end if][paragraph break]" to the file of Output;
        append "Chapter - Scenario[paragraph break]" to the file of Output;
        if we have a map:
            append "[bracket]Insert code here, particularly the definition of rooms and their connections. The following rooms were present in the geography defined in the source for the Canvas Editor: " to the file of Output;
            let L be the list of rooms;
            remove fake-room_x from L;
            append "[L]" to the file of Output;
        otherwise:
            append "Starting Room is a room" to the file of Output;
        append ".[close bracket][paragraph break]" to the file of Output;
        append "Chapter - Figure Definitions[paragraph break][bracket]Paste the list of figure definitions here (e.g., Figure of Error is the file [quotation mark]Error.png[quotation mark])[close bracket][paragraph break]Chapter - Canvas and window[paragraph break]The graphics-window is a graphics g-window spawned by the main-window. The position of the graphics-window is [position of the working window]. The measurement of the graphics-window is 50. The back-colour of the graphics-window is [back-colour of working window].[paragraph break]The [targeted canvas] is a g-canvas. The canvas-width is [canvas-width of the working canvas]. The canvas-height is [canvas-height of the working canvas]. [unless the background image of the working canvas is Figure of Null]The background image of the [targeted canvas] is [background image of the working canvas]. [end unless]The associated canvas of the graphics-window is [targeted canvas]. [paragraph break]When play begins:[line break][tab]open up the graphics-window. " to the file of Output;
        if we have customized colors:
            append "[paragraph break]Chapter - Custom colors[paragraph break][bracket]You may have used glulx color values not supplied in Glulx Text Effects or Flexible Windows. As a convenience, these color values are provided in the table below. However, please note that if you are using an extension, such as HTML colors for Glulx Text Effects, that provides these colors, you may need to delete the table below to get your game to compile.[close bracket][paragraph break]Table of Common Color Values (continued)[line break]glulx color value[tab]assigned number[line break]" to the file of Output;
            repeat with current-hue running through the drawing colors:
                if current-hue is not a glulx color value listed in the Table of Default Color Values:
                    append "[current-hue][tab][assigned number of current-hue][line break]" to the file of Output;
                if the back-colour of the working window is not a glulx color value listed in the Table of Default Color Values and the back-colour of the working window is not listed in the drawing colors:
                 append "[back-colour of working window][tab][assigned number of back-colour of working window]" to the file of Output;
        if we have tags:
            append "[paragraph break]Chapter - Special element properties[paragraph break][bracket]This property reflects the tag(s) assigned in the editor.[close bracket][paragraph break]A g-element has a [tag type] called the [tag-surround][tag alias][tag-surround]." to the file of Output;
        append "[paragraph break]" to the file of Output;

    To say font extensions:
        let L be a list of texts;
        repeat with item running through in-play rendered strings:
            let X be the extension-name of the associated font of item;
            if X is not "":
                add X to L, if absent;
        repeat with item running through L:
            say "[line break]Include [item].[run paragraph on]";
        say "[line break]".


    Section - Sorting and otherwise preparing kinds

    To index element-kinds for parsing: [this is a workaround for a bug in 5Z71 that prevented us from sorting a list based on an indexed-text property.]
        let N be a list of indexed text;
        let L be the list of in-play g-elements;
        repeat with current-element running through L:
            now the kind-index of current-element is 0;
            if the of-kind of current-element is not "":
                add the of-kind of the current-element to N, if absent;
        unless N is {}:
            let count be 0;
            repeat with current-kind running through N:
                increase count by 1;
                repeat with current-element running through L:
                    if the of-kind of current-element is the current-kind:
                        change the kind-index of the current-element to count;
                        [say "Indexing:[line break]";
                        say "Kind index of [element-name of current-element] set to:[kind-index of current-element].";]
        change kinds-count to the number of entries of N.
        
    To evaluate element-kinds:
        let L be the list of in-play g-elements;
        sort L in kind-index order;
        let kind-comparison be the kind-index of entry 1 of L;
        let type-comparison be the kind-flag of entry 1 of L;
        repeat with current-element running through L:
            if the kind-index of current-element is not 0 and the kind-index of current-element is the kind-comparison:
                if the kind-flag of current-element is not the type-comparison:
                    say "[one of]****Warning: Two elements of different types have been assigned the same kind. The code output will not compile properly. The first issue was encountered with the [kind-flag of current-element] [element-name of current-element], which problematically has been assigned the kind [of-kind of current-element].[paragraph break][or][stopping]";
            let kind-comparison be the kind-index of current-element;
            let type-comparison be the kind-flag of current-element;
            increase the kind-index of the current-element by the appropriate type count for the current-element;
            [say "Evaluating:[line break]";
            say "Kind index set to:[kind-index of current-element] ([kind-flag of current-element]:[of-kind of current-element]).".]
            
    To decide what number is the appropriate type count to/for (current-element - a g-element):
        if the kind-flag of current-element is "sprite", decide on 1000;
        if the kind-flag of current-element is "rectangle primitive", decide on 2000;
        if the kind-flag of current-element is "box primitive", decide on 3000;
        if the kind-flag of current-element is "stroked rectangle primitive", decide on 4000;
        if the kind-flag of current-element is "line primitive", decide on 5000;
        if the kind-flag of current-element is "bitmap-rendered string", decide on 6000;
        if the kind-flag of current-element is "image-rendered string", decide on 7000.
        
    To parse element-kinds:
        now the kind-parsed omnibus is {};
        let L be the list of standard g-elements;
        add the list of instanced g-elements to L;
        sort L in kind-index order;
        [say "The list of standard elements:";
        repeat with S running through L:
            say "[of-kind of S], ";
        say "[line break]";]
        let current-kind be the kind-index of entry 1 of L;
        let graphlink_cnt be 0;
        let graphlink-kinds be 0;
        let T be a list of objects;
        let count be 0;
        let kinds-counter be 1;
        repeat with current-element running through L:
            increase count by 1;
            [say "master list number: [count][line break]";]
            unless the replacement-command of the current-element is "":
                let graphlink_cnt be graphlink_cnt + 1;
                [say "graphlink count increased to [graphlink_cnt].[line break]";]
            if count is the number of entries of L:
                [say "element of kind [current-kind][line break]";]
                add current-element to T;
                increase kinds-counter by 1;
                if the graphlink_cnt is not 0 and the graphlink_cnt is the number of entries of T:
                    add graphlink_active at entry 1 in T;
                    increase graphlink-kinds by 1;
                    [say "adding graphlink to list.[line break]";]
                otherwise:
                    add graphlink_absent at entry 1 in T;
                    [say "list not graphlinked.[line break]";]
                [say "list parsed: [T][line break]";]
                add T to the kind-parsed omnibus;
            otherwise unless the kind-index of entry (count + 1) of L is the current-kind:
                [say "element of kind [current-kind][line break]";]
                add current-element to T;
                if the graphlink_cnt is not 0 and the graphlink_cnt is the number of entries of T:
                    add graphlink_active at entry 1 in T;
                    increase graphlink-kinds by 1;
                    [say "adding graphlink to list.[line break]";]
                otherwise:
                    add graphlink_absent at entry 1 in T;
                    [say "list not graphlinked.[line break]";]
                add T to the kind-parsed omnibus;
                now T is {};
                let the graphlink_cnt be 0;
                increase kinds-counter by 1;
                now current-kind is the kind-index of entry (count + 1) of L;
                [say "New list detected: [current-kind][line break]";]
            otherwise:
                [say "element of kind [current-kind][line break]";]
                add the current-element to T;
        [say "[paragraph break]The kind-parsed omnibus:[line break]";
        repeat with current-list running through the kind-parsed omnibus:
            say "New list-->[line break]";
            repeat with current-element running through current-list:
                if current-element is entry 1 of current-list:
                    next;
                say "[element-name of current-element]: [of-kind of current-element] ([kind-flag of current-element]): [kind-index of current-element]."]
                            

    Section - Writing the body of the source code

    To write paragraphed source code:
        repeat with current-list running through the kind-parsed omnibus:
            let current-kind be indexed text;
            if the remainder after dividing the kind-index of entry 2 of current-list by 1000 is less than 1:[the sublist is for first-level elements (i.e., not a subkind)]
                let super-kind be true;
                let current-kind be the kind-flag of entry 2 of current-list;
            otherwise:
                let super-kind be false;
                let current-kind be the of-kind of entry 2 of current-list;
            if current-kind matches the regular expression "^<aeiou>", case insensitively:
                let kind-article be "an";
            otherwise:
                let kind-article be "a";
            append "[if super-kind is true]Chapter - [current-kind in sentence case]s[otherwise]Section - [current-kind in sentence case] [kind-flag of entry 2 of current-list]s[end if][paragraph break]" to the file of Output;
            unless super-kind is true, append "[kind-article in sentence case] [current-kind] is a kind of [kind-flag of entry 2 of current-list]. " to the file of Output;
            append "The graphlink status of [kind-article] [current-kind] is [if entry 1 of the current-list is graphlink_active]g-active[otherwise]g-inactive[end if]. " to the file of Output;
            append "The associated canvas of [kind-article] [current-kind] is [targeted canvas]. " to the file of Output;
            append "[paragraph break]" to the file of Output;
            repeat with current-element running through the current-list:
                if current-element is graphlink_active or current-element is graphlink_absent:
                    next;
                append "[element-name of current-element in sentence case] is [kind-article] [current-kind]. [if current-element is a dynamic-sprite]The image-ID is [image-ID of current-element].[end if] The origin is [origin of current-element in brace notation]. [if current-element provides the property endpoint] The endpoint is [endpoint of current-element in brace notation].[end if] [if current-element provides the property line-weight]The line-weight is [line-weight of current-element].[end if][if current-element provides the property text-string] The text-string is [quotation mark][text-string of current-element][quotation mark]. The associated font is [associated font of current-element]. [element-name of current-element in sentence case] is [alignment of current-element].[end if][if current-element provides the property tint and current-element is not a dynamic-image-string] The tint is [tint of current-element]. [end if][if current-element provides the property background tint]The background tint is [background tint of current-element]. [end if]" to the file of Output;
                if the x-scaling factor of the current-element is not 1.0000 or the y-scaling factor of the current-element is not 1.0000:
                    if we have asymmetrical elements:
                        append "The x-scaling factor is [x-scaling factor of current-element]. The y-scaling factor is [y-scaling factor of current-element]. " to the file of Output;
                    otherwise:
                        append "The scaling factor is [x-scaling factor of current-element]. " to the file of Output;
                append " The display-layer is [display-layer of current-element]. " to the file of Output;
                if the current-element is display-inactive:
                    append "The display status of [element-name of current-element] is g-inactive. " to the file of Output;
                unless the tag of the current-element is "":
                    append "The [tag alias] of [element-name of current-element] is [tag-surround][tag of current-element][tag-surround]. " to the file of Output;
                if entry 1 of the current-list is graphlink_absent and the current-element is graphic-linked, append "The graphlink status of [element-name of current-element] is g-active. " to the file of Output;
                if the current-element is graphic-linked, append "The linked replacement-command is [quotation mark][replacement-command of current-element][quotation mark]. " to the file of Output;
                append "[paragraph break]" to the file of Output;

                
    To write tabulated source code:
        repeat with current-list running through the kind-parsed omnibus:
            let current-kind be indexed text;
            if the remainder after dividing the kind-index of entry 2 of current-list by 1000 is less than 1:[the sublist is for first-level elements (i.e., not a subkind)]
                let super-kind be true;
                let current-kind be the kind-flag of entry 2 of current-list;
            otherwise:
                let super-kind be false;
                let current-kind be the of-kind of entry 2 of current-list;
            if current-kind matches the regular expression "^<aeiou>", case insensitively:
                let kind-article be "an";
            otherwise:
                let kind-article be "a";
            append "[if super-kind is true]Chapter - [current-kind in sentence case]s[otherwise]Section - [current-kind in sentence case] [kind-flag of entry 2 of current-list]s[end if][paragraph break]" to the file of Output;
            unless super-kind is true, append "[kind-article in sentence case] [current-kind] is a kind of [kind-flag of entry 2 of current-list]. " to the file of Output;
            append "The graphlink status of [kind-article] [current-kind] is [if entry 1 of the current-list is graphlink_active]g-active[otherwise]g-inactive[end if]. " to the file of Output;
            append "The associated canvas of [kind-article] [current-kind] is [targeted canvas]. " to the file of Output;
            append "[paragraph break]" to the file of Output;
            append "Some [current-kind]s are defined by the Table of [current-kind in sentence case] Elements.[paragraph break]" to the file of Output;
            append "Table of [current-kind in title case] Elements[line break][current-kind][tab]origin[if entry 2 of the current-list provides the property endpoint][tab]endpoint[end if][if entry 2 of the current-list provides the property image-ID][tab]image-ID[end if][if entry 2 of the current-list provides the property line-weight][tab]line-weight[end if]" to the file of Output;
            append "[if entry 2 of the current-list provides the property bit-size][tab]bit-size[end if][if entry 2 of the current-list provides the property text-string][tab]text-string[tab]associated font[end if][if entry 2 of the current-list provides the property tint][tab]tint[end if][if entry 2 of the current-list provides the property background tint][tab]background tint[end if][tab]display-layer[tab]display status" to the file of Output;
            if we have asymmetrical elements:
                append "[tab]x-scaling factor[tab]y-scaling factor" to the file of Output;
            otherwise:
                append "[tab]scaling factor" to the file of Output;
            if entry 1 of the current-list is graphlink_active:
                append "[tab]linked replacement-command" to the file of Output;
            if we have tags:
                append "[tab][tag alias]" to the file of Output;
            append "[line break]" to the file of Output;
            repeat with current-element running through the current-list:
                if current-element is graphlink_active or current-element is graphlink_absent:
                    next;
                append "[element-name of current-element][tab][origin of current-element in brace notation][if entry 2 of the current-list provides the property endpoint][tab][endpoint of current-element in brace notation][end if][if entry 2 of the current-list provides the property image-ID][tab][image-ID of current-element][end if][if entry 2 of the current-list provides the property line-weight][tab][line-weight of current-element][end if][if entry 2 of the current-list provides the property bit-size][tab][bit-size of current-element][end if]" to the file of Output;
                append "[if entry 2 of the current-list provides the property text-string][tab][quotation mark][text-string of current-element][quotation mark][tab][associated font of current-element][end if][if entry 2 of the current-list provides the property tint][tab][tint of current-element][end if][if entry 2 of the current-list provides the property background tint][tab][background tint of current-element][end if][tab][display-layer of current-element][tab][display status of current-element]" to the file of Output;
                if we have asymmetrical elements:
                    append "[tab][x-scaling factor of current-element][tab][y-scaling factor of current-element]" to the file of Output;
                otherwise:
                    append "[tab][x-scaling factor of current-element]" to the file of Output;
                if entry 1 of the current-list is graphlink_active:
                    append "[tab][quotation mark][replacement-command of current-element][quotation mark]" to the file of Output;
                if we have tags:
                    if the tag of current-element is "":
                        append "[tab]--" to the file of Output;
                    otherwise:
                        append "[tab][tag-surround][tag of current-element][tag-surround]" to the file of Output;
                append "[line break]" to the file of Output;
            repeat with current-element running through the current-list:
                if current-element is graphlink_active or current-element is graphlink_absent:
                    next;
                if entry 1 of the current-list is graphlink_absent and the current-element is graphic-linked:
                    append "[one of][paragraph break][or][stopping]" to the file of Output;
                    append "The graphlink status of [element-name of current-element] is g-active. The linked replacement-command is [quotation mark][replacement-command of current-element][quotation mark]" to the file of Output;
            append "[paragraph break]" to the file of Output;
                
    To decide whether (current-element - a g-element) is a primitive:
        if the kind-flag of the current-element matches the text "primitive", decide yes;
        decide no.
                

    Section - Appending the list of element instances to the source code
                
    To write listings for instances:
        append "[bracket]Following is a list of [quotation mark]instances[quotation mark] provided for elements that change in some tangible way--their size, scale, or the image associated with them, for example--over the course of the game. Because there are many different ways in which this information could be used, it is provided as a simple table of attributes rather than as compilable source code. You may copy and paste the table data into Excel, Numbers, or Google Spreadsheets to easily select and manipulate the attribute information.[paragraph break]" to the file of Output;
        repeat with item running through the list of instances:
            [ensures that all of the instances generated from a given element have the same kind currently held by the element.]
            let the selected-element be the instance-pointer of item;
            unless the instance-kind of item is the of-kind of the selected-element:
                change the instance-kind of the item to the of-kind of the selected-element;
        repeat with current-list running through the kind-parsed omnibus:
            [This routine take the long way around via the kind-parsed omnibus list as another workaround to the bug in 5Z71 that prevented lists being sorted on indexed text.]
            if entry 2 of current-list is not a sprite:
                next;
            unless the current-list contains an instanced element:
                next;
            let current-kind be the of-kind of entry 2 of current-list;
            let current-type be the kind-flag of entry 2 of current-list;
            append "[line break]***[current-type in sentence case] elements[unless current-kind is null] of kind [current-kind][end if]***[paragraph break]" to the file of Output;
            append "[current-type][tab]reference[tab]origin[tab]image-ID[tab]display-layer[if we are scaling asymmetrically][tab]x-scaling factor[tab]y-scaling factor[otherwise][tab]scaling factor[end if][tab]linked replacement-command[line break]" to the file of Output;
            repeat with current-element running through the current-list:
                if current-element is instanced:
                    repeat with item running through the list of instances:
                        if the current-element is the instance-pointer of item:
                            append "[element-name of current-element][tab][instance-ref of item][tab][instance-origin of item in brace notation][tab][instance-identity of item][tab][instance-layer of item][if we are scaling asymmetrically][tab][instance x-scale of item][tab][instance y-scale of item][otherwise][tab][instance x-scale of item][end if][tab][unless instance-command of item is null][instance-command of item][otherwise][quotation mark][quotation mark][end if][line break]" to the file of Output;
        append "[close bracket][paragraph break]" to the file of Output;
        
    To decide whether (T - an indexed text) is null:
        if T is "", decide yes;
        decide no.

    To decide whether (L - a list of objects) contains an instanced element:
        repeat with item running through L:
            if item is instanced, decide yes;
        decide no.


    Chapter - Previewing source code

    Previewing source code is an action applying to nothing. Understand "preview source code" or "preview source" or "preview" as previewing source code.

    Check previewing source code:
        abide by the check for defined elements rule;
            
    Carry out previewing source code:
        say "[italic type]Inform cannot print tabs to the window, so previewed code will use spaces instead. A file with tabs has been written to your hard drive. (Type GENERATE SOURCE CODE to skip the preview and write the file directly.) Here is the source code:[roman type][line break]";
        follow the source code generation rule;
        say "[text of the file of Output]";


    Glimmr Canvas Editor ends here.


    ---- DOCUMENTATION ----

    Glimmr Canvas Editor (GCE) is not a standard extension. It is a self-contained project, complete with multimedia assets, that generates a GUI editor for building canvas-based compositions. The user may include a list of figures, but at minimum one need include only the extension itself. If a list of figures is included, those figures will be available to use as sprites within the editor. We can also specify various settings and, within limits, add our own code (see below).

    Glimmr Canvas Editor depends on a rather large set of extensions. These include:

        Glimmr Canvas-Based Drawing
        Glimmr Drawing Commands
        Glimmr Bitmap Font (another bitmap font extension can be substituted)
        Glimmr Image Font (another image font extension can be substituted)
        Glimmr Graphics Hyperlinks
        Dynamic Objects
        Questions
        Fixed Point Maths
        Undo Output Control
        Glulx Text Effects
        (and also some built-in extensions)

    Note that GCE also requires you to download and place in your Materials/Figures/ folder a rather large set of image assets. These assets provide the editor's graphical user interface, as well as the glyphs for the Glimmr Image Font extension. If you don't have these images in the proper place, the extension will not be usable.

    GCE generates source code for use with the Glimmr Canvas-Based Drawing extension. Note that the bitmap and image-map element types cannot be created using GCE.


    Chapter: Including Glimmr Canvas Editor in a project

    GCE includes all of the other Glimmr extensions you will need, so usually you will need to include only GCE:

        Include Glimmr Canvas Editor by Erik Temple.

    This inclusion should be the first line after the project's title.


    Chapter: Overview

    A project built on Glimmr Canvas Editor opens with a short description and a few questions about the canvas that is being edited, as well as the name of the window in which it will be displayed. If you are not yet familiar with Glimmr canvases, please see the documentation for Glimmr Canvas-Based Drawing. Once these questions are answered, the screen clears and the graphical user interface for the canvas editor opens. This is where you will place, draw, and resize graphic elements to build your composition. You can also record different instances of movable or changeable elements.

    The GUI operates alongside the standard IF command line interface, and most commands can be entered using either the buttons in the interface, or with typed commands. When a button is pressed, the command is also printed at the command line, making it easy to learn the typed commands if you wish to.

    When you have completed the composition, hit the generate source code button to write an external file with valid I7 source code that replicates your design.


    Section: A note on the documentation

    Glimmr Canvas Editor has a graphical user interface that it is hoped will make it more easily approachable than a largely text-based command interface would be, at least for users who are familiar with Glimmr canvas-based drawing. This documentation will not cover most of the commands available in GCE in detail, with the understanding that the user will be able to explore the GCE GUI to discover commands.

    Instead, the documentation will, after providing a general introduction to the user interface, focus on elements of the editor that may be obscure or non-obvious. A later chapter details the customization options available for GCE projects.


    Chapter: Glimmr Canvas Editor


    Section: Introductory questionnaire

    When a GCE project opens, the user is presented with a set of three questions about the canvas to be built. This questionnaire can be skipped by typing SKIP at any of the prompts, and all of the parameters set by the answers can also be set by commands within the editor.

    The first question requests the name of the canvas (e.g., "graphics-canvas" or "my canvas"). This is used solely in the output source code. To change the name of the canvas from within the editor:

        RENAME CANVAS <new name>

    The default is "graphics-canvas," and this will be the name of the canvas if the question is SKIPped.

    The next two questions ask for the width of the canvas and the height of the canvas. If the provided dimensions define a portrait orientation (that is, the height is greater than the width), the editor will open with the windows configured to provide a full landscape view. If instead a landscape orientation (width greater than height) is defined, the windows will be arranged to allow a landscape view. If SKIPped, the default values will produce a landscape orientation. To change the dimensions of the canvas from within the editor:

        RESIZE CANVAS TO <width> BY <height>
            or
        CANVAS WIDTH <number>
        CANVAS HEIGHT <number>

    If we have changed from a portrait to landscape canvas orientation or vice versa, we can type

        REBUILD WINDOWS

    to rearrange the editor windows to better accomodate the new orientation.

    After the three questions have been answered, press any key to proceed to the editor proper.


    Section: Editor window

    The editor window is the centerpiece of the editor, where the canvas and its elements will be built up and edited. Initially, it shows only the outline of the canvas. Elements can be placed anywhere on the screen, but only elements that appear within the bounds of the canvas are guaranteed to appear in the display.

    There are three main modes for working with the editor window. These three modes are defined by the three main tabs in the control panel window (see below). They are: Moving, Selecting, and Scaling:

        Moving - When the editor is in Move mode, a click in the editor window will move any selected elements to the position indicated. If no elements are selected, clicking on an element will select it.

        Selecting - When the editor is in Select mode, clicking on any unselected element will select that element; click on multiple unselected elements in succession to select them all. Clicking on a selected element will deselect it. Clicking in the empty space between elements will deselect all elements.

        Scaling - When the editor is in Scale mode, a click in the editor window will attempt to scale the selected element. (If no elements are selected, clicking on an element will select it.) Elements can be scaled symmetrically (i.e., retaining the aspect ratio) or asymmetrically. To scale an element, click to the right and down from origin (the upper left corner) of the element to indicate where the lower right corner of the element should be. A box will appear around the element to indicate the new size and, if scaling asymmetrically, the new shape of the element. If scaling symmetrically, only the width input will be considered; a new height will be calculated for the element based on the aspect ratio. In this case, the box (ideal) will not coincide with the shape of the resized element (actual). Note that only image-based elements (sprites and image-rendered strings) can be scaled using the GUI.

    The editor window is also used for drawing elements. Elements can be drawn to the window while in any of these three modes. See the section on the drawing panel for details.


        --- Canvas scaling and zoom ---

    GCE will function regardless of whether there is room in the window to display the full canvas without scaling; if need be, the canvas will be scaled to fit in the window. When the canvas has been scaled down to fit the window, the ZOOM command becomes available. ZOOM toggles back and forth between 100% (unscaled) and the scaled view. Zoom is also enabled by oversize scaling.

    Zoom can be invoked either by typing ZOOM or by clicking on the magnifying glass icon in the control panel (located beneath the tab area); the icon appears only when zoom is available. If an element is selected, the zoomed view will be centered on that element. If no element is selected, zoomed view will be centered on the center of the canvas.

    Information on the canvas and the scaling ratio can be got by typing INFO or by clicking on the info icon I underneath the tab area in the control panel window.


        --- Hiding and deleting elements ---

    Elements in the editor window can be hidden as needed. This may be useful when elements overlap. To hide elements, select the desired elements and either:

        Type HIDE
            or
        Click Control panel -> Select tab -> Hide

    Hidden elements remain associated with the canvas and will appear in the source code output. To remove an element completely, DELETE it.

    To reveal hidden elements, type SHOW or click Control panel -> Select tab -> Show. A menu will appear listing the hidden elements. Type the number corresponding to the hidden element to reveal it.

    All hidden elements can be revealed at once by typing SHOW ALL (Control panel -> Select tab -> Show All).


        --- Background image ---

    The canvas can be defined by using a background image. To do this, be sure the image you want to use as a background is included in the project (see the chapter on Setting up a GCE project below). From the image library (see below for more on the image library), select the image you want to use. It will appear in the center of the canvas. The image should be selected. If it isn't, select it and then either:

        Type MAKE BACKGROUND
            or
        Click Control panel -> Settings -> Make Background Image

    To remove the background, type REMOVE BACKGROUND or click the Remove Background Image button.

    Setting a background image will change the dimensions of the canvas to match those of the image. After having set the background image, we can adjust the dimensions manually (see the Introductory Questionnaire section above for instructions on resizing the canvas from within the editor). If we do manually resize the canvas while it has a background image, there are two potential outcomes depending on whether we have allowed oversize scaling in the editor window:

        * with oversize scaling: the background image will be stretched to fit the canvas dimensions

        * without oversize scaling: the background image will remain unscaled in the upper left corner of the canvas

    To toggle oversize scaling, use the typed command:
        
        TOGGLE OVERSIZE SCALING
            or
        OVERSIZE

    Note that, when oversize scaling is on, the default view of the editor window may be scaled to greater than 100%, depending on the size of the window. Typing ZOOM will toggle between 100% and oversized scaling.


    Section: Control panel

    The control panel is located below left (landscape orientation) or below right (portrait orientation) of the editor window. It includes most of the buttons used to issue commands to the editor.

    There are three main parts to the control panel:

        Tab Area - The tab area is the central portion of the control panel. There are three tabs, each associated with one of the three main editor modes: moving, selecting, and scaling. (See the editor window section above for more on editing modes.)

        Pop-Up Menus - There are three buttons that open pop-up menus. These are located along the right side of the tab area. They are, from top to bottom, the Settings menu (gear icon), Source Code menu (document icon), and Tools menu (wrench icon).

        Control Buttons - These buttons are found below the tab area, on the left side. These buttons are divided into two groups. The group on the left affect elements, while the buttons on the right affect the user interface.

    Quick descriptions of these controls follow:


        --- Tab Area ---

    When a tab is selected in the control panel, the editor window will respond according to the behavior for the selected mode. In other words, when the Move tab is selected, clicking in the window will move selected elements around. While the Select tab is active, clicking in the editor window selects and deselects elements.

    Different controls are shown in each of the tabs. Under the Move tab, there are four buttons for nudging an element (or elements) a certain number of pixels (canvas units) in any direction. Set the nudge amount using the button alongside the Nudge controls. There are also four buttons that allow an element to be Aligned with one edge of another element, and a button that will Center one element on another.

    Under the Select tab, we can not only select elements based on certain attributes (such as kind or the display-layer) and hide or reveal them, we can also add a "graphlink" to an element. Graphlinks are "graphic hyperlinks", allowing that the element will respond to mouse input. When a graphlink is added to an element, GCE will ask you to provide a replacement command--this command will be issued on behalf of the player when she clicks on the element. There are also settings in the Select tab for the styling of hyperlinks.

    The Scale tab provides controls for making scaling Symmetrical or Asymmetrical, and for scaling numerically rather than by resizing the element visually in the editor window. We can also set the default scaling factor (usually 1.0000, that is, 100%). All new elements created will be scaled by this amount (note that this will affect the size of image-based elements only; rectangle-based elements will see their line weight changed by the scaling, nothing else).


        --- Pop-Up Menus ---

    The button with the gear icon brings up the Settings menu, where we can set or remove the background image for the canvas, if desired, or toggle the outline that indicates the boundaries of the canvas in the editor window (the canvas outline is not included in the output source--it is strictly a part of the GCE user interface). There is also a button to list the available color names (see section on Customizing Colors below). These color names can be used in a number of text-only commands to change both UI and elements colors; the LIST COLORS button/command provides a list of these.

    The next icon, a page or document, represents the button for the Source Code menu. Here, source code can be generated--that is, written to an external file--or previewed within the editor itself. If written to an external file, that file will be called "GlimmrSource". Your interpreter may or may not append a file extension, but the file is a plain text file. Interpreters will also vary in where they save the file: some will save it to the same file as the project's gblorb, but others will save it to your home folder, or even to the root of your hard drive.

    Source code can be produced in two styles, tabular or paragraphed. In tabular style, elements are defined using tables, a more succinct method that is generally to be preferred. In paragraphed style, each element is defined in its own paragraph of source code.

    The final button, with an icon of a wrench, opens the Tools menu. In this menu, there are controls for renaming elements, adding or changing the sub-kind of the element, tagging elements, and instancing elements. See the Advanced Topics below for more on kinds & sub-kinds, tags, and instances.


        --- Control Buttons ---

    The two buttons in the left-hand groups act on elements. The X button deletes the selected element(s), while the I button provides information about them. (When pressed without elements selected, the I button will display information about the canvas.)

    The right-hand group are user interface buttons. The pencil button toggles the drawing toolbar (see below). The magnifying glass button, which appears only when zoom is available, toggles the zoom state. See the Canvas Scaling and Zoom section under the editor window above for more information about zooming.


    Section: Drawing toolbar

    The drawing controls are located at the bottom of the editor window. They can be removed if desired by clicking on the X on the right edge of the drawing controls toolbar, or by clicking on the drawing icon (a pencil) beneath the tab area in the control panel window. The drawing icon will also restore the toolbar if it has been removed.

    The drawing controls allow for drawing any of four types of primitive (line, rectangle, box, and stroked rectangle), or for painting bitmap-based and image-based text strings. Click on the appropriate button and follow the onscreen instructions to create a drawing object.

    The drawing toolbar also allows us to set the foreground and background colors for a drawn object (in the language of Canvas-Based Drawing, these are the "tint" and "background tint" properties). To set the color for an object, select the object and click on the square next to the color you wish to change. A selection of color chips appears; click to select the color. The red slash indicates no color. Element colors can also be changed using typed commands, if you know the color name:

        CHANGE ELEMENT FOREGROUND COLOR TO <color name>
        CHANGE ELEMENT BACKGROUND COLOR TO <color name>

    Note that the background color only affects the stroked rectangle (it specifies the color of the stroke) and the text elements. The foreground color affects all drawn elements except the image-based string, the color of which is provided by the images that make it up.

    The drawing toolbar also allows for changing the weight of the line used to draw the line, box, and stroked rectangle primitives, as well as the bitmap-based text string. Click on the button to set the line weight.

    Finally, for text strings we can set the alignment: left-aligned (the default), center-aligned, or right-aligned. Click on the appropriate icon to set the alignment.


    Section: Text input window

    The text input window acts as a log of actions that have been performed, and can also be used as a command-line alternative to the control panel and drawing controls. (The SCRIPT ON command can be used to produce a more permanent log, if desired.) Nearly all commands can be entered at the command line rather than using the GUI. The exceptions are (1) the GUI selection, movement, and scaling commands, as described under the editor window section, and (2) creation of a new sprite from the image library, which requires clicking on the image in the library.


        --- Commands with no GUI counterpart ---

    There are also a few commands that have no counterpart in the GUI. Here is the list of such commands:

        UNDO
        SAVE
        RESTORE
        RENAME CANVAS <text>
        RESIZE CANVAS TO <width> BY <height>
        CANVAS WIDTH <number>
        CANVAS HEIGHT <number>
        REBUILD WINDOWS
        TOGGLE OVERSIZE SCALING
        CHANGE STROKE HIGHLIGHT COLOR TO <color name>
        CHANGE CANVAS BACKGROUND COLOR TO <color name>
        CHANGE CANVAS OUTLINE COLOR TO <color name>
        CHANGE ELEMENT FOREGROUND COLOR TO <color name>
        CHANGE ELEMENT BACKGROUND COLOR TO <color name>

    These are discussed in various places through the course of this documentation.


        --- Command abbreviations ---

    Some of the more common operations have radically shortened forms for quick entry into the text input window. Here is a list:

        M - MOVE MODE
        S - SELECT MODE
        X - SCALE MODE

        A - SELECT ALL
        D - DESELECT ALL

        DEL - delete selected element

        I - INFO

        Z - ZOOM

        L <number> (when an element is selected) - place element on the given display-layer
        L <number> (when nothing is selected) - change current layer to number given

        C - duplicate selected element

        R <reference name> - register an element instance with the reference name provided

        T <reference name> - tag selected element with reference name provided

        G - repeat last command
        

    Section: Status line

    The status line appears immediately above the text input window, as in your standard IF layout. Its function in GCE is to display basic information about the selected elements. On the left hand side, the name of the element is given, while the right side indicates the origin coordinates. The central part of the status line indicates the kind of the element and, if a sub-kind has been defined, this is also indicated. (See below for information on sub-kinds.)

    When no elements are selected, the central part of the status line displays the canvas dimensions, and the right-hand part gives the scaling ratio (as a percentage to economize on space).

    All of the information in the status line and more can be accessed by typing INFO or by clicking on the info icon I underneath the tab area in the control panel window.


    Section: Layers window

    The layers window is a narrow vertical window on the left side of the editor screen. The layers window presents a visual representation of the canvas's display-layers. The display-layer of a graphic element represents its z-coordinate: an element on layer 2 will be drawn after--and appear "on top of" an element drawn on layer 1.

    GCE makes available 24 display-layers. The layers window displays as many of these as are actually in use, starting from the bottom of the window and moving up as new layers are assigned. Each layer is shown as a sphere. When there is at least one selected element on a layer, a blue dot will appear at the center of the sphere.

    One of the active display-layers will be identified as the "current display-layer". This is the layer on which new elements will be created (whether using the drawing tools or by selecting an image from the image library). The current display-layer is indicated in the layers window by a gray shadow behind the layer's spherical indicator. To designate a layer as the current layer, click on that layer's sphere.

    At the top of the layers window is an icon in the form of an eye. This button toggles "layer reveal mode." When activated, layers reveal mode places a badge in the upper left corner of each element in the editor window. The number on the badge indicates that element's display-layer.

    To move elements between layers, select multiple elements and either:

        type MOVE TO LAYER <number>
        type LAYER <number>
        type L <number>
            or
        press the Move to Layer button under the Move tab

    To change the current layer using a typed command rather than clicking as described above:

        DEFAULT LAYER <number>


    Section: Image library window

    The image library will only appear if the project includes custom images (see below). The image library displays a grid of all of the available custom images. If there are more images available than will fit in the window, multiple "pages" will be generated; move between these pages by clicking on the arrows that will appear (as needed) in the window header.

    Clicking on an image in the library will create a new sprite element in the editor window using that image. We can create as many sprites as we like from a single image. The new sprite will be created on the current display-layer (see the Layers Window section above), and will be named after the figure that spawned it. For example, if we have an image in the library that was defined as Figure of Bird, the second sprite created from it would be called "Bird_2". Use the Rename command to change the name as desired:

        RENAME <new name>
            or
        click Control panel > Tools pop-up menu -> Rename element


        --- Reassigning a sprite's identity ---

    The image associated with a sprite element is known as the sprite's image identity, or "image-ID". The image-ID, like any other property, can be changed during the course of a story, and it can also be changed in GCE. This is most likely to be useful when combined with instancing (see below): we may want a sprite to represent multiple images over the course of our game, perhaps in tandem with moving the element, scaling it differently, changing the associated graphlink command, etc. Any or all of these can done with instances. Use one of the following commands:

        REASSIGN IMAGE-ID
            or
        REASSIGN SPRITE IDENTITY
            or
        Control panel -> Tools menu -> Change Identity button


    Chapter: Advanced topics

    Section: Kinds and Sub-kinds

    All elements added to the canvas in GCE are members of one of the following hierarchy of kinds:

        object -> thing -> g-element -> sprite
        object -> thing -> g-element -> primitive -> (rectangle, box, line, stroked rectangle)
        object -> thing -> g-element -> rendered string -> (image-rendered string, bitmap-rendered string)

    When an element is selected, the status line identifies the most specific kind in the hierarchy of the element, such as sprite, rectangle primitive, or bitmap-rendered string.

    GCE allows us to add one additional layer to the hierarchy for any element. For example, we may want to make subsets of the sprite class:

        object -> thing -> g-element -> sprite -> room-sprite
        object -> thing -> g-element -> sprite -> person-sprite

    Now we have two sub-kinds--room-sprite and person-sprite--that serve to distinguish sprites representing rooms from sprites representing people. This kind of division, which we will call the "sub-kind" for brevity's sake, is quite useful. We can, for example, write rules referring to the sub-kinds to treat different types differently, e.g.:

        Carry out exploding the atom bomb:
            repeat with vaporized running through person-sprites:
                deactivate vaporized.

    When the selected element has a sub-kind, the status line will show both the sub-kind and the parent kind, e.g. "sprite -> room-sprite". In the output source code, sub-kinds are defined separately from other sub-kinds and from their parent kinds:

        A room-sprite is a kind of sprite. The graphlink status of a room-sprite is g-inactive. The associated canvas of a room-sprite is graphics-canvas.

        Orthogonal_room_hexagonal_1 is a room-sprite. The image-ID is ...

    Only one level of sub-kind can be defined for an element within GCE. We couldn't, for example, add a second level within room-sprites. This is an arbitrary limit--selected to keep things as simple as possible--and any number of levels can be edited into the output source code if we wish.

    To add a sub-kind to an element or group of elements:

        1) Select the element(s) to be subclassed.
        2) Choose Control panel -> Tools menu -> Change Kind, or type KIND.
        3) When prompted, type the name of the sub-kind, e.g. "room-sprite".

    Steps 2 and 3 can be combined by typing KIND <name>, e.g. "KIND ROOM-SPRITE".

    Once a sub-kind has been assigned, it cannot be rescinded, though the name can be changed following the same steps.


    Section: Tags

    GCE allows us to assign a "tag" to any element. The tag is just arbitrary text, but it will be treated as a property of the element in output source code. Effectively, then, the tag allows us to add a custom property to elements and specify its value within the editor. For example, the example code below adds a tag to each sprite element that is translated in the source code as the "associated room" of the element. To activate all of the sprites associated with a given room simultaneously, we can use this property like so:

        This is the update map sprites rule:
             repeat with current-element running through display-inactive room-elements:
                 if the associated room of current-element is the location:
                     activate current-element.

    To apply a tag to an element, type TAG or select Control panel -> Tools menu -> Tag, and enter the tag text when prompted. A shorter form is simply to type TAG <name>, e.g. "TAG LOUNGE" to tag the element with "LOUNGE".

    To delete the tag from an element, type DELETE TAG or select Control panel -> Tools menu -> Delete Tag.

    Tags must be properly set up from within the source code of the GCE story file to function as expected. See the section on setting up tags below.


    Section: Instances

    One of the main reasons for the existence of Glimmr is to enable authors to create *dynamic* on-screen compositions using multiple discrete elements. GCE introduces the notion of "element instances" to make it possible to mark different values for attributes for the same element, such as different origin coordinates, scaling factors, and so on.

    Element instances are not visible in the editor. Instead, when an instance is registered, all of its major properties are saved, with a particular instance name (the "reference") provided by the user. Here, for example, is a short list of instances for the sprite "Player Avatar":

        sprite reference origin image-ID display-layer scaling factor linked replacement-command
        Player Avatar Large Room {149, 162} Figure of Player Icon Alternate 2 1.0000 ""
        Player Avatar Round Room {233, 263} Figure of Player Icon Alternate 2 1.0000 ""
        Player Avatar Rough Room {285, 227} Figure of Player Icon Alternate 2 1.0000 ""

    Player Avatar is a sprite that represents the location of the player character in an onscreen map. Each instance was registered with the icon overlaid on a different room's sprite representation, and the room names were used for the instances' reference names. Notice how the origin coordinates change along with the room names.

    Because there are many different ways in which this information about element dynamics could be used, it is provided as a simple table of attributes (commented out) rather than as compilable source code. The table data may be copied and pasted into Excel, Numbers, or Google Spreadsheets to easily select and manipulate the attribute information as needed.

    To register an instance, select the element you want to register and type REGISTER, or just R. You will be asked to input a reference ID for the instance. This can be a name (like the room names in the example above), a number, or whatever you like. This can also be done in one command, by typing REGISTER <reference> or R <reference>, e.g.:

        REGISTER ROUND ROOM
        R ROUND ROOM

    To see the list of instances recorded for an element, select that element and type INSTANCES.

    To delete an instance, select the element and type DELETE INSTANCE. A menu appears, listing all of the instances of the selected element. Enter the number of the instance you wish to delete and press return. Once deleted, an instance cannot be restored, though instance deletion can be UNDOne.

    It is possible to create a new element from any instance. To do so, select the instanced element and type LOAD INSTANCE. A list of available instances is presented, and you are asked to type the number of the desired instance. Once you enter that number, a new element will appear that has all of the properties of the selected instance. Note that this is a new element, one with no instances, and that the old element--and the instance that spawned the new element--remain intact.

    When an element is destroyed, all of the instances of that element are also destroyed.


    Chapter: Setting up a GCE project

    Minimally, all that is required to create a GCE project is the line "Include Glimmr Canvas Editor..." in an otherwise empty Inform project (with all of the required image assets must be in the project's Materials>Figures folder). This will serve to allow the user to draw basic shapes and text strings in a handful of colors.

    Most users, however, will want a bit more to work with, and the following sections explore some of the customizations that are possible.

    Section: Working with image files

    The most commonly used elements in GCE are anticipated to be sprites (that is, image files). To include some image files that you'd like to work with, declare a list of figures as you would for any other I7 project. For example:

        Include Glimmr Canvas Editor by Erik Temple.

        Figure of Orthogonal Room Square is the file "Orthogonal Room Square.png".
        Figure of Orthogonal Room Horizontal is the file "Orthogonal Room Horizontal.png".
        (and so on...)

    (These images come from the package of floor plan images that I've included with GCE. The example code below uses these images.)

    Figures must be declared *after* the inclusion of the extension or problems with result.

    The images you've declared here will appear in the "Image Library" window on the right side of the editor when you compile your project. You can click on an image to add a sprite based on that image to the canvas.

    GCE projects can be distributed as compiled graphic toolkits, with a selection of images that work well together for a given purpose. The example provided


    Section: Setting canvas parameters

    When a GCE project is first run, the user is asked to answer a short questionnaire to define the basic parameters of the canvas. If we want to avoid this, we can set these parameters directly. The canvas for the editor is called the "editor-canvas", and we can set the canvas dimensions directly:

        The canvas-width of the editor-canvas is 600.
        The canvas-height of the editor-canvas is 450.

    We can also set the name of the g-window that the source code will produce:

        The targeted canvas is "graphics-canvas".

    We can also set the window's background color from the source code--see the following section on colors.


    Section: Customizing colors

    Colors in Glimmr are used primarily for the backgrounds of windows, and for the colors of drawn elements such as rectangles, lines, and text elements. There are also a couple of UI elements within GCE that can be set using glulx color values. GCE and Glimmr Canvas-Based Drawing--which is the extension that GCE compiles its code to work with--use "glulx color values" to specify colors. The glulx color value type is defined in Emily Short's Glulx Text Effects extension, and it provides a color name to stand in for far less grok-able color numbers that Glulx understands. By convention, glulx color values are written as a single (run-together) word prefaced with "g-".

    All glulx color values must be specified in advance (that is, before the project is compiled). A few colors are already available by virtue of the extensions included in GCE (see the list below). If you want to use others, you will need to add them yourself.

    To add colors to GCE, we must first declare the colors. This is done by extending the Table of Common Color Values (see Glulx Text Effects for more on this), for example:

        Table of Common Color Values (continued)
        glulx color value assigned number
        g-AliceBlue 15792383
        g-AntiqueWhite 16444375
        g-Aqua 65535
        g-Aquamarine 8388564

    Once the colors have been declared, we can define how they are to be used. The most important to do in the source code of our project--since it cannot be done from within the compiled editor--is the list of drawing colors. These are the colors that are will appear as color chips in the drawing panel; for space reasons we should not choose more than perhaps 25 of them. To define the drawing colors, insert something like this in your source code:

        The drawing colors are { g-Black, g-White, g-Red, g-Orange, g-Yellow, g-Green, g-Blue, g-Indigo, g-Violet}.

    Note that any glulx color value can be used for drawing, but only those in the drawing list will appear as color chips in the GUI. To access other colors, we need to use textual commands.

    If desired, we can also specify the initial foreground and background colors (these are the colors that the drawing tools will be initialized with):

        The current element color is g-White.
        The current element background color is g-Black.

    To set the background color of the main editor window, which will also be reflected in the source code output by GCE:

        The back-colour of the editor-window is g-Indigo.

    Finally, there are two user interface colors that we can change as desired. These are the stroke highlight color (the color used to draw a stroke highlight surrounding a selected element) and the canvas outline color, used to mark the boundaries of the canvas. To change these in the source code of our project:

        The highlight-color is g-CornflowerBlue.
        The canvas outline-color is g-Yellow.


    Section: Setting editor defaults

    A few other options are available, some of which can also be changed while the editor is running.

    Two settings which cannot be changed in the editor are the scaling limits. These numbers indicate minimum and maximum acceptable scaling factors--how big or small we can scale an element.

        The lower scaling-limit is 0.1000.
        The upper scaling-limit is 2.0000.

    We can also set the number of canvas units that each press of a nudge button will move the selected elements:

        The nudge factor is 1.

    This setting can also be changed from within the editor, as can the default scaling factor for elements, which we can also set from our project's source code:

        The default scaling factor is 1.0000.


    Section: Setting up tags

    It is not necessary to set up tags, but it is the only way to specify in advance what you want to use them for. This saves you a little work in tweaking the output source code. There are generally just two parameters to be set.

    All tags in a GCE project will represent the same thing--a property of a g-element. For example, we might want to associate elements with game locations via a property of the room type--this element is assigned to this room, e.g.:

        A g-element has a room called the associated room.

    To accomplish this, we identify the name of this property using the "tag alias":

        The tag alias is "associated room".

    The "tag type" identifies the Inform 7 named type of the property:

        The tag type is "room".

    Now all of our tags will be written into the source code as if they were properties containing a room.

    Note: If we do not set up our tags before running GCE, the output source code will use "text" for the tag type and "tag" for the tag alias, giving us:

        A g-element has a text called the tag.

    (There is a third parameter, the "tag-surround," which is intended to provide a single character to be printed on either side of a tag's value in the output source code. For text or indexed text tags, this is automatically set to the quotation mark. It probably has no other use.)


    Section: Customized instructions

    It is possible to provide customized text at the startup of a project built with GCE. This is intended primarily for toolkits--like the Basic Floorplan toolkit, the code for which is presented as the example below--that are distributed as compiled builds. This text is called the "user-specified startup text", and will be printed after the initial paragraph that begins "Welcome to the Glimmr Canvas Editor". To add this text:

        The user-specified startup text is "This is my custom UI creation toolkit. Enjoy!".

    To *replace* the standard introductory text rather than add to it, we can change the "startup text" and "startup instructions text variables". See the source code of the extension for the default content of these variables.


    Section: Customized source code

    We may also specify our own text to be output as source code from GCE. This is again intended for GCE toolkits, precompiled builds of GCE that include images and so on that might be useful across a range of projects. To inject our own source text, we set the "user-specified source text" variable. See the example toolkit code below.


    Section: Using alternate fonts

    Glimmr Canvas Editor requires exactly one bitmap font and one image font to work. By default, these are the fonts available in the Glimmr Bitmap Font and Glimmr Image Font extensions. However, you may change the fonts by replacing the Fonts chapter section of the GCE extension. Here is an example:

        Chapter - My Fonts (replaces Chapter - Fonts in Glimmr Canvas Editor by Erik Temple)

        Include Bubble Blob Bitmap Font by Erik Temple.
        Include Gloopy Glop Image Font by Erik Temple.

        To decide what text is the extension-name of (typeface - a font):
            if the typeface is Gloop Glop:
                decide on "Gloopy Glop Image Font by Erik Temple";
            if the typeface is Bubble Blob:
                decide on "Bubble Blob Bitmap Font by Erik Temple";
            decide on "".
        
        The associated font of a bitmap-rendered string is usually Bubble Blob.
        The associated font of an image-rendered string is usually Gloopy Glop.

    First, include your font extensions. Then, provide a decide phrase like that given here, so that the source code generator will know what to write (Inform cannot directly access the names of extensions). Finally, set the "associated font name" of your font(s) to the appropriate value.

    For information on how to create your own fonts for use with Glimmr, see the documentation for Glimmr Drawing Commands.


    Chapter: Performance

    GCE should be run on relatively modern hardware, using the newest available interpreters; a number of interpreters have had bug fixes and preformance enhancements in recent months and will run this and other Glimmr game files much better.

    Glimmr Canvas Editor functions much better in a release build, opened with an external interpreter, than it does when run from within the Inform IDE. Running it in the IDE is not to be recommended in any case, since the window should be maximized to the fullest extent possible.

    Note that, in the Mac IDE, there is a *significant* delay upon entering the editor. During this delay, commands can be entered, but clicks in the GUI will appear to do nothing. These clicks are in fact being registered, however, and will generate actions after the delay is complete. It is best to make a single click when the editor loads, then wait for that click's result to appear before continuing.


    Chapter: Debugging

    At present, no debugging features are associated with Glimmr Canvas Editor, and the extension makes no output to the Glimmr debugging log.


    Chapter: Contact info

    If you have comments about the extension, please feel free to contact me directly at ek.temple@gmail.com.

    Please report bugs on the Google Code project page, at http://code.google.com/p/glimmr-i7x/issues/list.

    For questions about Glimmr, please consider posting to either the rec.arts.int-fiction newsgroup or at the intfiction forum (http://www.intfiction.org/forum/). This allows questions to be public, where the answers can also benefit others. If you prefer not to use either of these forums, please contact me directly via email (ek.temple@gmail.com).


    Example: *** Basic Floorplan Toolkit Example - A toolkit including images for use in constructing basic floorplans for indoor maps, as well as illustrating most of the basic options available. Also illustrates user-specified source text and tags to create automatic mapping capabilities. This example is a bit different from the released Basic Floorplan Toolkit gblorb file, in that it contains a small map to be used as reference while you draw. Type MAP to see the geography.

    Most of the available settings are included in the code, many just restating the defaults.


        "Basic Floorplan Toolkit Example"

        Include Glimmr Canvas Editor by Erik Temple.

        Figure of Orthogonal Room Square is the file "Orthogonal Room Square.png".
        Figure of Orthogonal Room Horizontal is the file "Orthogonal Room Horizontal.png".
        Figure of Orthogonal Room Vertical is the file "Orthogonal Room Vertical.png".
        Figure of Orthogonal Room Round is the file "Orthogonal Room Round.png".
        Figure of Orthogonal Room Hexagonal is the file "Orthogonal Room Hexagonal.png".
        Figure of Orthogonal Hall Horizontal is the file "Orthogonal Hall Horizontal.png".
        Figure of Orthogonal Hall Vertical is the file "Orthogonal Hall Vertical.png".
        Figure of Orthogonal Hall NW to SE is the file "Orthogonal Hall NW to SE.png".
        Figure of Orthogonal Hall SW to NE is the file "Orthogonal Hall SW to NE.png".
        Figure of Orthogonal Long Hall NW to SE is the file "Orthogonal Long Hall NW to SE.png".
        Figure of Orthogonal Long Hall SW to NE is the file "Orthogonal Long Hall SW to NE.png".
        Figure of Orthogonal Curve N to E is the file "Orthogonal Curve N to E.png".
        Figure of Orthogonal Curve S to E is the file "Orthogonal Curve S to E.png".
        Figure of Orthogonal Curve W to N is the file "Orthogonal Curve W to N.png".
        Figure of Orthogonal Curve W to S is the file "Orthogonal Curve W to S.png".
        Figure of Rough Room Square 01 is the file "Rough Room Square 01.png".
        Figure of Rough Room Square 02 is the file "Rough Room Square 02.png".
        Figure of Rough Room Horizontal is the file "Rough Room Horizontal.png".
        Figure of Rough Room Vertical is the file "Rough Room Vertical.png".
        Figure of Rough Room Circular is the file "Rough Room Circular.png".
        Figure of Rough Hall Horizontal is the file "Rough Hall Horizontal.png".
        Figure of Rough Hall Vertical is the file "Rough Hall Vertical.png".
        Figure of Rough Hall NW to SE is the file "Rough Hall NW to SE.png".
        Figure of Rough Hall SW to NE is the file "Rough Hall SW to NE.png".
        Figure of Rough Long Hall Horizontal is the file "Rough Long Hall Horizontal.png".
        Figure of Rough Long Hall Vertical is the file "Rough Long Hall Vertical.png".
        Figure of Rough Long Hall NW to SE is the file "Rough Long Hall NW to SE.png".
        Figure of Rough Long Hall SW to NE is the file "Rough Long Hall SW to NE.png".
        Figure of Rough Curve N to E is the file "Rough Curve N to E.png".
        Figure of Rough Curve S to E is the file "Rough Curve S to E.png".
        Figure of Rough Curve W to N is the file "Rough Curve W to N.png".
        Figure of Rough Curve W to S is the file "Rough Curve W to S.png".
        Figure of Door Horizontal is the file "Door Horizontal.png".
        Figure of Door NE to SW is the file "Door NE to SW.png".
        Figure of Door NW to SE is the file "Door NW to SE.png".
        Figure of Door Vertical is the file "Door Vertical.png".
        Figure of Stair Circular is the file "Stair Circular.png".
        Figure of Stair Horizontal is the file "Stair Horizontal.png".
        Figure of Stair Vertical is the file "Stair Vertical.png".
        Figure of Occluder Square is the file "Occluder Square.png".
        Figure of Player Icon is the file "Player Icon.png".
        Figure of Player Icon Alternate is the file "Player Icon2.png".

        The targeted canvas is "graphics-canvas".

        The canvas-width of the editor-canvas is 600.
        The canvas-height of the editor-canvas is 450.

        The back-colour of the editor-window is g-Black.

        The highlight-color is g-CornflowerBlue.
        The canvas outline-color is g-White.

        The nudge factor is 1.

        The lower scaling-limit is 0.1000.
        The upper scaling-limit is 2.0000.

        The default scaling factor is 1.0000.

        Table of Common Color Values (continued)
        glulx color value assigned number
        g-Orange 16753920
        g-Violet 15631086


        The drawing colors are {
        g-Black,
        g-White,
        g-Red,
        g-Orange,
        g-Yellow,
        g-Green,
        g-Blue,
        g-Indigo,
        g-Violet,
        g-Dark-Grey,
        g-Medium-Grey,
        g-Light-Grey
        }.

        The current element color is g-White.
        The current element background color is g-placeNULLcol.


        Section - Custom text and source

        The tag type is "room".
        The tag alias is "associated room".

        The user-specified startup text is "This is a special edition of Glimmr Canvas Editor optimized for the creation of a map for a specific scenario. You may type MAP at any time after this screen to see a list of the rooms and connections that have been defined for this scenario. TAG elements with a room name to indicate which elements should be revealed when that room is entered for the first time.[paragraph break]".

        The user-specified source text is "Chapter - Associating rooms with elements[paragraph break][bracket]This code assumes that each sprite that forms the map has been given the kind [quotation mark]room-element[quotation mark] and that each has also been tagged with the name of the room that should trigger its display. It further assumes that there exists an element that represents the avatar of the player, given the name [quotation mark]PC avatar[quotation mark], and that there is a table called the Table of Avatar Coordinates that consists of a column of room names (the locale column) and a column of the coordinates for the avatar that correspond to the avatar. These columns can easily be extracted from the instances data, provided an instance of the avatar has been recorded in advance for each room.[close bracket][paragraph break]The update map sprites rule is listed in the carry out looking rules.[line break]This is the update map sprites rule:[line break][tab]repeat with current-element running through display-inactive room-elements:[line break][tab][tab]if the associated room of current-element is the location:[line break][tab][tab][tab]activate current-element;[line break][tab]if there is a locale of the location in the Table of Avatar Coordinates:[line break][tab][tab]choose row with a locale of the location in the Table of Avatar Coordinates;[line break][tab][tab]change the origin of the PC avatar to the coord entry;[line break][tab]follow the window-drawing rules for the graphics-window.[paragraph break]"


    If we are compiling this GCE project strictly for our own use, we may want to include the map geography itself in the project, as a reference for our drawing. To do that, we paste in the relevant code from our game:

        Section - Map

        Entrance Chamber is a room. The heavy door is an open door. It is south of Entrance Chamber and north of Hall. Guard Room is east of Hall. Up from Entrance Chamber is the Shaft. Watch Room is south of the Shaft. Up from Shaft is the Upper Chamber. Flanking Chamber is south of Upper Chamber. North of Flanking Chamber is nowhere. West of Flanking Chamber is Upper Chamber. East of Upper Chamber is nowhere.


    ...and, some new commands to summarize the map for us:

        Section - Map summary

        Listing rooms is an action applying to nothing. Understand "rooms" or "list rooms" or "map" as listing rooms.

        Carry out listing rooms:
            let L be the list of rooms;
            remove fake-room_x from L;
            if the number of entries of L > 0:
                say "The following rooms have been defined:[paragraph break]";
                repeat with current-room running through L:
                    say "[bold type][current-room][roman type][line break][list exits for current-room]";

        To say list exits for (R - a room):
            let begun be false;
            say " ";
            repeat with way running through directions:
                if the room way from R is a room:
                    say "[if begun is true]; [end if][italic type][if the door way from R is a door]door [end if][way][roman type] to [the room way from R][run paragraph on]";
                    let begun be true;
            say ".";