#include #include #include #include "oct.h" class radio_values { public: radio_values (const std::string& opt_string) { size_t beg = 0; size_t len = opt_string.length (); bool done = len == 0; while (! done) { size_t end = opt_string.find ('|', beg); if (end == std::string::npos) { end = len; done = true; } std::string t = opt_string.substr (beg, end-beg); // Might want more error checking here... if (t[0] == '{') { t = t.substr (1, t.length () - 2); default_val = t; } else if (beg == 0) // ensure default value { default_val = t; } possible_vals.insert (t); beg = end + 1; } }; radio_values (const radio_values& a) : default_val (a.default_val), possible_vals (a.possible_vals) { } radio_values& operator = (const radio_values& a) { if (&a != this) { default_val = a.default_val; possible_vals = a.possible_vals; } return *this; } std::string default_value (void) const { return default_val; } std::set possible_values (void) const { return possible_vals; } bool validate (const std::string& val) { bool retval = true; if (possible_vals.find (val) == possible_vals.end ()) { error("invalid value = %s",val.c_str () ); retval= false; } return retval; } private: // Might also want to cache std::string default_val; std::set possible_vals; }; class radio_property { public: radio_property (const radio_values& v) : vals (v), current_val (v.default_value ()) { } radio_property (const radio_values& v, const std::string& initial_value) : vals (v), current_val (initial_value) { } radio_property (const radio_property& a) : vals (a.vals), current_val (a.current_val) { } radio_property& operator = (const radio_property& a) { if (&a != this) { vals = a.vals; current_val = a.current_val; } return *this; } radio_property& operator = (const std::string& newval) { if (vals.validate (newval)) current_val = newval; return *this; } const std::string& current_value (void) const { return current_val; } private: radio_values vals; std::string current_val; }; class color_values { public: color_values (double r = 0, double g = 0, double b = 1) { xrgb[0] = r; xrgb[1] = g; xrgb[2] = b; validate (); } color_values (const char c) { if (!c2rgb (c)) error ("invalid color specification"); } color_values (const color_values& c) { xrgb[0] = c.xrgb[0]; xrgb[1] = c.xrgb[1]; xrgb[2] = c.xrgb[2]; } color_values& operator = (const color_values& c) { if (&c != this) { xrgb[0] = c.xrgb[0]; xrgb[1] = c.xrgb[1]; xrgb[2] = c.xrgb[2]; } return *this; } const double* rgb (void) const { return xrgb; } void validate (void) const { for (int i = 0; i < 3; i++) { if (xrgb[i] < 0 || xrgb[i] > 1) { error ("invalid RGB color specification"); break; } } } private: double xrgb[3]; bool c2rgb (char c) { double tmp_rgb[3] = {0, 0, 0}; bool retval = true; switch(c) { case 'r': tmp_rgb[0] = 1; break; case 'g': tmp_rgb[1] = 1; break; case 'b': tmp_rgb[2] = 1; break; case 'c': tmp_rgb[1] = tmp_rgb[2] = 1; break; case 'm': tmp_rgb[0] = tmp_rgb[2] = 1; break; case 'y': tmp_rgb[0] = tmp_rgb[1] = 1; break; case 'w': tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1; break; default: retval = false; } if (retval) { for (int i = 0; i < 3; i++) xrgb[i] = tmp_rgb[i]; } return retval; } }; class color_property { public: color_property (const color_values& c=color_values (), const radio_values& v = radio_values ("")) : color_val (c) , radio_val (v) , current_val (v.default_value ()) , current_type (color_t) { } color_property (const radio_values& v) : color_val (color_values ()), radio_val (v), current_val (v.default_value ()), current_type (radio_t) { } color_property (const radio_values& v, const std::string& initial_value) : color_val (color_values ()), radio_val (v), current_val (initial_value), current_type (radio_t) { } color_property (const octave_value& val) : radio_val (""), current_val ("") { // FIXME -- need some error checking here. if ( val.is_real_matrix () ) { Matrix m = val.matrix_value (); if ( m.numel () == 3) { color_values col (m (0), m (1), m(2)); if (! error_state ) { color_val = col; current_type = color_t; } } else error ("invalid color specification"); } else error ("invalid color specification"); } operator octave_value (void) const { if (current_type == color_t) { Matrix retval (1, 3); const double *xrgb = color_val.rgb (); for (int i = 0; i < 3 ; i++) retval(i) = xrgb[i]; return retval; } return current_val; } color_property& operator = (const color_property& a) { if (&a != this) { current_type = a.current_type; color_val = a.color_val; radio_val = a.radio_val; current_val = a.current_val; } return *this; } color_property& operator = (const std::string& newval) { if (radio_val.validate (newval)) { current_val = newval; current_type = radio_t; } return *this; } color_property& operator = (const color_values& newval) { color_val = newval; current_type = color_t; return *this; } bool is_rgb (void) const { return (current_type == color_t); } bool is_radio (void) const { return (current_type == radio_t); } const double* rgb (void) const { if (current_type != color_t) error ("color has no rgb value"); return color_val.rgb (); } const std::string& current_value (void) const { if (current_type != radio_t) error ("color has no radio value"); return current_val; } private: enum { color_t, radio_t } current_type; color_values color_val; radio_values radio_val; std::string current_val; }; std::ostream& operator << (std::ostream& os, const radio_property& a) { return (os << a.current_value ()); } void tryme (const std::string& nm, radio_property& x) { std::cerr << nm << " initial: " << x << std::endl; x = "yes"; std::cerr << nm << " after yes assignment: " << x << std::endl; x = "no"; std::cerr << nm << " after no assignment: " << x << std::endl; x = "foobar"; std::cerr << nm << " after failed assignment: " << x << "\n" << std::endl; } void test_col (const std::string& nm, const color_property& c) { std::cerr << nm << " : " ; if ( c.is_rgb () ) { const double * d = c.rgb (); std::cerr << "color -> " << d[0] << "," << d[1] << "," << d[2] << "\n"; } else if ( c.is_radio () ) { std::cerr << "radio -> " << c.current_value () << "\n"; } else { std::cerr << "illegal state\n"; } } DEFUN_DLD (test_prop, args , ,"") { octave_value retval; // Initial value set from default: radio_property x (radio_values ("yes|no|{auto}")); tryme ("x", x); // Non-default initial value: radio_property y (radio_values ("yes|no|{auto}"), "yes"); tryme ("y", y); radio_property yy (radio_values ("")); tryme("yy",yy); std::cerr << "yy length " << yy.current_value ().length () << std::endl; std::cerr << "\n\n\n-------------------------\n\n"; color_property aa ( color_values (1,0,0)); test_col ( "aa" , aa ); color_property bb ( color_values ('r')); test_col ( "bb" , bb ); color_property cc (color_values (0,1,0),radio_values ("yes|no|{auto}") ); test_col ( "cc1" , cc ); cc = "yes"; test_col ( "cc2" , cc ); cc = "good"; test_col ( "cc3" , cc ); cc = 'g'; test_col ( "cc4" , cc ); cc = color_values (1,1,1); test_col ( "cc5" , cc ); color_property dd (radio_values ("yes|no|{auto}") , "no"); test_col ( "dd1" , dd ); dd = 'b'; test_col ( "dd2" , dd ); dd = "auto"; test_col ( "dd3" , dd ); dd = color_values (5,3,1); test_col ( "dd3" , dd ); color_property ee; test_col ( "ee" , ee ); return retval; }