12/11/2017 - 3:28 PM

Code block from a blog post about using the text port for a live performance.,

Code block from a blog post about using the text port for a live performance.,

author | matthew ragan
web | matthewragan.com

The idea behind the display class comes from a question on the TouchDesiger 
slack channel about how to handle displaying text for performance. While you
might choose to display the console, the challenge here is that you'll end 
up with another window open on your output machine. Ideally, you only draw
a single openGL context - this results in the best possible performance
from TouchDesigner. With that in mind, how might you approach wanting to use
the textport in an artistic way for your project? 

This example tackles that challenge with a set of methods designed to 
print to a texture intended for display, as well as to the text port.

class disp():

    def __init__( self ):
        ''' our init method does a bit of set-up and starting organization.

        We need a few things to be available to us in this method. It's handy
        to have the target table, the target text TOP, a message with a placeholder
        and some information for our start and end rows to be displayed.
        self.TextTarget       = op( 'table_target' )
        self.DisplayText      = op( 'text_for_display' )
        self.MessagePrompt    = ">>> {msg}"
        self.StartRow         = 0
        self.EndRow           = 11


    def Display( self, inputMsg="hello world" ):
        ''' The display method will populate a table which is used to feed a text TOP

        The big idea here is that we need to fill in a table DAT that will then feed
        a text TOP. Why a table DAT instead of a text TOP? Well, you can do whatever you
        want. My idea here is that a table DAT is a little easier to think of in terms 
        of single rows that can fill up a text TOP. We can also do fancy things like use
        a select to make sure that our text is always displayed even if our start and end
        rows get away from us. A text DAT will just keep filling our text TOP, and
        we might end up with squashed text we can't see. 

        In this method we format our MessagePrompt with the supplied text. We also do a 
        quick check to see if our text will fit in the display. If we have more rows than
        can be displayed, we update our class variables to so that our last lines will
        remain visible.

        Finally, we return our formattedMsg - why? This is handy if we want to use another
        method to actually print our message to the textport as well.
        formattedMsg = self.MessagePrompt.format( msg = inputMsg )

        self.TextTarget.appendRow( [ formattedMsg ] )

        if self.TextTarget.numRows > 11:
            self.StartRow   += 1
            self.EndRow     += 1


        return formattedMsg

    def PrintAndDisplay( self, inputMsg="hello world" ):
        ''' The PrintAndDisplay method will both add the message to the text TOP, and 
        print the same message to the console.

        You may be wondering why we return the formatted message - the trick here is that
        we can take advantage of the work that arleady happens in the Display method.
        Why write that whole bit again, if we can just use the same logic and work 
        we've already done, and just add a final step of printing to the textport as well.

        forConsole          = self.Display( inputMsg )
        print( forConsole )

        def ClearDisplay( self ):
        ''' Clear display dumps out the contents of our target table.

        This method seems silly, but the idea is that you're likely to want
        a fast and clean way of cleaning out the contents of your display window.
        This method does only that simple little task. This will also reset our 
        start and end bounds to make sure that we're getting the correct selection
        for our text TOP.