15.1.937. tablet_qt/whisker/whiskerapi.h

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include <QColor>
#include <QDebug>
#include <QDateTime>
#include <QRect>
#include <QString>
#include <QStringList>
#include "whisker/whiskerconstants.h"

namespace whiskerapi {

// Define the Whisker client API in C++.
// See http://www.whiskercontrol.com/
//      -> Current versions and manuals
//      -> Whisker help.

// ============================================================================
// Helper functions
// ============================================================================

// Maps a boolean to Whisker's convention of "on" or "off".
QString onVal(bool on);

// ============================================================================
// Helper structs
// ============================================================================

struct Pen {
    // Describes a pen to draw with.

    // Constructor. See member variables below.
    Pen(int width = 1,
        const QColor& colour = whiskerconstants::WHITE,
        whiskerconstants::PenStyle style = whiskerconstants::PenStyle::Solid);

    // Return the Whisker parameters, e.g.
    // "-pencolour 255 0 0 -penwidth 1 -penstyle solid".
    QString whiskerOptionString() const;

    int width;  // width in pixels
    QColor colour;  // pen colour
    whiskerconstants::PenStyle style;  // solid, dashed, etc.
};


struct Brush {
    // Describes a brush to fill with.

    // Constructor. See member variables below.
    Brush(const QColor& colour = whiskerconstants::WHITE,
          const QColor& bg_colour = whiskerconstants::BLACK,
          bool opaque = true,
          whiskerconstants::BrushStyle style = whiskerconstants::BrushStyle::Solid,
          whiskerconstants::BrushHatchStyle hatch_style = whiskerconstants::BrushHatchStyle::Cross);

    // Return the Whisker parameters, e.g. "-brushsolid 0 0 100".
    QString whiskerOptionString() const;

    QColor colour;  // brush colour
    QColor bg_colour;  // background colour for hatched brushes (if opaque)
    bool opaque;  // for hatched brushes: opaque?
    whiskerconstants::BrushStyle style;  // e.g. solid, hollow, hatched
    whiskerconstants::BrushHatchStyle hatch_style;  // for hatched: e.g. horizontal, fdiagonal, cross
};


struct LogOptions {
    // Options to control what's written to a Whisker server disk log.

    bool events = true;  // log events?
    bool key_events = true;  // log keyboard events?
    bool client_client = true;  // log client-to-client communications?
    bool comms = false;  // log communications?
    bool signature = true;  // sign the log?
};


struct DisplayCreationOptions {
    // Options to control how a Whisker dynamic display window is created.

    bool resize = true;  // allow the window to be resized?
    bool directdraw = true;  // use DirectDraw?
    bool debug_touches = false;  // debug touches to the window?
    QRect rectangle;  // window rectangle on the server's screen
};


// ============================================================================
// Display object definition classes
// ============================================================================

class DisplayObject {
    // Base class for graphical objects.

public:

    // Return the Whisker options string, beginning with the type of the
    // display object (as a list).
    virtual QStringList options() const = 0;

    // Default destructor.
    virtual ~DisplayObject() = default;

    // Return the Whisker options string, beginning with the type of the
    // display object (as a single string).
    QString optionString() const;
};


class Arc : public DisplayObject {
    // Draws an arc.

public:
    Arc(const QRect& rect, const QPoint& start, const QPoint& end,
        const Pen& pen = Pen());
    virtual QStringList options() const override;

    QRect rect;  // The arc fits into the rect.
    QPoint start;  // Start of the arc.
    QPoint end;  // End of the arc.
    Pen pen;  // Pen to draw with.
};


class Bezier : public DisplayObject {
    // Draws a Bezier curve.

public:
    Bezier(const QPoint& start, const QPoint& control1, const QPoint& control2,
           const QPoint& end, const Pen& pen = Pen());
    virtual QStringList options() const override;

