Class: UIC::Presentation

Inherits:
Object
  • Object
show all
Includes:
XMLFileBacked
Defined in:
lib/ruic/presentation.rb

Overview

A Presentation represents a .uip presentation, created and edited by UI Composer Studio.

Direct Known Subclasses

Application::Presentation

Instance Attribute Summary

Attributes included from XMLFileBacked

#doc

Attributes included from FileBacked

#file, #file_content

Instance Method Summary collapse

Methods included from XMLFileBacked

#file=, #save!, #save_as

Methods included from FileBacked

#absolute_path, #file_found?, #filename, #relative_path, #save!, #save_as

Constructor Details

#initialize(uip_path = nil) ⇒ Presentation

Create a new presentation. If you do not specify the uip_path to load from, you must later set the .file =for the presentation, and then call the #load_from_file method.

Parameters:

  • uip_path (String) (defaults to: nil)

    path to the .uip to load.



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/ruic/presentation.rb', line 8

def initialize( uip_path=nil )
	@doc = Nokogiri.XML('<UIP version="3"><Project><Graph><Scene id="Scene"/></Graph><Logic><State name="Master Slide" component="#Scene"/></Logic></Project></UIP>')
	@graph = @doc.at('Graph')
	@scene = @graph.at('Scene')
	@logic = @doc.at('Logic')
	@missing_classes = []
	@asset_by_el  = {} # indexed by asset graph element
	@slides_for   = {} # indexed by asset graph element
	@slides_by_el = {} # indexed by slide state element
	self.file = uip_path if uip_path
end

Instance Method Details

#aliasesArray<MetaData::AssetBase>

Returns array of alias nodes in the presentation.

Returns:



612
# File 'lib/ruic/presentation.rb', line 612

def aliases; find _type:'Alias'; end

#anchor_pointsArray<MetaData::AssetBase>

Returns array of path anchor points in the presentation.

Returns:



618
# File 'lib/ruic/presentation.rb', line 618

def anchor_points; find _type:'PathAnchorPoint'; end

#asset_by_id(id) ⇒ MetaData::AssetBase

Find an asset in the presentation based on its internal XML identifier.

Parameters:

  • id (String)

    the id of the asset (not an idref), e.g. "Material_003".

Returns:



105
106
107
# File 'lib/ruic/presentation.rb', line 105

def asset_by_id( id )
	(@graph_by_id[id] && asset_for_el( @graph_by_id[id] ))
end

#assetsObject

Get an array of all assets in the scene graph, in document order



136
137
138
# File 'lib/ruic/presentation.rb', line 136

def assets
	@graph_by_id.map{ |id,graph_element| asset_for_el(graph_element) }
end

#at(path, root = @graph) ⇒ MetaData::AssetBase Also known as: /

Find an element or asset in this presentation by scripting path.

  • If root is supplied, the path is resolved relative to that asset.
  • If root is not supplied, the path is resolved as a root-level path.

Examples:

preso  = app.main
scene  = preso.scene
camera = scene/"Layer.Camera"

# Four ways to find the same layer
layer1 = preso/"Scene.Layer"
layer2 = preso.at "Scene.Layer"
layer3 = preso.at "Layer", scene
layer4 = preso.at "parent", camera

assert layer1==layer2 && layer2==layer3 && layer3==layer4

Returns:

See Also:



300
301
302
303
304
305
306
307
308
309
# File 'lib/ruic/presentation.rb', line 300

def at(path,root=@graph)
	name,path = path.split('.',2)
	root = root.el if root.respond_to?(:el)
	el = case name
		when 'parent' then root==@scene ? nil : root.parent
		when 'Scene'  then @scene
		else               root.element_children.find{ |el| asset_for_el(el).name==name }
	end
	path ? at(path,el) : asset_for_el(el) if el
end

#attribute_linked?(asset, attribute_name) ⇒ Boolean

Returns true if this asset's attribute is linked on the master slide.

Examples:

preso  = app.main
camera = preso/"Scene.Layer.Camera"

# Two ways of determining if an attribute for an asset is linked.
if preso.attribute_linked?( camera, 'fov' )
if camera['fov'].linked?

Returns:

  • (Boolean)

    true if this asset's attribute is linked on the master slide.

See Also:



