add an plugin API to query generic-gui grid-layout
[ardour.git] / libs / ardour / ardour / variant.h
index 00b9c3acf8e772fd80b5ad33c635eab608f66da5..4cf1df5556490946c857c14bcdd0a52ae7b57ef5 100644 (file)
 #define __ardour_variant_h__
 
 #include <stdint.h>
+#include <limits.h>
 
+#include <algorithm>
 #include <stdexcept>
 
 #include "ardour/libardour_visibility.h"
+#include "evoral/Beats.hpp"
 #include "pbd/compose.h"
 
 namespace ARDOUR {
@@ -34,6 +37,8 @@ class LIBARDOUR_API Variant
 {
 public:
        enum Type {
+               NOTHING, ///< Nothing (void)
+               BEATS,   ///< Beats+ticks
                BOOL,    ///< Boolean
                DOUBLE,  ///< C double (64-bit IEEE-754)
                FLOAT,   ///< C float (32-bit IEEE-754)
@@ -44,29 +49,142 @@ public:
                URI      ///< URI string
        };
 
-       explicit Variant(bool value)   : _type(BOOL)   { _bool   = value; }
-       explicit Variant(double value) : _type(DOUBLE) { _double = value; }
-       explicit Variant(float value)  : _type(FLOAT)  { _float  = value; }
-       explicit Variant(int value)    : _type(INT)    { _int    = value; }
-       explicit Variant(long value)   : _type(LONG)   { _long   = value; }
+       Variant() : _type(NOTHING) { _long = 0; }
 
+       explicit Variant(bool    value) : _type(BOOL)    { _bool   = value; }
+       explicit Variant(double  value) : _type(DOUBLE)  { _double = value; }
+       explicit Variant(float   value) : _type(FLOAT)   { _float  = value; }
+       explicit Variant(int32_t value) : _type(INT)     { _int    = value; }
+       explicit Variant(int64_t value) : _type(LONG)    { _long   = value; }
+
+       explicit Variant(const Evoral::Beats& beats)
+               : _type(BEATS)
+               , _beats(beats)
+       {}
+
+       /** Make a variant of a specific string type (string types only) */
        Variant(Type type, const std::string& value)
                : _type(type)
                , _string(value)
        {}
 
+       /** Make a numeric variant from a double (numeric types only).
+        *
+        * If conversion is impossible, the variant will have type NOTHING.
+        */
+       Variant(Type type, double value)
+               : _type(type)
+       {
+               switch (type) {
+               case BOOL:
+                       _bool = value != 0.0;
+                       break;
+               case DOUBLE:
+                       _double = (double)value;
+                       break;
+               case FLOAT:
+                       _float = (float)value;
+                       break;
+               case INT:
+                       _int = (int32_t)lrint(std::max((double)INT32_MIN,
+                                                      std::min(value, (double)INT32_MAX)));
+                       break;
+               case LONG:
+                       _long = (int64_t)lrint(std::max((double)INT64_MIN,
+                                                       std::min(value, (double)INT64_MAX)));
+                       break;
+               case BEATS:
+                       _beats = Evoral::Beats(value);
+                       break;
+               default:
+                       _type = NOTHING;
+                       _long = 0;
+               }
+       }
+
+       /** Convert a numeric variant to a double. */
+       double to_double() const {
+               switch (_type) {
+               case BOOL:   return _bool;
+               case DOUBLE: return _double;
+               case FLOAT:  return _float;
+               case INT:    return _int;
+               case LONG:   return _long;
+               case BEATS:  return _beats.to_double();
+               default:     return 0.0;
+               }
+       }
+
        bool   get_bool()   const { ensure_type(BOOL);   return _bool;   }
        double get_double() const { ensure_type(DOUBLE); return _double; }
        float  get_float()  const { ensure_type(FLOAT);  return _float;  }
        int    get_int()    const { ensure_type(INT);    return _int;    }
        long   get_long()   const { ensure_type(LONG);   return _long;   }
 
+       bool   operator==(bool v)   const { return _type == BOOL   && _bool == v; }
+       double operator==(double v) const { return _type == DOUBLE && _double == v; }
+       float  operator==(float v)  const { return _type == FLOAT  && _float == v; }
+       int    operator==(int v)    const { return _type == INT    && _int == v; }
+       long   operator==(long v)   const { return _type == LONG   && _long == v; }
+
+       Variant& operator=(bool v)   { _type = BOOL;   _bool = v;   return *this; }
+       Variant& operator=(double v) { _type = DOUBLE; _double = v; return *this; }
+       Variant& operator=(float v)  { _type = FLOAT;  _float = v;  return *this; }
+       Variant& operator=(int v)    { _type = INT;    _int = v;    return *this; }
+       Variant& operator=(long v)   { _type = LONG;   _long = v;   return *this; }
+
        const std::string& get_path()   const { ensure_type(PATH);   return _string; }
        const std::string& get_string() const { ensure_type(STRING); return _string; }
        const std::string& get_uri()    const { ensure_type(URI);    return _string; }
 
+       bool operator==(const Variant& v) const {
+               if (_type != v._type) {
+                       return false;
+               }
+
+               switch (_type) {
+               case NOTHING: return true;
+               case BEATS:   return _beats  == v._beats;
+               case BOOL:    return _bool   == v._bool;
+               case DOUBLE:  return _double == v._double;
+               case FLOAT:   return _float  == v._float;
+               case INT:     return _int    == v._int;
+               case LONG:    return _long   == v._long;
+               case PATH:
+               case STRING:
+               case URI:     return _string == v._string;
+               }
+
+               return false;
+       }
+
+       bool operator==(const Evoral::Beats& v) const {
+               return _type == BEATS && _beats == v;
+       }
+
+       bool operator!() const { return _type == NOTHING; }
+
+       Variant& operator=(Evoral::Beats v) {
+               _type  = BEATS;
+               _beats = v;
+               return *this;
+       }
+
+       const Evoral::Beats& get_beats() const {
+               ensure_type(BEATS); return _beats;
+       }
+
        Type type() const { return _type; }
 
+       static bool type_is_numeric(Type type) {
+               switch (type) {
+               case BOOL: case DOUBLE: case FLOAT: case INT: case LONG: case BEATS:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
 private:
        static const char* type_name(const Type type) {
                static const char* names[] = {
@@ -84,8 +202,9 @@ private:
                }
        }
 
-       Type        _type;    ///< Type tag
-       std::string _string;  ///< For all string types (PATH, STRING, URI)
+       Type          _type;    ///< Type tag
+       std::string   _string;  ///< PATH, STRING, URI
+       Evoral::Beats _beats;   ///< BEATS
 
        // Union of all primitive numeric types
        union {