5 # Script does the following:
6 # - greps dali-core for DALI_PROPERTY macro which holds all the information about a property ( type, read only etc)
7 # - uses the filename of the macro to detect the class the properties belong to. E.g. actor-impl.cpp = Actor
8 # - Scans each property macro and builds a list of DALi classes with an array of properties
9 # - Generates the csharp get/set code for each property
10 # - Pastes the property get / set code into the DALi csharp files
12 # Given a DALi C++ property type this table stores the
13 # information needed to produce a csharp getter / setter
15 ["BOOLEAN", "bool", "ref", "bool temp = false;"],
16 ["FLOAT", "float", "ref", "float temp = 0.0f;"],
17 ["INTEGER", "int", "ref", "int temp = 0;"],
18 ["VECTOR2", "Vector2", "", "Vector2 temp = new Vector2(0.0f,0.0f);"],
19 ["VECTOR3", "Vector3", "", "Vector3 temp = new Vector3(0.0f,0.0f,0.0f);"],
20 ["VECTOR4", "Vector4", "", "Vector4 temp = new Vector4(0.0f,0.0f,0.0f,0.0f);"],
21 ["MATRIX3", "Matrix3", "", "Matrix3 temp = new Matrix3();"],
22 ["MATRIX", "Matrix", "", "Matrix temp = new Matrix();" ],
23 ["RECTANGLE", "RectInteger", "", "RectInteger temp = new RectInteger(0,0,0,0);"],
24 ["ROTATION", "Quaternion", "", "Quaternion temp = new Quaternion();"],
25 ["STRING", "string", "out", "string temp;"],
26 ["ARRAY", "Dali.Property.Array", "", "Dali.Property.Array temp = new Dali.Property.Array();"],
27 ["MAP", "Dali.Property.Map", "", "Dali.Property.Map temp = new Dali.Property.Map();"],
30 # Some csharp classes are renamed ( e.g. C++ Control is called View in C#)
35 $daliSwigPath = String.new;
37 def getCSharpName( cppClassName )
39 entry = $renameMap.select{ |a| a.first == cppClassName }
46 # use the table above to get information for a specific type
47 def getCSharpType( type )
49 entry = $typeTable.select{ |a| a.first == type }
57 # Property struct stores the information about a property after parsing the C++ DALI_PROPERTY macro
58 $propertyStruct = Struct.new("Property", :name, :type, :writable, :animatable,:constrainInput, :enum, :shortenum, :develAPI, :csharpGetter, :csharpSetter, :childProperty,)
60 # daliClass struct stores a class name and an array of properties
61 $daliClassStruct = Struct.new("DaliClass", :name, :properties )
63 # class array stores all the dali classes ( actor, image etc)
64 $daliClassArray = Array.new
66 # list of files not generated by swig that we have tried to inject properties into
67 $filesNotWrapped= Array.new
78 # Extracts data DALI__PROPERTY( "points", ARRAY,true,false,false,Dali::Path::Property::POINTS )
79 def extractPropertyInfo( propertyMacro )
81 # want to extract the property name, type + read only status
82 # split the DALI_PROPERTY macro definition by comma and quotes, and delete any empty segments
83 data = propertyMacro.split(/[\s,"]/).reject { |s| s.empty? }
85 propertyName = data[1]
87 # e.g. turn viewMatrix into ViewMatrix
88 propertyName[0] = propertyName[0].capitalize
90 # extract the property enum name Dali::Path::Property::POINTS -> POINTS
91 shortenum = data[6].split(":").last
94 # Check if the property uses devel API
95 # Currently we ignore devel properties for now
96 if data[6].include? "Devel"
98 puts("Ignoring DEVEL API property: " + shortenum);
103 # store the :name, :type, :writable, :animatable, :constrainInput, :enum
104 property = $propertyStruct.new;
106 property.name = propertyName
107 property.type = data[2]
108 property.writable = (data[3]=="true")
109 property.animatable = (data[4] == "true")
110 property.constrainInput = (data[5]=="true")
111 property.enum = shortenum
112 property.develAPI = develAPI;
116 # Extracts data from Toolkit property definition
117 def extractToolkitPropertyInfo( propertyMacro )
119 # Extract the property name, type
120 property = $propertyStruct.new;
122 #First strip out any comments at the end of the macro, some have text like // deprecated
123 commentIndex = propertyMacro.index("//");
126 propertyMacro = propertyMacro.slice(0..commentIndex-1)
130 # Split the macro definition by comma and quotes, close bracket and delete any empty segments
131 data = propertyMacro.split(/[\s,")]/).reject { |s| s.empty? }
133 if(data[1] == "PropertyRegistration")
135 # Properties defined in Control using PropertyRegistration
136 # const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
138 # Creates an array of strings that looks like this:
140 # PropertyRegistration 1
141 # Control::Impl::PROPERTY_1 2
144 # Toolkit::Control::Property::STYLE_NAME 5
146 # &Control::Impl::SetProperty 7
147 # &Control::Impl::GetProperty 8
150 property.name = data[4]
152 propertyType = data[6].rpartition("::")
153 property.type = propertyType[2]
155 propertyEnum = data[5].rpartition("::")
156 property.enum = propertyEnum[2]
160 # Properties defined in macro DALI_PROPERTY_REGISTRATION or DALI_ANIMATABLE_PROPERTY_REGISTRATION or DALI_CHILD_PROPERTY_REGISTRATION
161 # or DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT:
162 # DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "multiLine", BOOLEAN, MULTI_LINE)
163 # DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA)
165 # Creates an array of strings that looks like this:
166 # DALI_PROPERTY_REGISTRATION( 0
174 property.name = data[3]
177 if property.name == "image"
178 property.name = "imageMap"
181 if( data[0] == "DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(" )
182 # TODO: Need to work out the property type from the value
183 property.type = "VECTOR4"
185 property.type = data[4]
188 # last item should be property enum, e.g. INPUT_POINT_SIZE
189 property.enum = data[data.length-1]
193 # e.g. turn styleName into StyleName
194 property.name[0] = property.name[0].capitalize
196 property.writable = true
197 property.animatable = false
198 property.constrainInput = false
199 property.childProperty = false;
201 # check to see if it's a child property
202 if( data[0] == "DALI_CHILD_PROPERTY_REGISTRATION(" )
203 #puts(" #{property.name} is child property ")
204 property.childProperty = true;
206 if( data[0] == "DALI_ANIMATABLE_PROPERTY_REGISTRATION(" )
207 #puts(" #{property.name} is animatable")
208 property.animatable = true;
214 def writePropertiesToCSharpFile( daliClass )
216 # open the CSharp file autogenerated by SWIG
217 swigFiles = $daliSwigPath + "/automatic/csharp/"
219 # some C++ classes are renamed for C#
220 className = getCSharpName( daliClass.name )
222 fileName =(swigFiles + className ) + ".cs"
225 # it's possible some classes in dali-core aren't being wrapped by swig, so if the swig generated file
226 # doesn't exist just return
227 if( ! File.exist?(fileName) )
228 $filesNotWrapped.push("#{daliClass.name}.cs ")
232 File.open(fileName, 'r+') do |file|
235 file.each { last_line = file.pos unless file.eof? }
237 # we seek to the end of the file... minus 3 characters which lets us overwrite the 2 closing brackets
238 # so we can insert the getter/setter stuff into the file.
239 file.seek( last_line-3, IO::SEEK_SET)
241 for property in daliClass.properties
243 if( (!property.childProperty) && (!property.develAPI))
244 file.write( property.csharpGetter );
245 file.write( property.csharpSetter );
250 file.write("\n}\n\n}"); # re-insert the closing brackets we over-wrote
253 puts("Injected #{daliClass.properties.length} C# Properties from #{daliClass.name} into #{className}.cs".blueBackground)
257 def writeChildPropertiesToCSharpFile( daliClass )
259 # open the CSharp file autogenerated by SWIG
260 swigFiles = $daliSwigPath + "/automatic/csharp/"
262 # Add all the child properties to Control
263 fileName = (swigFiles+"View") + ".cs"
265 if( ! File.exist?(fileName) )
269 File.open(fileName, 'r+') do |file|
272 file.each { last_line = file.pos unless file.eof? }
274 # we seek to the end of the file... minus 3 characters which lets us overwrite the 2 closing brackets
275 # so we can insert the getter/setter stuff into the file.
276 file.seek( last_line-3, IO::SEEK_SET)
278 $childPropertyCount = 0
280 for property in daliClass.properties
282 if (property.childProperty)
283 file.write( property.csharpGetter );
284 file.write( property.csharpSetter );
285 $childPropertyCount += 1
290 file.write("\n}\n\n}"); # re-insert the closing brackets we over-wrote
293 puts("Injected #{$childPropertyCount} C# Child Properties into #{"View"}.cs".blueBackground)
297 # Write the CSharp data to the generated .cs file
300 for daliClass in $daliClassArray
302 #puts ( daliClass.name )
305 hasChildProperties = false
307 for property in daliClass.properties
308 propertyInfo = getCSharpType( property.type )
310 if( propertyInfo.length() < 2 )
311 # some types aren't supported yet like Rotation
315 $totalProperties+=1 # keep track of total
317 propertyType = propertyInfo[1] # e.g. bool or int
318 propertyArg = propertyInfo[2] # e.g. ref or out
319 tempDeclaration = propertyInfo[3] # e.g. bool temp;
321 csharpClassName = getCSharpName(daliClass.name);
324 propertyName = "#{csharpClassName}.Property.#{property.enum}"
326 if property.childProperty
327 propertyName = "#{csharpClassName}.ChildProperty.#{property.enum}"
328 hasChildProperties = true
331 property.csharpGetter =" public #{propertyType} #{property.name} \n"\
335 " #{tempDeclaration}\n"\
336 " GetProperty( #{propertyName}).Get( #{propertyArg} temp );\n"\
341 #text.SetProperty(TextLabel.Property.HORIZONTAL_ALIGNMENT, new Property.Value("CENTER"));
342 property.csharpSetter = " set \n" \
344 " SetProperty( #{propertyName}, new Dali.Property.Value( value ) );\n" \
348 property.csharpSetter = "}" # close the opening property declaration
351 # write normal properties to the class's own csharp file
352 writePropertiesToCSharpFile( daliClass )
353 # write child properties to View.cs ( on Control has child properties)
354 if (hasChildProperties)
355 writeChildPropertiesToCSharpFile( daliClass )
361 def getDaliClassItem( className )
363 # puts( "getDaliClassItem "+ className )
364 index = $daliClassArray.index{ |a| a.name == className }
367 # create a new item along with a array for it's properites
368 classItem = $daliClassStruct.new( className, Array.new )
369 $daliClassArray.push( classItem )
370 $totalDaliClasses+=1 # for stats
372 # puts("class found " + className )
373 classItem = $daliClassArray[ index ]
384 pn = Pathname.new(Dir.pwd)
387 $rootPath = fullPath.slice(0..( fullPath.index('/dali-toolkit')))
388 $daliCorePath = $rootPath + "dali-core/dali" # source code path
389 $daliSwigPath = $rootPath + "dali-toolkit/plugins/dali-swig"
390 $daliToolkitPath = $rootPath + "dali-toolkit/dali-toolkit" # source code path
392 puts("--------------------------------------------")
393 puts("Injecting DALi properties into SWIG generated C# files ")
399 def writeDaliCoreProperties
401 puts("Scanning for DALI_PROPERTY macro in dali-core");
402 puts("Scanning folder: #{$daliCorePath}\n\n");
404 # Executed a recursive grep over dali-core for the DALI_PROPERTY macro
405 result =`grep --include \\*.cpp -r "DALI_PROPERTY( \" #{$daliCorePath}`
408 # We now have a list of lines that look like this:
409 # dali/internal/event/animation/path-impl.cpp:DALI__PROPERTY( "points", ARRAY,true,false,false,Dali::Path::Property::POINTS )
411 lines = result.split(/\n+/);
415 # Split the line into file name and property macro, splt 2 means just create two strings as we don't want to split
416 # property Dali::Path::Property::POINTS string as well
418 data = line.split(":",2)
422 # Get the class name from the filename ( e.g. image-actor-impl.cpp => image-actor)
423 className = File.basename(fileName,"-impl.cpp").capitalize
425 # convert it from image-actor to ImageActor
426 className = className.split(/ |\_|\-/).map(&:capitalize).join
428 # Get the property information ( name, type, read/writeable)
429 propertyInfo = extractPropertyInfo( macro );
431 # get or create a new DALi class item which stores the property information
432 classItem = getDaliClassItem( className )
434 classItem.properties.push( propertyInfo )
441 def writeDaliToolkitProperties
444 puts("\nScanning for PROPERTY_REGISTRATION macros in dali-toolkit");
445 puts("Scanning folder: #{$daliToolkitPath}\n\n");
447 $daliClassArray.clear;
449 # Executed a recursive grep over dali-toolkit for following macros
450 # DALI_PROPERTY_REGISTRATION
451 # DALI_ANIMATABLE_PROPERTY_REGISTRATION
452 # DALI_CHILD_PROPERTY_REGISTRATION
453 result =`grep --include \\*.cpp -w 'Control::Impl::SetProperty\\|DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(\\|DALI_CHILD_PROPERTY_REGISTRATION(\\|DALI_ANIMATABLE_PROPERTY_REGISTRATION(\\|DALI_PROPERTY_REGISTRATION' -r #{$daliToolkitPath}`
456 puts("Error parsing #{$daliToolkitPath} no properties found")
459 # create an array to store each DALi class and it's assoc
460 classArray = Array.new
462 # We now have a list of lines that look like this:
463 # text-controls/text-label-impl.cpp:DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "multiLine", BOOLEAN, MULTI_LINE )
464 lines = result.split(/\n+/);
468 # Split the line into file name and property macro, split 2 means just create two strings
469 data = line.split(":",2)
473 # Get the class name from the filename ( e.g. image-actor-impl.cpp => image-actor)
474 className = File.basename(fileName,"-impl.cpp").capitalize
476 # convert it from image-actor to ImageActor
477 className = className.split(/ |\_|\-/).map(&:capitalize).join
482 # Get the property information ( name, type, read/writeable)
483 propertyInfo = extractToolkitPropertyInfo( macro );
485 # get or create a new DALi class item which stores the property information
486 classItem = getDaliClassItem( className )
488 classItem.properties.push( propertyInfo )
496 # helper class to color the background
498 def blueBackground; "\e[44m#{self}\e[0m" end
503 puts("\nFiles that have not been wrapped file by SWIG ( not included in dali.i file):")
504 for i in $filesNotWrapped
508 puts("Done. Injected #{$totalProperties} properties into #{$totalDaliClasses} DALi C# classes".blueBackground)
514 writeDaliCoreProperties()
516 writeDaliToolkitProperties()