diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 81f25683d..48b40631f 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -420,7 +420,8 @@ HEADERS = \ dbOriginalLayerTexts.h \ dbNetShape.h \ dbShapeCollection.h \ - dbShapeCollectionUtils.h + dbShapeCollectionUtils.h \ + gsiDeclDbPropertiesSupport.h RESOURCES = \ dbResources.qrc \ diff --git a/src/db/db/dbObjectWithProperties.h b/src/db/db/dbObjectWithProperties.h index 09f4697d6..b30231a8e 100644 --- a/src/db/db/dbObjectWithProperties.h +++ b/src/db/db/dbObjectWithProperties.h @@ -187,6 +187,17 @@ public: return object_with_properties (Obj::transformed (tr), m_id); } + /** + * @brief Returns a string describing the object + */ + std::string to_string () const + { + std::string s = Obj::to_string (); + s += " props="; + s += db::properties (properties_id ()).to_dict_var ().to_string (); + return s; + } + private: properties_id_type m_id; }; @@ -225,6 +236,16 @@ typedef object_with_properties DBoxWithProperties; typedef object_with_properties > CellInstArrayWithProperties; typedef object_with_properties > DCellInstArrayWithProperties; +/** + * @brief Output stream insertion operator + */ +template +inline std::ostream & +operator<< (std::ostream &os, const object_with_properties &p) +{ + return (os << p.to_string ()); +} + } // namespace db #endif diff --git a/src/db/db/gsiDeclDbBox.cc b/src/db/db/gsiDeclDbBox.cc index 697cbb2a1..2266c7fee 100644 --- a/src/db/db/gsiDeclDbBox.cc +++ b/src/db/db/gsiDeclDbBox.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" +#include "gsiDeclDbPropertiesSupport.h" #include "dbPoint.h" #include "dbBox.h" #include "dbHash.h" @@ -590,6 +591,25 @@ Class decl_Box ("db", "Box", "database objects." ); +static db::BoxWithProperties *new_box_with_properties (const db::Box &poly, db::properties_id_type pid) +{ + return new db::BoxWithProperties (poly, pid); +} + +Class decl_BoxWithProperties (decl_Box, "db", "BoxWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_box_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A Box object with properties attached.\n" + "This class represents a combination of a Box object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + static db::DBox *dbox_from_ibox (const db::Box &b) { return new db::DBox (b); @@ -645,4 +665,23 @@ Class decl_DBox ("db", "DBox", "database objects." ); +static db::DBoxWithProperties *new_dbox_with_properties (const db::DBox &poly, db::properties_id_type pid) +{ + return new db::DBoxWithProperties (poly, pid); +} + +Class decl_DBoxWithProperties (decl_DBox, "db", "DBoxWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_dbox_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A DBox object with properties attached.\n" + "This class represents a combination of a DBox object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + } diff --git a/src/db/db/gsiDeclDbPath.cc b/src/db/db/gsiDeclDbPath.cc index 14589ea69..1be94cfaf 100644 --- a/src/db/db/gsiDeclDbPath.cc +++ b/src/db/db/gsiDeclDbPath.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" +#include "gsiDeclDbPropertiesSupport.h" #include "dbPoint.h" #include "dbPath.h" #include "dbHash.h" @@ -384,6 +385,25 @@ Class decl_Path ("db", "Path", "database objects." ); +static db::PathWithProperties *new_path_with_properties (const db::Path &poly, db::properties_id_type pid) +{ + return new db::PathWithProperties (poly, pid); +} + +Class decl_PathWithProperties (decl_Path, "db", "PathWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_path_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A Path object with properties attached.\n" + "This class represents a combination of a Path object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + static db::DPath *dpath_from_ipath (const db::Path &p) { return new db::DPath (p); @@ -452,4 +472,23 @@ Class decl_DPath ("db", "DPath", "database objects." ); +static db::DPathWithProperties *new_dpath_with_properties (const db::DPath &poly, db::properties_id_type pid) +{ + return new db::DPathWithProperties (poly, pid); +} + +Class decl_DPathWithProperties (decl_DPath, "db", "DPathWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_dpath_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A DPath object with properties attached.\n" + "This class represents a combination of a DPath object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + } diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index 97670a515..287dd0a5b 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" +#include "gsiDeclDbPropertiesSupport.h" #include "dbPoint.h" #include "dbPolygon.h" #include "dbPolygonTools.h" @@ -785,6 +786,25 @@ Class decl_SimplePolygon ("db", "SimplePolygon", "database objects." ); +static db::SimplePolygonWithProperties *new_simple_polygon_with_properties (const db::SimplePolygon &poly, db::properties_id_type pid) +{ + return new db::SimplePolygonWithProperties (poly, pid); +} + +Class decl_SimplePolygonWithProperties (decl_SimplePolygon, "db", "SimplePolygonWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_simple_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A SimplePolygon object with properties attached.\n" + "This class represents a combination of a SimplePolygon object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + static db::DSimplePolygon *dspolygon_from_ispolygon (const db::SimplePolygon &p) { return new db::DSimplePolygon (p, false); @@ -853,6 +873,25 @@ Class decl_DSimplePolygon ("db", "DSimplePolygon", "database objects." ); +static db::DSimplePolygonWithProperties *new_dsimple_polygon_with_properties (const db::DSimplePolygon &poly, db::properties_id_type pid) +{ + return new db::DSimplePolygonWithProperties (poly, pid); +} + +Class decl_DSimplePolygonWithProperties (decl_DSimplePolygon, "db", "DSimplePolygonWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_dsimple_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A DSimplePolygon object with properties attached.\n" + "This class represents a combination of a DSimplePolygon object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + // --------------------------------------------------------------- // polygon binding @@ -2026,6 +2065,25 @@ Class decl_Polygon ("db", "Polygon", "database objects." ); +static db::PolygonWithProperties *new_polygon_with_properties (const db::Polygon &poly, db::properties_id_type pid) +{ + return new db::PolygonWithProperties (poly, pid); +} + +Class decl_PolygonWithProperties (decl_Polygon, "db", "PolygonWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A Polygon object with properties attached.\n" + "This class represents a combination of a Polygon object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + static db::DPolygon *dpolygon_from_ipolygon (const db::Polygon &p) { return new db::DPolygon (p, false); @@ -2121,4 +2179,23 @@ Class decl_DPolygon ("db", "DPolygon", "database objects." ); +static db::DPolygonWithProperties *new_dpolygon_with_properties (const db::DPolygon &poly, db::properties_id_type pid) +{ + return new db::DPolygonWithProperties (poly, pid); +} + +Class decl_DPolygonWithProperties (decl_DPolygon, "db", "DPolygonWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_dpolygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A DPolygon object with properties attached.\n" + "This class represents a combination of a DPolygon object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + } diff --git a/src/db/db/gsiDeclDbPropertiesSupport.h b/src/db/db/gsiDeclDbPropertiesSupport.h new file mode 100644 index 000000000..14e88b6c5 --- /dev/null +++ b/src/db/db/gsiDeclDbPropertiesSupport.h @@ -0,0 +1,116 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 Matthias Koefferlein + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef HDR_dbPropertiesSupport +#define HDR_dbPropertiesSupport + +#include "gsiDecl.h" +#include "dbPropertiesRepository.h" + +namespace gsi +{ + +template +static void delete_property_meth_impl (T *s, const tl::Variant &key) +{ + db::properties_id_type id = s->properties_id (); + if (id == 0) { + return; + } + + db::PropertiesSet props = db::properties (id); + props.erase (key); + s->properties_id (db::properties_id (props)); +} + +template +static void set_property_meth_impl (T *s, const tl::Variant &key, const tl::Variant &value) +{ + db::properties_id_type id = s->properties_id (); + + db::PropertiesSet props = db::properties (id); + props.erase (key); + props.insert (key, value); + s->properties_id (db::properties_id (props)); +} + +template +static tl::Variant get_property_meth_impl (const T *s, const tl::Variant &key) +{ + db::properties_id_type id = s->properties_id (); + + const db::PropertiesSet &props = db::properties (id); + return props.value (key); +} + +template +static tl::Variant get_properties_meth_impl (const T *s) +{ + db::properties_id_type id = s->properties_id (); + + const db::PropertiesSet &props = db::properties (id); + return props.to_dict_var (); +} + +template +static gsi::Methods properties_support_methods () +{ + return + gsi::method ("prop_id", (db::properties_id_type (T::*) () const) &T::properties_id, + "@brief Gets the properties ID associated with the object\n" + ) + + gsi::method ("prop_id=", (void (T::*) (db::properties_id_type)) &T::properties_id, gsi::arg ("id"), + "@brief Sets the properties ID of the object\n" + ) + + gsi::method_ext ("delete_property", &delete_property_meth_impl, gsi::arg ("key"), + "@brief Deletes the user property with the given key\n" + "This method is a convenience method that deletes the property with the given key. " + "It does nothing if no property with that key exists. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID." + ) + + gsi::method_ext ("set_property", &set_property_meth_impl, gsi::arg ("key"), gsi::arg ("value"), + "@brief Sets the user property with the given key to the given value\n" + "This method is a convenience method that sets the user property with the given key to the given value. " + "If no property with that key exists, it will create one. Using that method is more " + "convenient than creating a new property set with a new ID and assigning that properties ID.\n" + "This method may change the properties ID. " + "Note: GDS only supports integer keys. OASIS supports numeric and string keys.\n" + ) + + gsi::method_ext ("property", &get_property_meth_impl, gsi::arg ("key"), + "@brief Gets the user property with the given key\n" + "This method is a convenience method that gets the user property with the given key. " + "If no property with that key does not exist, it will return nil. Using that method is more " + "convenient than using the layout object and the properties ID to retrieve the property value. " + ) + + gsi::method ("to_s", (std::string (T::*) () const) &T::to_string, + "@brief Returns a string representing the polygon\n" + ) + + gsi::method_ext ("properties", &get_properties_meth_impl, + "@brief Gets the user properties\n" + "This method is a convenience method that gets the properties of the shape as a single hash.\n" + ); +} + +} + +#endif diff --git a/src/db/db/gsiDeclDbText.cc b/src/db/db/gsiDeclDbText.cc index d37c71bb6..63974976b 100644 --- a/src/db/db/gsiDeclDbText.cc +++ b/src/db/db/gsiDeclDbText.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" +#include "gsiDeclDbPropertiesSupport.h" #include "gsiEnums.h" #include "dbPoint.h" #include "dbText.h" @@ -448,6 +449,25 @@ Class decl_Text ("db", "Text", "database objects." ); +static db::TextWithProperties *new_text_with_properties (const db::Text &poly, db::properties_id_type pid) +{ + return new db::TextWithProperties (poly, pid); +} + +Class decl_TextWithProperties (decl_Text, "db", "TextWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_text_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A Text object with properties attached.\n" + "This class represents a combination of a Text object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + static db::DText *dtext_from_itext (const db::Text &t) { return new db::DText (t); @@ -497,6 +517,25 @@ Class decl_DText ("db", "DText", "database objects." ); +static db::DTextWithProperties *new_dtext_with_properties (const db::DText &poly, db::properties_id_type pid) +{ + return new db::DTextWithProperties (poly, pid); +} + +Class decl_DTextWithProperties (decl_DText, "db", "DTextWithProperties", + gsi::properties_support_methods () + + constructor ("new", &new_dtext_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"), + "@brief Creates a new object from a property-less object and a properties ID." + ) + , + "@brief A DText object with properties attached.\n" + "This class represents a combination of a DText object an user properties. User properties are " + "stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve " + "user properties directly.\n" + "\n" + "This class has been introduced in version 0.30." +); + gsi::Enum decl_HAlign ("db", "HAlign", gsi::enum_const ("HAlignLeft", db::HAlignLeft, "@brief Left horizontal alignment\n" diff --git a/testdata/ruby/dbBoxTest.rb b/testdata/ruby/dbBoxTest.rb index b86c5f2f2..77a5cdf57 100644 --- a/testdata/ruby/dbBoxTest.rb +++ b/testdata/ruby/dbBoxTest.rb @@ -512,6 +512,38 @@ class DBBox_TestClass < TestBase end + def test_boxWithProperties + + s = RBA::BoxWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::BoxWithProperties::new(RBA::Box::new(0, 0, 100, 200), pid) + assert_equal(s.to_s, "(0,0;100,200) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;100,200) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;100,200) props={}") + assert_equal(s.property(1), nil) + + s = RBA::DBoxWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::DBoxWithProperties::new(RBA::DBox::new(0, 0, 100, 200), pid) + assert_equal(s.to_s, "(0,0;100,200) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;100,200) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;100,200) props={}") + assert_equal(s.property(1), nil) + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbPathTest.rb b/testdata/ruby/dbPathTest.rb index 5b46d6a23..f224b96c2 100644 --- a/testdata/ruby/dbPathTest.rb +++ b/testdata/ruby/dbPathTest.rb @@ -329,6 +329,38 @@ class DBPath_TestClass < TestBase end + def test_pathWithProperties + + s = RBA::PathWithProperties::new + assert_equal(s.to_s, "() w=0 bx=0 ex=0 r=false props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::PathWithProperties::new(RBA::Path::new([ [0,0], [100, 0] ], 100), pid) + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={}") + assert_equal(s.property(1), nil) + + s = RBA::DPathWithProperties::new + assert_equal(s.to_s, "() w=0 bx=0 ex=0 r=false props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::DPathWithProperties::new(RBA::DPath::new([ [0,0], [100, 0] ], 100), pid) + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={}") + assert_equal(s.property(1), nil) + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index ef598737a..13e825d1c 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -894,6 +894,66 @@ class DBPolygon_TestClass < TestBase end + def test_polygonWithProperties + + s = RBA::PolygonWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(0, 0, 100, 200)), pid) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") + assert_equal(s.property(1), nil) + + s = RBA::DPolygonWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::DPolygonWithProperties::new(RBA::DPolygon::new(RBA::DBox::new(0, 0, 100, 200)), pid) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") + assert_equal(s.property(1), nil) + + s = RBA::SimplePolygonWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::SimplePolygonWithProperties::new(RBA::SimplePolygon::new(RBA::Box::new(0, 0, 100, 200)), pid) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") + assert_equal(s.property(1), nil) + + s = RBA::DSimplePolygonWithProperties::new + assert_equal(s.to_s, "() props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::DSimplePolygonWithProperties::new(RBA::DSimplePolygon::new(RBA::DBox::new(0, 0, 100, 200)), pid) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") + assert_equal(s.property(1), nil) + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbTextTest.rb b/testdata/ruby/dbTextTest.rb index 99d9551ad..ce00a852e 100644 --- a/testdata/ruby/dbTextTest.rb +++ b/testdata/ruby/dbTextTest.rb @@ -254,6 +254,38 @@ class DBText_TestClass < TestBase end + def test_textWithProperties + + s = RBA::TextWithProperties::new + assert_equal(s.to_s, "('',r0 0,0) props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::TextWithProperties::new(RBA::Text::new("text", RBA::Trans::R90), pid) + assert_equal(s.to_s, "('text',r90 0,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "('text',r90 0,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "('text',r90 0,0) props={}") + assert_equal(s.property(1), nil) + + s = RBA::DTextWithProperties::new + assert_equal(s.to_s, "('',r0 0,0) props={}") + + pid = RBA::Layout::properties_id({ 1 => "one" }) + s = RBA::DTextWithProperties::new(RBA::DText::new("text", RBA::Trans::R90), pid) + assert_equal(s.to_s, "('text',r90 0,0) props={1=>one}") + assert_equal(s.property(1), "one") + assert_equal(s.properties, { 1 => "one" }) + s.set_property(1, "xxx") + assert_equal(s.to_s, "('text',r90 0,0) props={1=>xxx}") + s.delete_property(1) + assert_equal(s.to_s, "('text',r90 0,0) props={}") + assert_equal(s.property(1), nil) + + end + end load("test_epilogue.rb")