Widgets and Scene Graph

jwatte's picture

To implement a GUI, there are a number of widgets provided in the support library (text edit box, rotary knob, slider, selector, pushbutton, checkbox, etc). Given that ItfWindowSlave interface, a plug-in can also implement custom widgets. The widgets, in turn, use the retained-mode scene graph to describe what they look like. Changing what's drawn typically means updating the text or image of an element on screen, or moving/scaling/rotating it. Because the host typically uses an accelerated graphics API to render the GUI, things like bitmap transparency and rotation are basically "free" (no extra cost).

The widgets are implemented entirely in terms of ItfElement (bitmap and text) and ItfWindowSlave. This means that an effect can provide a totally custom GUI using the same interfaces, without using the support library widget kit. Thus, the interfaces ItfElement, ItfText, ItfBitmap, ItfPolygon and ItfLineList make up the entirety of the interface exposed by the host, and ItfWindowSlave makes up the entirety of the interface exposed by the plug-in. The convenience classes that simplify programming with SAPS are not part of the formal interface specification, but part of the SAPS SDK.

The support library contains widgets to implement knobs etc. These widgets update values to the base effect by posting events to the parameters through the host. This allows the host to record events, providing parameter automation capability. While interaction with the mouse in real time cannot be done at sample accuracy, later editing, or interactions from hardware controllers such as MIDI keyboards or USB user interface surfaces can be sample precise from the get-go.

class ItfElement
{
  public:
    /* Remove the element, and dispose it so it can't be used again. */
    virtual void    Dispose() = 0;
    /* Return the window the element is attached to, or NULL. */
    virtual ItfWindow *
                    Window() = 0;
    /* Remove the element from its window (if any), but keep it around (you can later add it back). */
    virtual void    Remove() = 0;
    /* Given a window coordinate, test whether the element was hit by that point, and if so, */
    /* calculate element-relative coordinates (which is not trivial for rotated elements). */
    virtual bool    PointHit(Pixels x, Pixels y, Pixels *ox, Pixels *oy) = 0;
    /* Return the reference point, in element coordinates, around which the element is rotated and positioned. */
    virtual void    RefPoint(Pixels *ocx, Pixels *ocy) = 0;
    /* Set the reference point, in element coordinates, around which the element is rotated, and which is positioned with SetPosition(). */
    virtual void    SetRefPoint(Pixels cx, Pixels cy) = 0;
    /* Return the position, in window coordinates, of the reference point of the element. */
    virtual void    Position(Pixels *ox, Pixels *oy) = 0;
    /* Set the position, in window coordinates, of the reference point of the element. */
    virtual void    SetPosition(Pixels x, Pixels y) = 0;
    /* Return the size, in element coordinates, of the element. */
    virtual void    Extent(Pixels *ow, Pixels *oh) = 0;
    /* Return the rotation, in radians counter-clockwise, of the element. */
    virtual Radians Rotation() = 0;
    /* Set the rotation, in radians counter-clockwise, of the element. */
    virtual void    SetRotation(Radians r) = 0;
    /* Return the tint of the element. The "add" value is added to each pixel, the "multiply" value is multiplied into each pixel. */
    /* Note that these values may be greater than 1, or less than 0! */
    virtual void    Tint(Color *outAdd, Color *outMultiply) = 0;
    /* Set the tint. The "add" values are added to each pixel; the "multiply" value is multiplied into each pixel. */
    virtual void    SetTint(Color add, Color multiply) = 0;
    /* Turn off or on whether the slave should receive notifications about the mouse moving over this element. */
    virtual void    SetWantsMouse(bool wantsMouse) = 0;
    /* Return whether the slave should receive notifications about the mouse moving over this element. */
    virtual bool    WantsMouse() = 0;
 
    /*  Aah! Some data in an interface! This data is for use by the effect/plug-in implementer, and not touched by the library or host. */
    void           *UserPtr;
};
 
struct BitmapInfo
{
  void const       *Pixels;     //  Pointer to pixels. Pixels are stored in the BGRA byte order.
  size32            Pitch;      //  how many bytes per row (which may be more than 4 * width)
  size32            Width;      //  how many columns of pixels. Column 0 is at the left.
  size32            Height;     //  how many rows of data. Row 0 is at the top.
};
 
class ItfBitmap
{
  public:
    /* Return the element that can actually be added/positioned. */
    virtual ItfElement *
                    Element() = 0;
    /* Fill the bitmap with some data. */
    virtual void    SetData(BitmapInfo const &info, size32 left = 0, size32 top = 0) = 0;
};
 
class ItfText
{
  public:
    /* Return the Element that can actually be placed in the window. */
    virtual ItfElement *
                    Element() = 0;
    /* Update the text of the element. The original size constraints are still used. */
    virtual void    SetText(TextInfo const &info) = 0;
    /* Return the text */
    virtual wchar_t const *
                    Text() = 0;
    /* Given a point (in widget-relative coordinates), return which character that points at. */
    /* This is offset half a character, to be properly used when drag-selecting text. */
    virtual size32  
                    CharacterFromPoint(Pixels x, Pixels y) = 0;
    /* How tall is a line in the current text? */
    virtual Pixels  
                    LineHeight() = 0;
    /* Given a character index (from 0 to length-1), what is the rectangle that encloses that character? */
    virtual void    RectFromCharacter(size32 ix, Pixels *oLeft, Pixels *oRight, Pixels *oTop, Pixels *oBottom) = 0;
    /* Given a character index (from 0 to length-1), what line is that character part of? */
    virtual size32  
                    LineFromCharacter(size32 ix) = 0;
    virtual size32  LineCount() = 0;
    /* Given a line, what index does the character have that starts that line? */
    virtual size32  
                    LineStartCharacter(size32 line) = 0;
    /* Get the selection (highlighted area). If there is no selection, return false. */
    virtual bool    Selection(size32 *ostart, size32 *oend) = 0;
    /* Set the selection (highlighted area). */
    virtual void    SetSelection(size32 start, size32 end) = 0;
};
 
enum TextAdjust
{
  TextAdjustNormal = 0,
  TextAdjustCenter = 1,
  TextAdjustReverse = 2,
};
 
struct TextInfo
{
  size64            StructSize;   //  sizeof(TextInfo)
  wchar_t const    *Text;         //  non-terminated string
  size32            Length;       //  wcslen(text)
  Pixels            MaxWidth;     //  Maximum width. If 0, use window width.
  Pixels            MaxHeight;    //  Maximum height. If 0, use infinite height.
  Pixels            PointsSize;   //  How many points is the text? (9pt is small but readable; 12 pt is common)
  bool              Bold;         //  Is the text fattened?
  bool              Italic;       //  Is the text italic/slanted/oblique?
  bool              Monospace;    //  Is the text monospace?
  bool              FullRect;     //  Will the element always use the full rect specified by MaxWidth/MaxHeight, 
                                  //  even if it fits in a smaller rect?
  bool              RightToLeft;  //  Is the text in a right-to-left script?
  bool              TopToBottom;  //  Is the text in a top-to-bottom script?
  byte              Adjust;       //  Normal (Left for Latin), Center, Reverse (Right for Latin)
};