445
446
447
448
# File 'lib/ruic/presentation.rb', line 445

def attribute_linked?( asset, attribute_name )
	graph_element = asset.el
	!(@addsets_by_graph[graph_element] && @addsets_by_graph[graph_element][1] && @addsets_by_graph[graph_element][1].key?(attribute_name))
end

#behaviorsArray<MetaData::AssetBase>

Returns array of behavior elements in the presentation.

Returns:



609
# File 'lib/ruic/presentation.rb', line 609

def behaviors; find _type:'Behavior'; end

#camerasArray<MetaData::AssetBase>

Returns array of cameras in the presentation.

Returns:



586
# File 'lib/ruic/presentation.rb', line 586

def cameras; find _type:'Camera'; end

#child_assets(parent_asset) ⇒ Array<MetaData::AssetBase>

Returns array of scene graph children of the specified asset.

Parameters:

Returns:

See Also:



131
132
133
# File 'lib/ruic/presentation.rb', line 131

def child_assets( parent_asset )
	parent_asset.el.element_children.map{ |child| asset_for_el(child) }
end

#componentsArray<MetaData::AssetBase>

Returns array of components in the presentation (not including the Scene).

Returns:

  • (Array<MetaData::AssetBase>)

    array of components in the presentation (not including the Scene).



592
# File 'lib/ruic/presentation.rb', line 592

def components; find _type:'Component'; end

#effectsArray<MetaData::AssetBase>

Returns array of effects in the presentation.

Returns:



580
# File 'lib/ruic/presentation.rb', line 580

def effects; find _type:'Effect'; end

#errorsArray<String>

Returns an array (possibly empty) of all errors in this presentation.

Returns:

  • (Array<String>)

    an array (possibly empty) of all errors in this presentation.



274
275
276
# File 'lib/ruic/presentation.rb', line 274

def errors
	@errors
end

#errors?Boolean

Returns true if there any errors with the presentation.

Returns:

  • (Boolean)

    true if there any errors with the presentation.



269
270
271
# File 'lib/ruic/presentation.rb', line 269

def errors?
	(!errors.empty?)
end

#find(criteria = {}) {|asset, index| ... } ⇒ Array<MetaData::AssetBase>

Find assets in this presentation matching criteria.

Examples:

1) Searching for simple values

every_asset   = preso.find                          # Every asset in the presentation
master_assets = preso.find _master:true             # Test for master/nonmaster
models        = preso.find _type:'Model'            # …or based on type
slide2_assets = preso.find _slide:2                 # …or presence on a specific slide
rectangles    = preso.find sourcepath:'#Rectangle'  # …or attribute values
gamecovers    = preso.find name:'Game Cover'        # …including the name

2) Combine tests to get more specific

master_models = preso.find _type:'Model', _master:true
slide2_rects  = preso.find _type:'Model', _slide:2, sourcepath:'#Rectangle'
nonmaster_s2  = preso.find _slide:2, _master:false
red_materials = preso.find _type:'Material', diffuse:[1,0,0]

3) Matching values more loosely

pistons       = preso.find name:/^Piston/           # Regex for batch finding
bottom_row    = preso.find position:[nil,-200,nil]  # nil for wildcards in vectors

4) Restrict the search to a sub-tree

group        = preso/"Scene.Layer.Group"
group_models = preso.find _under:group, _type:'Model'  # All models under the group
group_models = group.find _type:'Model'                # alternatively start from the asset

5) Iterate the results as they are found

preso.find _type:'Model', name:/^Piston/ do |model, index|
   show "Model #{index} is named #{model.name}"
end

# You do not need to receive the index if you do not need its value
group.find _type:'Model' do |model|
   scale = model['scale'].value
   scale.x = scale.y = scale.z = 1
end

Parameters:

  • criteria (Hash) (defaults to: {})

    Attribute names and values, along with a few special keys.

Options Hash (criteria):

  • :_type (String)

    asset must be of specified type, e.g. "Model" or "Material" or "PathAnchorPoint".

  • :_slide (Integer, String)

    slide number or name that the asset must be present on.

  • :_master (Boolean)

    true for only master assets, false for only non-master assets.

  • :_under (MetaData::AssetBase)

    a root asset to require as an ancestor; this asset will never be in the search results.

  • :attribute_name (Numeric)

    numeric attribute value must be within 0.001 of the supplied value.

  • :attribute_name (String)

    string attribute value must match the supplied string exactly.

  • :attribute_name (Regexp)

    supplied regex must match the string attribute value.

  • :attribute_name (Array)

    each component of the attribute's vector value must be within 0.001 of the supplied value in the array; if a value in the array is nil that component of the vector may have any value.