    QPoint start;  // Start of the curve.
    QPoint control1;  // The control points "pull" the curve.
    QPoint control2;
    QPoint end;  // End of the curve.
    Pen pen;  // Pen to draw with.
};


class Bitmap : public DisplayObject {
    // Displays a bitmap, loaded by the server via a filename.

public:
    Bitmap(const QPoint& pos, const QString& filename,
           bool stretch = false, int height = -1, int width = -1,
           whiskerconstants::VerticalAlign valign = whiskerconstants::VerticalAlign::Top,
           whiskerconstants::HorizontalAlign halign = whiskerconstants::HorizontalAlign::Left);
    virtual QStringList options() const override;

    QPoint pos;  // Coordinate of the bitmap (meaning depends on valign/halign).
    QString filename;  // Filename
    bool stretch = false;  // Stretch, rather than clip?
    int height = -1;  // Height (or -1 for the bitmap's own)
    int width = -1;  // Width (or -1 for the bitmap's own)
    whiskerconstants::VerticalAlign valign = whiskerconstants::VerticalAlign::Top;  // vertical alignment
    whiskerconstants::HorizontalAlign halign = whiskerconstants::HorizontalAlign::Left;  // horizontal alignment
};


class CamcogQuadPattern : public DisplayObject {
    // Displays a CamcogQuadPattern, being a 2x2 grid (four quadrants), each of
    // 8x8 grids of chunky pixels in a quadrant colour.

public:
    CamcogQuadPattern(const QPoint& pos, const QSize& pixel_size,
                      const QVector<uint8_t>& top_left_patterns,
                      const QVector<uint8_t>& top_right_patterns,
                      const QVector<uint8_t>& bottom_left_patterns,
                      const QVector<uint8_t>& bottom_right_patterns,
                      const QColor& top_left_colour,
                      const QColor& top_right_colour,
                      const QColor& bottom_left_colour,
                      const QColor& bottom_right_colour,
                      const QColor& bg_colour);
    virtual QStringList options() const override;

    // See Whisker docs.
    QPoint pos;
    QSize pixel_size;
    QVector<uint8_t> top_left_patterns;
    QVector<uint8_t> top_right_patterns;
    QVector<uint8_t> bottom_left_patterns;
    QVector<uint8_t> bottom_right_patterns;
    QColor top_left_colour;
    QColor top_right_colour;
    QColor bottom_left_colour;
    QColor bottom_right_colour;
    QColor bg_colour;
};


class Chord : public DisplayObject {
    // Displays a chord (an ellipse with a bit sliced off).

public:
    Chord(const QRect& rect, const QPoint& line_start, const QPoint& line_end,
          const Pen& pen = Pen(), const Brush& brush = Brush());
    virtual QStringList options() const override;

    // The chord is the intersection of an ellipse (defined by the rect)
    // and a line that intersects it.
    QRect rect;
    QPoint line_start;
    QPoint line_end;
    Pen pen;
    Brush brush;
};


class Ellipse : public DisplayObject {
    // Displays an ellipse.

public:
    Ellipse(const QRect& rect,
            const Pen& pen = Pen(), const Brush& brush = Brush());
    virtual QStringList options() const override;

    // The ellipse fits into the rectangle (and its centre is at the centre
    // of the rectangle).
    QRect rect;
    Pen pen;
    Brush brush;
};


class Line : public DisplayObject {
    // Displays a line.

public:
    Line(const QPoint& start, const QPoint& end, const Pen& pen = Pen());
    virtual QStringList options() const override;

    QPoint start;
    QPoint end;
    Pen pen;
};


class Pie : public DisplayObject {
    // Displays a pie slice (a "solid" arc).

public:
    Pie(const QRect& rect, const QPoint& arc_start, const QPoint& arc_end,
        const Pen& pen = Pen(), const Brush& brush = Brush());
    virtual QStringList options() const override;

    // See Whisker docs.
    QRect rect;
    QPoint arc_start;
    QPoint arc_end;
    Pen pen;
    Brush brush;
};


class Polygon : public DisplayObject {
    // Displays a polygon.

public:
    Polygon(const QVector<QPoint>& points,
            const Pen& pen = Pen(), const Brush& brush = Brush(),
            bool alternate = false);
    virtual QStringList options() const override;

