|
For this example, suppose we want to add this facility: We want to be able to dynamically place a button at a location on a page which, when clicked, will take us to another page. This might be useful, for example, if the current page uses a term with a complicated definition given on another page, or if the other page contains a table we need to refer to frequently. Once you've gone to the other page, you will want to be able to return to this one with a single button click.
For example, here are two pages from a presentation, which we've labelled P1 and P2 for reference below:
P1:
P2:
Here the teacher is discussing the states of New England and wants to occasionally refer back to a map of the United States. In designing this feature, we have assumed that this is likely to be a spontaneous decision; the teacher realizes that there is a useful page to link to, but does not know its number.
Here's how the feature will work (many variations are possible):
The display returns to page P2, and, on that page, the last ink mark is covered by a button saying "Link". The "Link here" button reverts to "Add link":
When that button is clicked, the display returns to page P2 and the button reverts to "Add link".
We will need to change the initial XML file for this application (lecture.xml) to add the new button, and will need to write four functions:
Slice (this is the root of the entire state tree)
   Lecture (w/ attribute CurrentPage)
     Slides
       InkPanel
       InkPanel
       ...
Slides are numbered by their order under the Slides node. The current page - the one currently displayed - is the unique InkPanel node whose Visible attribute is True.
This is actually all we need to know, but it is useful to know that the lecture application also provides a function GoToPageNum(page number) (where page number is a string giving the new page number). It is also useful to know that the Python global variable Lecture is initialized to point to the Lecture node (allowing us to avoid writing "Lecture = Root.GetChild("Lecture")" at the start of each script).
We need to make two changes to the XML file, lecture.xml. First, we will put the functions mentioned above in a file called Links.py; we need to add it to the PythonDefs attribute near the start of the document:
    PythonDefs="
       Lecture/scripts/init.py|
       Lecture/scripts/scripts.py|
       Lecture/scripts/Print.py|
       Lecture/scripts/Links.py"
Next, we add the Add Link button. The initial display screen for this application looks like this:
There is some space on the bottom left side, so we'll place our button there. (If there were no space, you would have to move or resize the other buttons.) The part of the XML file that describes the yellow button looks like this:
    <Button Id="YellowColorButton" W="55" H="40" X="0" Y="555"
        BackColor="Yellow" ... />
We want to add our button a bit below this, so that would be at Y=595, plus a bit for spacing:
    <Button W="55" H="40" X="0" Y="600" Text="Add Link" Id="LinkButton"
        OnClick="AddLink"/>
The button is placed as shown above. When clicked, it will call the Python AddLink function.
We now look at the functions in Links.py.
AddLink: This is clicked when the teacher is at the linking page (P2). Remember the page number by storing an attribute in the Lecture node, and change the Add Link button to Link Here. The slide number of the current slide, counting from zero, is the position of the current slide among its siblings; it needs to be converted to a string to store it as an attribute.
    def AddLink ():
      Lecture["LinkingPage"] = str(GetCurrentSlide().Position())
      ChangeLinkButton("Link Here", "LinkHere")
      return
The ChangeLinkButton is used in several of the functions. Note that there is just one button in this application, but we keep changing its label and its associated Python function. ChangeLinkButton finds the button by using its Id field, and then changes its label and its associated script name.
    def ChangeLinkButton (label, script):
      buttonnode = TreeNode.FindNodeById("LinkButton")
      buttonnode["Text"] = label
      buttonnode["OnClick"] = script
      return
LinkHere: The teacher navigates to the page she wants to link to (P1), and clicks the Link Here button, which calles the LinkHere function. This is the most complicated function in this feature because it has to find out where to put the Link button and then put it there.
    def LinkHere ():
      linkedpage = GetCurrentSlide().position()
      linkingpage = Lecture["LinkingPage"]
      GoToPageNum(int(linkingpage))
      linkingpagenode = Slides[int(linkingpage)]
      strokes = linkingpagenode.GetChildren()
      laststroke = strokes[len(strokes)-1]
      X = laststroke["X"]
      Y = laststroke["Y"]
      linkbuttonnode = tree("Button", ["Text", "Link", "X", X, "Y", Y, "W", 40,
           "H", 30, "LinkTo", linkedpage,
"OnClick", "FollowLink"], [])
      linkingpagenode.AppendChild(linkbuttonnode)
      ChangeLinkButton("Add Link", "AddLink")
      return
Keep in mind the distinction between the "linked" page (P1) and the "linking" page (P2). This script goes back to the linking page, finds the last ink stroke that was entered on that page, creates a new Button node using the same (X,Y) coordinates as the stroke, adds it to the page, and then changes the "Link Here" button back to "Add Link". If you look back at the structure of the lecture tree, you should be able to follow the code. Some tricky points to note:
FollowLink: This is the script invoked when the Link button is clicked. The node we created contains the number of the page to link to in its LinkTo attribute. This script needs to record the number of the page we're linking from so that the Return script can return to it.
    def FollowLink ():
      Lecture["LinkingPage"] = str(GetCurrentSlide().position())
      GoToPageNum(int(Source["LinkTo"]))
      ChangeLinkButton("Return", "Return")
      return
Return: Since the linking page's number was recorded when the link was followed, this script just finds it in the Lecture node. The toolbar button reverts to its original Add Link version.
    def Return ():
      GoToPageNum(int(Lecture["LinkingPage"]))
      ChangeLinkButton("Add Link", "AddLink")
      return
That's all there is to it.