Yields:

  • (asset, index)

    Yields each found asset (and its index in the results) to the block (if supplied) as they are found.

Returns:

See Also:



547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/ruic/presentation.rb', line 547

def find(criteria={},&block)
	index = -1
	start = criteria.key?(:_under) ? criteria.delete(:_under).el : @graph
	[].tap do |result|
		start.xpath('./descendant::*').each do |el|
			asset = asset_for_el(el)
			next unless criteria.all? do |att,val|
				case att
					when :_type   then el.name == val
					when :_slide  then has_slide?(asset,val)
					when :_master then master?(asset)==val
					else
						if asset.properties[att.to_s]
							value = asset[att.to_s].value
							case val
								when Regexp  then val =~ value.to_s
								when Numeric then (val-value).abs < 0.001
								when Array   then value.to_a.zip(val).map{ |a,b| !b || (a-b).abs<0.001 }.all?
								else value == val
							end
						end
				end
			end
			yield asset, index+=1 if block_given?
			result << asset
		end
	end
end

#generate_custom_classesnil

Scan the .uip for custom classes that will be needed to generate assets. Called once during initial load of the file.

Returns:

  • (nil)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ruic/presentation.rb', line 46

def generate_custom_classes
	# TODO: this method assumes an application to find the metadata on; the metadata should be part of this class instance instead, shared with the app when present
	parent_class_name = {
		'CustomMaterial' => 'MaterialBase',
		'Effect'         => 'Effect',
		'Behavior'       => 'Behavior',
		'RenderPlugin'   => 'RenderPlugin'
	}
	@class_by_ref = {}
	@doc.xpath('/UIP/Project/Classes/*').each do |reference|
		path = absolute_path( reference['sourcepath'] )
		next unless File.exist?( path )
		parent_class = app..by_name[ parent_class_name[reference.name] ]
		raise "Error, unsupported custom class #{reference.name}" unless parent_class
		parent_props = parent_class.properties
		new_defaults = Hash[ reference.attributes.map{ |name,attr| [name,attr.value] }.select{ |name,val| parent_props[name] } ]
		property_el = case reference.name
			when 'CustomMaterial', 'Effect', 'RenderPlugin'
				doc = Nokogiri.XML(File.read(path,encoding:'utf-8'))
				doc.at('/*/MetaData') || doc.at('/*/metadata') # Some render plugins in the wild use lower-case tag name :/
			when 'Behavior'
				lua  = File.read(path,encoding:'utf-8')
				meta = lua[ /--\[\[(.+?)(?:--)?\]\]/m, 1 ]
				Nokogiri.XML("<MetaData>#{meta}</MetaData>").root
		end
		@class_by_ref[ "##{reference['id']}" ] = app..create_class( property_el, parent_class, reference.name, new_defaults )
	end
	nil
end

#get_attribute(asset, attr_name, slide_name_or_index) ⇒ Object

Fetch the value of an asset's attribute on a particular slide. Slide 0 is the Master Slide, slide 1 is the first non-master slide.

This method is used internally by assets; accessing attributes directly from the asset is generally more appropriate.

Examples:

preso = app.main_presentation
camera = preso/"Scene.Layer.Camera"

assert preso.get_attribute(camera,'position',0) == camera['position',0]

Parameters:

  • asset (MetaData::AssetBase)

    the asset to fetch the attribute for.

  • attr_name (String)

    the name of the attribute to get the value of.

  • slide_name_or_index (String, Integer)

    the string name or integer index of the slide.

Returns:

  • (Object)

    the value of the asset on the slide

See Also:



327
328
329
330
331
332
333
334
# File 'lib/ruic/presentation.rb', line 327

