============================================================
How to write presentations using Bruce the Presentation Tool
============================================================

Some of this document refers to the optional "examples" download
from <http://pypi.python.org/pypi/bruce>.

Bruce presentations are written as plain-text files in the
ReStructuredText format with some extensions. If you have
access to this HOWTO file in its original text format you
may view it using Bruce (the HTML version is produced using
the standard rst2html conversion tool.)

See the examples folder \*.rst files for some samples, the
simplest being "simple.rst" which displays plain text sentences
centered on a white background (using the "big-centered" style)::

    .. load-style:: big-centered

    Text displayed centered on the default white background.

    ----

    A new page, separated from the previous using the four
    dashes.

    Ut enim ad minim veniam.

    A Page Title
    ------------

    Pages may optionally have titles which are displayed
    centered at the top by default.

and so on. Blank pages are possible using ``.. blank::`` in place
of page content.

There's a lot of examples in the examples download, showing off
most of Bruce's features. Get the examples from
<http://pypi.python.org/pypi/bruce>.


More Detail
-----------

Pages in Bruce are defined as being the text contained in a section
or between transitions (horizontal rules, ``----``). It is important
that a blank surrounds the transition line, otherwise ReST might
try to interpret it as a title (which will often mean resulting in
a parsing error). See "examples/test_sectioning.rst" for a file
that mixes section-based and transition-based page delimiting.

There is also a "bullet mode" which treats each bullet point in a
top-level bullet list as a single page. See "examples/test_bullet_mode.rst"
for a file that uses this mode.

Bruce supports a large amount of ReStructuredText and some additional
features:

- inline markup for emphasis, strong, superscript, subscript and literal
- literal and line blocks
- block quotes
- bullet, enumerated and definiton lists (including nesting)
- images (inline and stand-alone)
- tables (no row / column spanning yet)
- page titles (section headings)
- syntax highlighting of code if Pygments__ is installed
- interactive Python interpreter sessions
- styling including separate style sheets
- backgrounds using images or gradients
- transitions between pages
- blank pages
- plugins to create your own inline elements

__ http://pygments.org/

**titles**
    Bruce will not line-wrap title text (doing so messes with layout way
    too much), so make sure your title fits in one line!

**images**
    A ``:width:`` and/or ``:height:`` may be specified to scale the image
    when displayed. If only one is specified then the image's other dimension
    will be scaled to ensure the image aspect ration is retained. Images
    (and video, stylesheets, etc) are located using `resource discovery`_
    described later.

**tables**
    No row or column spanning is implemented yet. Tables may have pretty much
    any arbitrary content though.

**video**
    Embedded in the same manner as images, and may be scaled in the same way.
    Additionally video may be asked to loop using the ``:loop:`` flag.

**code**
    Syntax-highlighting of code blocks if Pygments is installed. The range of
    languages supported by Pygments is at http://pygments.org/docs/lexers/

**blank pages**
    The ``.. blank::`` directive allows you to have blank pages in place of
    page content, for example::

       Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

       ----

       .. blank::

       ----

       Donec auctor vestibulum risus. Vestibulum porttitor purus sed magna.

**interpreter**
    Embeds a Python interpreter in the page. The options available are
    ``:width:`` and ``:height:`` (default 800 by 300). You may also have
    the optional flag ``:sysver:`` which will cause the standard Python
    interactive intepreter greeting with the Python version to be displayed.

**plugins**
    Enables the author to compose a new inline element in Python code. See
    the section on `writing plugins`_.

**style sheets**
    `Bruce Style Sheets (.bss)`_ may be specified on the command-line or
    in the presentation itself using the ``.. load-style::`` directive
    which takes either a built-in style name or a ".bss" filename.


Style Changes
-------------

The rendering stylesheet may be altered on the fly using the ``.. style::``
directive. Changes made in this way are immediate and affect all subsequent
text. The exception to this is the "layout" style which applies to the
entire current and subsequent pages.

The stylesheet is broken up into sections: default, literal, emphasis, strong,
title, footer, block_quote, line_block, literal_block, layout and transition.

Default, title and footer may specify a horizontal alignment.

Default, literal_block and line_block may specify margin_left, margin_right,
margin_top and margin_bottom.

All sections except layout, transition and literal_block may specify character
styling in color, background_color, font_size, font_name, old and italic.

The layout section specifies the background_color and vertical alignment for
page contents.

The transition section specifies the name of the page transition and time
to run it for.

**color**
    Specified as an HTML-like RGB or RGBA hex value, eg. ``#ff00ff`` for
    red=255, green=0 and blue=255, ie. purple. May also use the common HTML
    color names like ``red``, ``white``, ``gray`` etc.
**background_color**
    Specified as per color above, indicates the color to place behind the text.
**font_size**
    Size in points of the font.
**font_name**
    Name of the font. Must be loadable using pyglet.resource.font, so must be
    discoverable using pyglet.resource. Use the inspect_font.py tool in the
    pyglet distribution to discover a font file's name and other attributes
    if you're not sure. You may add new fonts using the resource directive.