    // See Whisker docs.
    QVector<QPoint> points;
    Pen pen;
    Brush brush;
    bool alternate = false;
};


class Rectangle : public DisplayObject {
    // Displays a rectangle.

public:
    Rectangle(const QRect& rect,
              const Pen& pen = Pen(), const Brush& brush = Brush());
    virtual QStringList options() const override;

    // See Whisker docs.
    QRect rect;
    Pen pen;
    Brush brush;
};


class RoundRect : public DisplayObject {
    // Displays a rectangle with rounded corners.

public:
    RoundRect(const QRect& rect, const QSize& ellipse_size,
              const Pen& pen = Pen(), const Brush& brush = Brush());
    virtual QStringList options() const override;

    // See Whisker docs.
    QRect rect;
    QSize ellipse_size;
    Pen pen;
    Brush brush;
};


class Text : public DisplayObject {
    // Displays text.

public:
    Text(const QPoint& pos, const QString& text, int height = 0,
         const QString& font = "");
    virtual QStringList options() const override;

    QPoint pos;  // Coordinates of the text (meaning depends on valign/halign).
    QString text;  // Text to display
    int height = 0;  // Height in pixels; 0 means some vaguely sensible default
    QString font;  // Font name; empty gives a system font
    bool italic = false;
    bool underline = false;
    int weight = 0;  // Weight ("bold"); 0 for default weight
    QColor colour = whiskerconstants::WHITE;  // Text colour
    bool opaque = false;  // Opaque, not transparent?
    QColor bg_colour = whiskerconstants::BLACK;  // Background colour (if opaque)
    whiskerconstants::TextVerticalAlign valign = whiskerconstants::TextVerticalAlign::Top;  // vertical alignment
    whiskerconstants::TextHorizontalAlign halign = whiskerconstants::TextHorizontalAlign::Left;  // horizontal alignment
};


class Video : public DisplayObject {
    // Displays a video.

public:
    Video(const QPoint& pos, const QString& filename, bool loop = false,
          whiskerconstants::VideoPlayMode playmode = whiskerconstants::VideoPlayMode::Wait,
          int width = -1, int height = -1);
    virtual QStringList options() const override;

    // See Whisker docs.
    QPoint pos;  // Coordinates of the video (meaning depends on valign/halign).
    QString filename;  // Filename, as seen by the Whisker server.
    bool loop = false;  // Loop once it's finished?
    whiskerconstants::VideoPlayMode playmode = whiskerconstants::VideoPlayMode::Wait;  // How to start?
    int width = -1;  // Width in pixels (-1 for the video's own)
    int height = -1;  // Height in pixels (-1 for the video's own)
    bool play_audio = true;  // Play any audio track?
    whiskerconstants::VerticalAlign valign = whiskerconstants::VerticalAlign::Top;  // vertical alignment
    whiskerconstants::HorizontalAlign halign = whiskerconstants::HorizontalAlign::Left;  // horizontal alignment
    QColor bg_colour = whiskerconstants::BLACK;  // background colour, e.g. before playback (see docs)
};


// ============================================================================
// Helper functions
// ============================================================================

// Converts Whisker's "on"/"off" strings to a bool.
bool onOffToBoolean(const QString& msg);

// Returns a quoted version of a string. Not optimal!
QString quote(const QString& s);

// Converts a list of arguments into a space-separated string, ignoring empty
// arguments.
QString msgFromArgs(const QStringList& args);

// Converts a Qt colour into a "red green blue" string like "255 0 0" for red.
QString rgbFromColour(const QColor& colour);

// Converts a QPoint into an "x y" string.
QString pointCoordinates(const QPoint& point);

// Converts a QRect into a "left top right bottom" string.
QString rectCoordinates(const QRect& rect);

// Converts a QSize into a "width height" string.
QString sizeCoordinates(const QSize& size);


}  // namespace whiskerapi