def get_attribute( asset, attr_name, slide_name_or_index )
	graph_element = asset.el
	((addsets=@addsets_by_graph[graph_element]) && ( # State (slide) don't have any addsets
		( addsets[slide_name_or_index] && addsets[slide_name_or_index][attr_name] ) || # Try for a Set on the specific slide
		( addsets[0] && addsets[0][attr_name] ) # …else try the master slide
	) || graph_element[attr_name]) # …else try the graph
	# TODO: handle animation (child of addset)
end

#groupsArray<MetaData::AssetBase>

Returns array of groups in the presentation.

Returns:



583
# File 'lib/ruic/presentation.rb', line 583

def groups; find _type:'Group'; end

#has_slide?(asset, slide_name_or_index) ⇒ Boolean

Returns true if the asset exists on the supplied slide.

Returns:

  • (Boolean)

    true if the asset exists on the supplied slide.

See Also:



425
426
427
428
429
430
431
432
433
# File 'lib/ruic/presentation.rb', line 425

def has_slide?( asset, slide_name_or_index )
	graph_element = asset.el
	if graph_element == @scene
		# The scene is never actually added, so we'll treat it just like the first add, which is on the master slide of the scene
		has_slide?( asset_for_el( @addsets_by_graph.first.first ), slide_name_or_index )
	else
		@addsets_by_graph[graph_element][slide_name_or_index] || @addsets_by_graph[graph_element][0]
	end
end

#hierarchy(root = scene) ⇒ String

Returns a visual hierarchy under the specified asset.

Parameters:

Returns:

  • (String)

    a visual hierarchy under the specified asset.



625
626
627
628
629
630
631
632
# File 'lib/ruic/presentation.rb', line 625

def hierarchy( root=scene )
	elide = ->(str){ str.length>64 ? str.sub(/(^.{30}).+?(.{30})$/,'\1...\2') : str }
	hier = UIC.tree_hierarchy(root){ |e| e.children }
	cols = hier.map{ |i,a| a ? [ [i,a.name].join, a.type, elide[a.path] ] : [i,"",""] }
	maxs = cols.transpose.map{ |col| col.map(&:length).max }
	tmpl = maxs.map{ |n| "%-#{n}s" }.join('  ')
	cols.map{ |a| tmpl % a }.join("\n").extend(RUIC::SelfInspecting)
end

#image_pathsArray<String>

Returns array of all image paths referenced by this presentation.

Returns:

  • (Array<String>)

    array of all image paths referenced by this presentation.



171
172
173
# File 'lib/ruic/presentation.rb', line 171

def image_paths
	image_usage.keys
end

#image_usageHash

Returns a mapping of image paths to arrays of the assets referencing them.

Returns:

  • (Hash)

    a mapping of image paths to arrays of the assets referencing them.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/ruic/presentation.rb', line 141