**bold**
    Use a font's bold variant. Use ``yes`` or ``no``.
**italic**
    Use a font's italic variant. Use ``yes`` or ``no``.
**alignment**
    One of ``left`` (default), ``center`` or ``right``.
**margin_left, margin_right, margin_top and margin_bottom**
    Margins surrounding paragraphs specified in pixels.
**valign**
    Only valid in the **layout** section; one of ``top`` (default), ``center``
    or ``bottom``.
**position**, **hanchor**, **vanchor**
    Used for title and footer these specify how to place the text. See `title
    and footer positioning`_.
**viewport**
    As seen in the **layout** section. This defines the restricted size to be
    used by page contents (not including title and footer). By default some
    space is allocated so the page contents don't overwrite the page title and
    footer, if they are present and positioned in the usual top and bottom
    places. The viewport is specified as::

        viewport:x,y,width,height

   Giving the bottom-left corner x,y position and the width and height.
**name**
    Only valid in the **transition** section; one of the `transition names`_
    listed below. Default is ``none``.
**duration**
    Only valid in the **transition** section; gives the duration in seconds
    to run the current transition for. Default is ``0.5``.

The default builtin stylesheet may be seen in "examples/default_style.bss".

The "default" group is used as a fallback when a particular style is looked
up and no explicit attribute is set. Thus all text is rendered in ``Arial``
by default, except in literal text where ``Courier New`` is used. You may
set ``title.font_name`` to override the font used in the title or
``default.font_name`` to override the font used everywhere (except literal
text). You may refer to defaults using bare style attributes, so
``default.font_name`` and ``font_name`` are both equivalent.

Style changes are specified using the style directive. To change the font to
64-point bold, you would::

   .. style::
      :font_size: 64
      :bold: yes

To change a single style element you may have the declaration on a single
line::

   .. style:: :font_size: 64

The ``code_*`` style names control the output of the Pygments rendering so if
you've not got that installed you may ignore them. The complete set of names
is (with the ``code_`` prefix removed): ``keyword``, ``text``, ``generic``,
``name``, ``name_class``, ``name_function``, ``literal``, ``punctuation``,
``operator`` and ``comment``.

Title and Footer Positioning
""""""""""""""""""""""""""""

**title positioning**
   The position of the title is controlled by the stylesheet. The
   default ``title`` styles are::

        title.position = w/2,h
        title.hanchor = center
        title.vanchor = top

   Which positions the title at the top-center of the viewport, anchored
   in the center/top of the text.

**footer positioning**
   The position of the footer is controlled by the stylesheet. The
   default ``footer`` styles are::

        footer.position = w,0
        footer.hanchor = right
        footer.vanchor = bottom

   Which positions the foorer at the bottom-right of the viewport, anchored
   in the right/bottom of the text.

All positions may be Python expressions which will be evaluated. The
expressions have the variables "w" and "h" available which are the
width and height of the presentation viewport. To center the title,
for example, the width could be specified as ``w//2``. This will divide
the width by two producing an integer (always try to produce an integer
as it will result in more pleasing rendering).


Bruce Style Sheets (.bss)
"""""""""""""""""""""""""

If you wish to change the style of your presentation significantly from the
built-in styles you may define your own Bruce Style Sheet. This allows you
to alter any of the style properties described above and also change the `page
layout`_ described below. The file may have two sections:

**[layout]**
  The contents of this section are parsed *exactly* the same as described
  in the `page layout`_ section below. This allows you to alter the
  page background decorations.

**[style]**
  This section contains style properties. The syntax for the properties is
  simple::

     property = value

  for example::

     color = white
     bold = yes
     italic = no
     table.border_color = #ff0000
     layout.background_color = black

  By default your stylesheet will use the properties defined in the "default"
  stylesheet where you don't specify anything. You may use an ``inherit-style``
  definition in your sheet to to specify another stylesheet (either built
  in or another .bss file), for example::

     inherit-style = big-centered

  you may only inherit from *one* other stylesheet though.

There are example .bss stylesheets in the "examples" download.


Transition Names
""""""""""""""""

none
  No transition effect. Immediate page change, no delay.
fade
  Fades to background color and then to next page.
jump_zoom
  Zoom out current page and zoom in new page.
shrink_grow
  Like jump_zoom but smoother.
roto_zoom
  Rotate and zoom our current page, rotate and zoom in new page.
move_in_left, move_in_right, move_in_bottom, move_in_top
  Move the next page in from the specified side.
slide_in_left, slide_in_right, slide_in_bottom, slide_in_top
  Slide the current page off and new page on from the specified side.

The following do not work on all machines:

- flip_x, flip_y, flip_angle
- shuffle
- turn_off_tiles
- fade_top_right, fade_bottom_left, fade_up, fade_down
- corner_move
- envelope
- split_rows, split_cols


