1. The Concept

The idea of this tutorial sprang from a forum question about automatically checking on the completion of key attributes in a writing project. To this has been added a rudimentary dashboard to help show how the data gathered from the process can be used to inform the writer. As well as the code to do the task, the tutorial covers in passing:

  • using prototypes to update many notes via one edit
  • using OnAdd actions to set correct prototypes
  • using naming prefixes for back-of-house notes to avoid duplicate note titles
  • using notes to store and edit longer sections of action code
  • using $Pattern to show progress data in Map view
  • using background agents to make reporting code shorter/simpler
  • using a map as a visual dashboard

The tutorial gives instructions to allow you to make the resulting demo from a blank new Tinderbox document. It may be you're starting out and this looks complex and you just want to play with the result, or you're just in a hurry. Either way, the TBX file created from writing this tutorial, along with a PDF version in this article can be downloaded. If you do jump straight to playing with the TBX, it is suggested you skim read this article so as to get an idea of what it does and why.

Colophon: the project was undertaken on OS 10.6.8 using Tinderbox v5.11.2. The tutorial is documented using Clarify.

2. Add the 'Code' prototype

2. Add the 'Code' prototype

Add the built-in prototype "Code", using the file menu.

3. Add a prototype for your Scene notes

3. Add a prototype for your Scene notes

Add a new prototype to the "Prototypes" container, called "pScene". The use of the 'p' prefix is a choice, but you don't have to do so (but amend code below if you choose a different name!). The point of a prefix is twofold: it reminds you of the note's purpose and stops the prototype name duplicating the name of a note you'll make in you main work.

4. Add User Attributes

4. Add User Attributes

Add eight user attributes. The first three are used in the reporting process. $CompleteCount, $CompleteState and LoopVar are all Number type attributes.

The remaining five attributes are, $MyBoolean a Boolean, $MyDate a Date, $MyNumber a Number, $MySet a Set and $MyString a String. The last few attributes are just specimen attributes to allow you to experiment and test the code you'll create .

5. Set Key Attributes for pScene

5. Set Key Attributes for pScene

Open pScene and set all 5 'My' prefixed attributes as key attributes. The code you go on to add will test whether these attributes are in their default state or not.

6. Rename

6. Rename

A a root level note below "Prototypes" (not inside it!). Give it the OnAdd code:

$Prototype="Code";

7. Add a note to Codes

7. Add a note to Codes

Add a child note to "Codes", with the name "cKA_Complete". The 'c' prefix reminds you it is a note holding code. Using underscores for spaces in the title is another simple way of reminding you this is a behind-the-scenes note.

8. Set a $Rule

8. Set a $Rule

Open the Rename dialog for "cKA_Complete" and enter the code:

$Rule("pScene)=$Text;

The result of this is that whatever code you write in this note's $Text automatically becomes the $Rule fo your Scene prototype. Update the text here and the other $Rule gets updated - as do those in all the notes using that prototype.

9. Add $Text to cKA_Complete

9. Add $Text to cKA_Complete

Add this code to $Text

$LoopVar=0;
$KeyAttributes.each(X) {
	if(eval("$"+X)) {
		$LoopVar = $LoopVar + 1;
	}
};
$CompleteCount = $LoopVar;
$CompleteState =($LoopVar/$KeyAttributes.size).format(2);
$Pattern="bar($CompleteState*100)";

Note the semi-colon after the last '}', you must not leave that out!

This code loops through each item in $KeyAttributes, turns the item into a reference to that attribute, i.e. "MyDate" -> "$MyDate", and then tests if it has a non-default value. A loop counter ,$LoopVar, is set to zero before the loop starts and for each attribute testing positive, it is incremented by one. At the end of the loop the current count is stored in $CompleteCount. Why do the latter? Were code elsewhere in the document to check $LoopVar during a loop the count might be incorrect. By comparison, $CompleteCount only changes, if at all, at the end of every loop. To make it easier for code elsewhere to use the completeness state as a percentage, $CompleteState is calculated from $CompleteCount.

10. Alternate code - Check Only Some Key Attributes

10. Alternate code - Check Only Some Key Attributes

Maybe you don't want to monitor all the key attributes for a scene but only some of them. In that case, add a new Set attribute $MandatoryAttributes, and populate it in pScene with the data from $KeyAttributes, removing from the list those attributes you don't wish to monitor.  Amend the code in $Text of "cKA_Complete" to this:

$LoopVar=0;
$MandatoryAttributes.each(X) {
	if(eval("$"+X)) {
		$LoopVar = $LoopVar + 1;
	}
};
$CompleteCount = $LoopVar;
$CompleteState =($LoopVar/$MandatoryAttributes.size).format(2);
$Pattern="bar($CompleteState*100)";

 

11. Add a Story container and per-scene notes

11. Add a Story container and per-scene notes

Add a root-level "Story"container.  If it's children will all be Scenes, consider using a OnAdd action to set the "pScene" prototype. Make two child notes "Scene 1" and "Scene 2" and give them the "pScene" prototype.

In "Scene 1", give a non-default value to 2 of the key attributes, e.g. tick the $MyBoolean's tick-box and set a date for $MyDate. For the other note, put a value in four of the attributes.

12. The scenes in Map view

12. The scenes in Map view

Select "Scene 1" and click Cmd+Opt+M to open a Map view. You will see something like above. Note how the $Pattern set in the $Rule results in a progress bar. The pattern uses $Color and $Color2. You can always customise these via the prototype to use colours with more contrast.

13. A sample Dashboard

13. A sample Dashboard

From the file menu, add the built-in "Dashboard" prototype and rename it to give it a 'p' prefix, "pDashboard". Why, because you're about to make a non-background note called Dashboard and you ideally don't want duplicate names.

14. Make a Dashboard container and add items

14. Make a Dashboard container and add items

Add a root-level container "Dashboard:" and set its OnAdd action to set the "pDashboard" prototype. Add 2 child notes, "Number of scenes" and "Scenes over half complete".

Also, not shown here, add one more scene note "Scene 3" to "the Story" container and put values in 3 key attributes.

15. Add an agent

15. Add an agent

For some of the dashboard reports you will repeatedly be wanting to get information about Scene type notes. These notes both live in "Story" and have the "pScene" prototype which is a longish 2-term query to add into lots of rules. Easier would be to look inside an agent already set to look for just scenes. Therefore, as a root-level note "Agents"; this isn't strictly necessary but does make a place to part other back-of-house agents. Add an agent to the container, called "aScene_List".

16. Set up the agent

16. Set up the agent

Open the agent's Rename dialog and add this query:

inside("/Story") & $Prototype=="pScene"

In the Sort's sort transform pop-up (shown by the arrow), select 'original note'. The latter ensures the alias created for the matched notes are listed as in their outline order. Assuming Scene 1 is added before Scene 2, they will list in that oder in the agent. This can be useful if we want to get an item from this list based on it's original order. Close the Rename dialog.

17. A $Rule for 'Number of Scenes'

17. A $Rule for 'Number of Scenes'

Open the note's Rename dialog and add this code to the note's $Rule:

$MyNumber=$ChildCount("aScene_List");
$Subtitle=$MyNumber;

This code sets the $Subtitle for the note to the number of scene items. That number is cached in $MyNumber as you'll refer to it from another note and you may subsequently add other text to the subtitle. Be aware that for actual use, where you may not need a $MyNumber attribute for testing, you may need to make a Number-type attribute to replace $MyNumber. If so, amend this and subsequent code accordingly.

Now, without the agent you made earlier, to achieve the same aim you would need code like:

$MyNumber=collect(find(inside("/Story")&$Prototype=="pScene"),$Name).size;
$Subtitle=$MyNumber;

See how the agent makes things easier. Both codes achieve the same result be the first one needs far less code and can help with similar slimming of code in other dashboard items too.

18. A $Rule for 'Scenes over half complete'

18. A $Rule for 'Scenes over half complete'

Open the note's Rename dialog and add this code to the note's $Rule:

$Subtitle=(((collect_if(find(inside("aScene_List")),$CompleteState>=0.5,$Name).size)/$MyNumber("Number of Scenes"))*100).format(0)+"%";

Here the subtitle shows the percentage of half complete items. See how the scene count from the last note is re-used via that note's $MyNumber attribute. There are quite a few parentheses here. Some may not be necessary, but they all help indicate to Tinderbox the order in which to execute the bits of the code: make a list of matching items then divide it by the scene count then multiply by 100, then format the result. You don't want those tasks occurring in a different order. If trying to do similar yourself when starting out and if you get confused, make yourself some extra attributes (if required) and split the tasks out. The following would achieve the same end as above, using more code & attributes (here we can re-use some existing test attributes):

$MyNumber = collect_if(find(inside("aScene_List")),$CompleteState>=0.5,$Name).size;
$MyNumber = $MyNumber /$MyNumber("Number of Scenes";
$MyNumber = $MyNumber * 100;
$Subtitle = $MyNumber.format(0)+"%";

Hopefully this helps both show how parentheses in code are used to guide execution and to avoid having to write out each step individually.

19. The Dashboard in Map view

19. The Dashboard in Map view

Select "Number of Scenes" and open a Map view (Cmd+Opt+M). Your icons may look a bit different as some further customisation had been done to "pDashboard" to achieve the above effect (e.g. $NameAlignment, $MapTextSize, $SubtitleSize, $SubtitleColor) but the picture gives an idea of the concept of dashboard notes which give you a tell back on critical info about your project.

Clearly, this dashboard is pretty trivial but the techniques here are those used in making more complex dashboards so should help point the way to you making a more meaningful reporting map. That said, there's no requirement to have a dashboard. If you don't need or want one, avoid the extra effort.

20. Make it your own

You can now either experiment with the document you just made following all the steps or just use the finished demo provided (download). You can use those as the basis for your own work project, for further experiment or simply as a place from which to borrow code.