def image_usage
	# TODO: this returns the same asset multiple times, with no indication of which property is using it; should switch to an Asset/Property pair, or some such.
	asset_types = app..by_name.values + @class_by_ref.values

	image_properties_by_type = asset_types.flat_map do |type|
		type.properties.values
		    .select{ |property| property.type=='Image' || property.type == 'Texture' }
		    .map{ |property| [type,property] }
	end.group_by(&:first).tap{ |x| x.each{ |t,a| a.map!(&:last) } }

	Hash[ assets.each_with_object({}) do |asset,usage|
		if properties = image_properties_by_type[asset.class]
			properties.each do |property|
				asset[property.name].values.compact.each do |value|
					value = value['sourcepath'] if property.type=='Image'
					unless value.nil? || value.empty?
						value = value.gsub('\\','/').sub(/^.\//,'')
						usage[value] ||= []
						usage[value] << asset
					end
				end
			end
		end
	end.sort_by do |path,assets|
		parts = path.downcase.split '/'
		[ parts.length, parts ]
	end ].tap{ |h| h.extend(UIC::PresentableHash) }
end

#imagesArray<MetaData::AssetBase>

Returns array of image elements in the presentation.

Returns:



606
# File 'lib/ruic/presentation.rb', line 606

def images; find _type:'Image'; end

#layersArray<MetaData::AssetBase>

Returns array of layers in the presentation.

Returns:



577
# File 'lib/ruic/presentation.rb', line 577

def layers; find _type:'Layer'; end

#lightsArray<MetaData::AssetBase>

Returns array of lights in the presentation.

Returns:



589
# File 'lib/ruic/presentation.rb', line 589

def lights; find _type:'Light'; end

#master?(asset) ⇒ Boolean

Returns true if the asset is added on the master slide.

Returns:

  • (Boolean)

    true if the asset is added on the master slide.

See Also:



490
491
492
493
# File 'lib/ruic/presentation.rb', line 490

def master?(asset)
	graph_element = asset.el
	(graph_element == @scene) || !!(@addsets_by_graph[graph_element] && @addsets_by_graph[graph_element][0])
end

#materialsArray<MetaData::AssetBase>

Returns array of materials in the presentation (includes Referenced and Custom Materials).

Returns:

  • (Array<MetaData::AssetBase>)

    array of materials in the presentation (includes Referenced and Custom Materials).



599
600
601
602
603
# File 'lib/ruic/presentation.rb', line 599

def materials
	# Loop through all assets so that the resulting array of multiple sub-classes is in scene graph order
	material = app..by_name['MaterialBase']
	find.select{ |asset| asset.is_a?(material) }
end

#modelsArray<MetaData::AssetBase> Also known as: meshes

Returns array of model nodes in the presentation.

Returns:



595
# File 'lib/ruic/presentation.rb', line 595

def models; find _type:'Model'; end

#on_doc_loadednil

Load information for the presentation from disk. If you supply a path to a .uip file when creating the presentation this method is automatically called.

Returns:

  • (nil)


25
26
27
28
29
30
31
32
33
34
# File 'lib/ruic/presentation.rb', line 25

def on_doc_loaded
	@graph = @doc.at('Graph')
	@scene = @graph.at('Scene')
	@logic = @doc.at('Logic')

	generate_custom_classes
	rebuild_caches_from_document

	nil
end

#owning_component(asset) ⇒ MetaData::AssetBase

Returns the component (or Scene) asset that owns the supplied asset.

Returns:

See Also:



379
380
381
# File 'lib/ruic/presentation.rb', line 379

def owning_component( asset )
	asset_for_el( owning_component_element( asset.el ) )
end

#parent_asset(child_asset) ⇒ MetaData::AssetBase

Returns the scene graph parent of the child asset, or nil for the Scene.

Parameters:

Returns:

See Also:



121
122
123
124
125
126
# File 'lib/ruic/presentation.rb', line 121

def parent_asset( child_asset )
	child_graph_el = child_asset.el
	unless child_graph_el==@scene || child_graph_el.parent.nil?
		asset_for_el( child_graph_el.parent )
	end
end

#path_to(asset, from_asset = nil) ⇒ String

Generate the script path for an asset in the presentation.

  • If from_asset is supplied the path will be relative to that asset (e.g. "parent.parent.Group.Model").
  • If from_asset is omitted the path will be absolute (e.g. "Scene.Layer.Group.Model").

This is used internally by MetaData::AssetBase#path and MetaData::AssetBase#path_to; those methods are usually more convenient to use.

Examples:

preso = app.main
preso.scene.children.each{ |child| show preso.path_to(child) }
#=> "main:Scene.MyAppBehavior"
#=> "main:Scene.UILayer"
#=> "main:Scene.ContentLayer"
#=> "main:Scene.BGLayer"

Parameters:

Returns:

  • (String)

    the script path to the element.

See Also:



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/ruic/presentation.rb', line 240

def path_to( asset, from_asset=nil )
	el = asset.el

	to_parts = if el.ancestors('Graph')
		[].tap{ |parts|
			until el==@graph
				parts.unshift asset_for_el(el).name
				el = el.parent
			end
		}
	end
	if from_asset && from_asset.el.ancestors('Graph')
		from_el = from_asset.el
		from_parts = [].tap{ |parts|
			until from_el==@graph
				parts.unshift asset_for_el(from_el).name
				from_el = from_el.parent
			end
		}
		until to_parts.empty? || from_parts.empty? || to_parts.first!=from_parts.first
			to_parts.shift
			from_parts.shift
		end
		to_parts.unshift *(['parent']*from_parts.length)
	end
	to_parts.join('.')
end

#pathsArray<MetaData::AssetBase>

Returns array of path nodes in the presentation.

Returns:



615
# File 'lib/ruic/presentation.rb', line 615

def paths; find _type:'Path'; end

#rebuild_caches_from_documentnil

Update the presentation to be in-sync with the document. Must be called whenever the in-memory representation of the XML document is changed. Called automatically by all necessary methods; only necessary if script (dangerously) manipulates the .doc of the presentation directly.

Returns:

  • (nil)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ruic/presentation.rb', line 82

def rebuild_caches_from_document
	@graph_by_id = {}
	@scene.traverse{ |x| @graph_by_id[x['id']]=x if x.is_a?(Nokogiri::XML::Element) }

	@graph_by_addset  = {}
	@addsets_by_graph = {}
	slideindex = {}
	@logic.xpath('.//Add|.//Set').each do |addset|
		graph = @graph_by_id[addset['ref'][1..-1]]
		@graph_by_addset[addset] = graph
		@addsets_by_graph[graph] ||= {}
		slide = addset.parent
		name  = slide['name']
		index = name == 'Master Slide' ? 0 : (slideindex[slide] ||= (slide.index('State') + 1))
		@addsets_by_graph[graph][name]  = addset
		@addsets_by_graph[graph][index] = addset
	end
	nil
end

#referenced_filesArray<String>

Which files are used by the presentation.

Returns:

  • (Array<String>)

    array of absolute file paths referenced by this presentation.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/ruic/presentation.rb', line 190

def referenced_files
	(
		[file] +
		%w[sourcepath importfile].flat_map do |att|
			find(att=>/./).flat_map do |asset|
				asset[att].values.compact.map do |path|
					path.sub!(/#.+/,'')
					absolute_path(path) unless path.empty?
				end.compact
			end
		end +
		find.flat_map do |asset|
			asset.properties.select{ |name,prop| prop.type=='Texture' }.flat_map do |name,prop|
				asset[name].values.compact.uniq.map{ |path| absolute_path(path) }
			end
		end +
		find(_type:'Text').flat_map do |asset|
			asset['font'].values.compact.map{ |font| absolute_path(font) }
		end +
		@doc.xpath('/UIP/Project/Classes/*/@sourcepath').map{ |att| absolute_path att.value }
	).uniq
end

#replace_asset(existing_asset, new_type, attributes = {}) ⇒ MetaData::AssetBase

Replace an existing asset with a new kind of asset.

Parameters:

  • existing_asset (MetaData::AssetBase)

    the existing asset to replace.

  • new_type (String)

    the name of the asset type, e.g. "ReferencedMaterial" or "Group".

  • attributes (Hash) (defaults to: {})

    initial attribute values for the new asset.

Returns:



476
477
478
479
480
481
482
483
484
485
486
# File 'lib/ruic/presentation.rb', line 476

def replace_asset( existing_asset, new_type, attributes={} )
	old_el = existing_asset.el
	new_el = old_el.replace( "<#{new_type}/>" ).first
	attributes['id'] = old_el['id']
	attributes.each{ |att,val| new_el[att.to_s] = val }
	asset_for_el( new_el ).tap do |new_asset|
		unsupported_attributes = ".//*[name()='Add' or name()='Set'][@ref='##{old_el['id']}']/@*[name()!='ref' and #{new_asset.properties.keys.map{|p| "name()!='#{p}'"}.join(' and ')}]"
		@logic.xpath(unsupported_attributes).remove
		rebuild_caches_from_document
	end
end

#sceneMetaData::Scene

Returns the root scene asset for the presentation.

Returns:

  • (MetaData::Scene)

    the root scene asset for the presentation.



214
215
216
# File 'lib/ruic/presentation.rb', line 214

def scene
	asset_for_el( @scene )
end

#set_attribute(asset, property_name, slide_name_or_index, str) ⇒ Object

Set the value of an asset's attribute on a particular slide. Slide 0 is the Master Slide, slide 1 is the first non-master slide.

This method is used internally by assets; accessing attributes directly from the asset is generally more appropriate.

Examples:

preso = app.main_presentation
camera = preso/"Scene.Layer.Camera"

# The long way to set the attribute value
preso.set_attribute(camera,'endtime',0,1000)

# …and the shorter way
camera['endtime',0] = 1000

Parameters:

  • asset (MetaData::AssetBase)

    the asset to fetch the attribute for.

  • attr_name (String)

    the name of the attribute to get the value of.

  • slide_name_or_index (String, Integer)

    the string name or integer index of the slide.

See Also:



354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/ruic/presentation.rb', line 354

def set_attribute( asset, property_name, slide_name_or_index, str )
	graph_element = asset.el
	if attribute_linked?( asset, property_name )
		if @addsets_by_graph[graph_element]
			@addsets_by_graph[graph_element][0][property_name] = str
		else
			raise "TODO"
		end
	else
		if @addsets_by_graph[graph_element]
			if slide_name_or_index
				@addsets_by_graph[graph_element][slide_name_or_index][property_name] = str
			else
				master = master_slide_for( graph_element )
				slide_count = master.xpath('count(./State)').to_i
				0.upto(slide_count).each{ |idx| set_attribute(asset,property_name,idx,str) }
			end
		else
			raise "TODO"
		end
	end
end

#slide_index(asset) ⇒ Integer

Returns the index of the first slide where an asset is added (0 for master, non-zero for non-master).

Parameters:

Returns:

  • (Integer)

    the index of the first slide where an asset is added (0 for master, non-zero for non-master).



111
112
113
114
115
116
# File 'lib/ruic/presentation.rb', line 111

def slide_index(asset)
	# TODO: probably faster to .find the first @addsets_by_graph
	id = asset.el['id']
	slide = @logic.at(".//Add[@ref='##{id}']/..")
	(slide ? slide.xpath('count(ancestor::State) + count(preceding-sibling::State[ancestor::State])').to_i : 0) # the Scene is never added
end

#slides_for(asset) ⇒ SlideCollection

Returns an array-like collection of all slides that the asset is available on.

Parameters:

Returns:

  • (SlideCollection)

    an array-like collection of all slides that the asset is available on.

See Also:



411
412
413
414
415
416
417
418
419
420
421
# File 'lib/ruic/presentation.rb', line 411

def slides_for( asset )
	graph_element = asset.el
	@slides_for[graph_element] ||= begin
		slides = []
		master = master_slide_for( graph_element )
		slides << [master,0] if graph_element==@scene || (@addsets_by_graph[graph_element] && @addsets_by_graph[graph_element][0])
		slides.concat( master.xpath('./State').map.with_index{ |el,i| [el,i+1] } )
		slides.map!{ |el,idx| @slides_by_el[el] ||= app..new_instance(self,el).tap{ |s| s.index=idx; s.name=el['name'] } }
		UIC::SlideCollection.new( slides )
	end
end

#textsArray<MetaData::AssetBase>

Returns array of text elements in the presentation.

Returns:



621
# File 'lib/ruic/presentation.rb', line 621

def texts; find _type:'Text'; end

#to_xmlString

Returns the xml representation of this presentation. Formatted to match UI Composer Studio's formatting as closely as possible (for minimal diffs after update).

Returns:

  • (String)

    the xml representation of this presentation. Formatted to match UI Composer Studio's formatting as closely as possible (for minimal diffs after update).



37
38
39
40
41
# File 'lib/ruic/presentation.rb', line 37

def to_xml
	doc.to_xml( indent:1, indent_text:"\t" )
	   .gsub( %r{(<\w+(?: [\w:]+="[^"]*")*)(/?>)}i, '\1 \2' )
	   .sub('"?>','" ?>')
end

Unlinks a master attribute, yielding distinct values on each slide. If the asset is not on the master slide, or the attribute is already unlinked, no change occurs.

Parameters:

  • asset (MetaData::AssetBase)

    the master asset to unlink the attribute on.

  • attribute_name (String)

    the name of the attribute to unlink.

Returns:

  • (Boolean)

    true if the attribute was previously linked; false otherwise.



455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/ruic/presentation.rb', line 455

def unlink_attribute(asset,attribute_name)
	graph_element = asset.el
	if master?(asset) && attribute_linked?(asset,attribute_name)
		master_value = get_attribute( asset, attribute_name, 0 )
		slides_for( asset ).to_ary[1..-1].each do |slide|
			addset = slide.el.at_xpath( ".//*[@ref='##{graph_element['id']}']" ) || slide.el.add_child("<Set ref='##{graph_element['id']}'/>").first
			addset[attribute_name] = master_value
		end
		rebuild_caches_from_document
		true
	else
		false
	end
end