Page Layout
-----------

The page layout may also be defined on the fly. Unlike the stylesheet
which may be modified in-place, the page layout must be specified entirely
with each directive. The layout directive applies to the current and
subsequent pages.

A blank layout directive ``.. layout::`` will result in the default
white background and no other decoration.

**image-based decoration**
   You may draw images on the page which will appear under any content. The
   syntax for specifying an image is::

       :image:<filename>;halign=left;valign=bottom

   This will place the indicated image flush against the bottom-left of
   the page.

**background gradients**
   You may specify a vertical or horizontal color gradient for the page
   background. This may be vertical or horizontal::

       :vgradient:<top color>;<bottom color>
       :hgradient:<left color>;<right color>

**quad-based decoration**
   You may draw quads on the page which will appear under any content. The
   quads may have color gradients by specifying different colors for each
   corner. The syntax for specifying a quad is::

       :quad:C<color spec>;Vx1,y1;Vx2,y2;Vx3,y3;Vx4,y4

   Quad vertex color carries over if it's not specified for each vertex,
   allowing either solid color or blending.

   Colors are specified in HTML format with either three or four channels
   (if three then the fourth, alpha channel is set to 255).

All positions (quad vertexes, title position, etc) may be Python expressions
which will be evaluated. The expressions have the variables "w" and "h"
available which are the width and height of the presentation viewport. To
center the title, for example, the width could be specified as ``w/2``.


Resource Discovery
------------------

Bruce can display images and video found in the same directory as the
presentation source. You may enable Bruce to search additional paths
to find images and video. Additionally you may load new fonts for display
by referring to TrueType Font files. You do so using the ``.. resource::``
directive.

**adding a directory of resources**::

    .. resource:: <path to directory>

**adding a font file**::

    .. resource:: <font filename>.ttf

To refer to the font later you'll need to know its name, which may differ
from the filename. You may use the inspect_font.py tool in the pyglet
source to do so.


Writing Plugins
---------------

A plugin is used with the ``.. plugin::`` directive. For example::

    .. plugin:: test_plugin
       :width: 300
       :height: 300

The directive is referring to the plugin implemented in the file
``test_plugin.py`` which is found using normal `resource discovery`_. That
file must contain:

1. a class called Plugin which derives from bruce.plugin.Plugin, and
2. an implementation of any or all of the methods described below.

If your plugin is animated you may request a regular tick from the clock
by setting the property needs_tick either on your class or in your
``__init__`` method.

**__init__(self, width=800, height=400)__**
    Invoked when the presentation is parsed.
    Passed the width and height as specified in the presentation.

**resize(self, width, height)**
    Invoked when the page the element is on is scaled.

**place(self, layout, x, y)**
    Invoked when the page layout needs to position the element on screen.
    Passed a pyglet.text.IncrementalTextLayout instance and the pixel
    position of the bottom left of the element in that layout. This
    position almost always has a negative y value.

**remove(self, layout)**
    Invoked when page layout removes the element from display.

**tick(self, dt)**
    Invoked if the element defines needs_tick **before enter is invoked**.
    Will be called once per "clock tick" with dt being the time in
    seconds since the last call.

Plugin contents should be rendered using the pyglet.graphics API with the
Batch instance on the layout passed into the place() method.

Additionally any graphics elements added to the batch should use the group
layout.top_group as the base group. This group defines positioning
transformations without which your plugin content will most likely not
be visible.

Again note you'll almost always receive a negative y position in the
``place()`` call. The transforms in ``layout.top_group`` adjust for this
(the top of the layout is typically at y=0).

If you wish to alter the OpenGL context to turn on environment features
such as texturing, or even just to perform additional transformations then
you should define your own pyglet.graphics.Group. When you instantiate
this group you should then pass it layout.top_group.

The following is an example plugin file used in "examples/test_plugin.rst"::

    import pyglet
    from pyglet.gl import *

    from bruce import plugin

    class TestGroup(pyglet.graphics.Group):
        angle = 0

        def set_state(self):
            glPushMatrix()
            x, y = self.center
            glTranslatef(x, y, 0)
            glRotatef(self.angle, 0, 0, 1)
            glTranslatef(-x, -y, 0)

        def unset_state(self):
            glPopMatrix()

    class Plugin(plugin.Plugin):
        needs_tick = True
        def resize(self, w, h):
            self.w, self.h = w, h

        def tick(self, dt):
            self.group.angle += 1

        def place(self, layout, x, y):
            x1 = int(x)
            y1 = int(y)
            x2 = int(x + self.w)
            y2 = int(y + self.h)
            self.group = TestGroup(layout.top_group)
            self.group.center = (x+self.w/2, y+self.h/2)
            self.r = layout.batch.add(4, GL_QUADS, self.group,
                ('c3B', (255, 0, 0) * 4),
                ('v2i', (x1, y1, x2, y1, x2, y2, x1, y2)),
            )

        def remove(self, layout):
            self.r.delete()

