RUIC 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +201 -0
- data/bin/ruic +52 -0
- data/gui/MetaData.xml +387 -0
- data/gui/TODO +2 -0
- data/gui/appattributesmodel.rb +51 -0
- data/gui/appelementsmodel.rb +126 -0
- data/gui/launch.rb +20 -0
- data/gui/makefile +14 -0
- data/gui/resources.qrc +37 -0
- data/gui/resources/images/Objects-Behavior-Normal.png +0 -0
- data/gui/resources/images/Objects-Camera-Normal.png +0 -0
- data/gui/resources/images/Objects-Component-Normal.png +0 -0
- data/gui/resources/images/Objects-Effect-Normal.png +0 -0
- data/gui/resources/images/Objects-Group-Normal.png +0 -0
- data/gui/resources/images/Objects-Image-Normal.png +0 -0
- data/gui/resources/images/Objects-Layer-Normal.png +0 -0
- data/gui/resources/images/Objects-Light-Normal.png +0 -0
- data/gui/resources/images/Objects-Material-Normal.png +0 -0
- data/gui/resources/images/Objects-Model-Normal.png +0 -0
- data/gui/resources/images/Objects-Music-Normal.png +0 -0
- data/gui/resources/images/Objects-Property-Normal.png +0 -0
- data/gui/resources/images/Objects-References-Normal.png +0 -0
- data/gui/resources/images/Objects-Scene-Normal.png +0 -0
- data/gui/resources/images/Objects-Sound-Normal.png +0 -0
- data/gui/resources/images/Objects-Text-Normal.png +0 -0
- data/gui/resources/images/Objects-Unknown-Normal.png +0 -0
- data/gui/resources/images/Objects-Video-Normal.png +0 -0
- data/gui/resources/images/SCXML.ico +0 -0
- data/gui/resources/images/TSCXML.ico +0 -0
- data/gui/resources/images/UIA.ico +0 -0
- data/gui/resources/images/clipboard.png +0 -0
- data/gui/resources/images/console_arrow.png +0 -0
- data/gui/resources/images/cross.png +0 -0
- data/gui/resources/images/currentline.png +0 -0
- data/gui/resources/images/disk-black.png +0 -0
- data/gui/resources/images/disks-black.png +0 -0
- data/gui/resources/images/document--plus.png +0 -0
- data/gui/resources/images/document-copy.png +0 -0
- data/gui/resources/images/executable-actions-delete-active.png +0 -0
- data/gui/resources/images/executable-actions-delete-idle.png +0 -0
- data/gui/resources/images/executable-actions-enter-badge.png +0 -0
- data/gui/resources/images/executable-actions-exit-badge.png +0 -0
- data/gui/resources/images/folder-horizontal--plus.png +0 -0
- data/gui/resources/images/folder-horizontal-open.png +0 -0
- data/gui/resources/images/gear.png +0 -0
- data/gui/resources/images/invalid_breakpoint.png +0 -0
- data/gui/resources/images/scissors-blue.png +0 -0
- data/gui/resources/images/slide-16-active.png +0 -0
- data/gui/resources/images/slide-16-master.png +0 -0
- data/gui/resources/images/slide-16-normal.png +0 -0
- data/gui/resources/images/slide-32-active.png +0 -0
- data/gui/resources/images/slide-32-master.png +0 -0
- data/gui/resources/images/slide-32-normal.png +0 -0
- data/gui/resources/images/studio_architect32.ico +0 -0
- data/gui/resources/images/studio_architect32.png +0 -0
- data/gui/resources/images/textfile_icon.png +0 -0
- data/gui/resources/style/checkbox.png +0 -0
- data/gui/resources/style/dark.qss +459 -0
- data/gui/resources/style/down_arrow.png +0 -0
- data/gui/resources/style/handle.png +0 -0
- data/gui/window.rb +90 -0
- data/gui/window.ui +753 -0
- data/lib/ruic.rb +59 -0
- data/lib/ruic/application.rb +129 -0
- data/lib/ruic/asset_classes.rb +448 -0
- data/lib/ruic/behaviors.rb +31 -0
- data/lib/ruic/interfaces.rb +36 -0
- data/lib/ruic/presentation.rb +354 -0
- data/lib/ruic/statemachine.rb +111 -0
- data/lib/ruic/version.rb +3 -0
- data/ruic.gemspec +23 -0
- data/test/MetaData.xml +387 -0
- data/test/customclasses.ruic +21 -0
- data/test/filtering.ruic +39 -0
- data/test/nonmaster.ruic +21 -0
- data/test/projects/CustomClasses/Brush Strokes.effect +38 -0
- data/test/projects/CustomClasses/CustomClasses.uia +6 -0
- data/test/projects/CustomClasses/CustomClasses.uip +34 -0
- data/test/projects/CustomClasses/copper.material +194 -0
- data/test/projects/CustomClasses/maps/UV-Checker.png +0 -0
- data/test/projects/CustomClasses/maps/effects/brushnoise.dds +0 -0
- data/test/projects/CustomClasses/maps/materials/spherical_checker.png +0 -0
- data/test/projects/ReferencedMaterials/ReferencedMaterials.uia +6 -0
- data/test/projects/ReferencedMaterials/ReferencedMaterials.uip +39 -0
- data/test/properties.ruic +81 -0
- data/test/referencematerials.ruic +53 -0
- data/test/usage.ruic +20 -0
- metadata +166 -0
data/lib/ruic.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
class RUIC; end
|
3
|
+
module UIC; end
|
4
|
+
|
5
|
+
require 'nokogiri'
|
6
|
+
require_relative 'ruic/version'
|
7
|
+
require_relative 'ruic/asset_classes'
|
8
|
+
require_relative 'ruic/interfaces'
|
9
|
+
require_relative 'ruic/application'
|
10
|
+
require_relative 'ruic/behaviors'
|
11
|
+
require_relative 'ruic/statemachine'
|
12
|
+
require_relative 'ruic/presentation'
|
13
|
+
|
14
|
+
class RUIC
|
15
|
+
DEFAULTMETADATA = 'C:/Program Files (x86)/NVIDIA Corporation/UI Composer 8.0/res/DataModelMetadata/en-us/MetaData.xml'
|
16
|
+
def self.run(ruic_path)
|
17
|
+
script = File.read(ruic_path,encoding:'utf-8')
|
18
|
+
Dir.chdir(File.dirname(ruic_path)) do
|
19
|
+
self.new.instance_eval(script,ruic_path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
def initialize( metadata=DEFAULTMETADATA )
|
23
|
+
@metadata = metadata
|
24
|
+
@apps = {}
|
25
|
+
end
|
26
|
+
def metadata(path)
|
27
|
+
@metadata = path
|
28
|
+
end
|
29
|
+
def uia(path)
|
30
|
+
meta = UIC.Meta @metadata
|
31
|
+
name = @apps.empty? ? :app : :"app#{@apps.length+1}"
|
32
|
+
@apps[name] = UIC.App(meta,path)
|
33
|
+
end
|
34
|
+
def method_missing(name,*a)
|
35
|
+
@apps[name] || super
|
36
|
+
end
|
37
|
+
def assert(condition=:CONDITIONNOTSUPPLIED,msg=nil,&block)
|
38
|
+
if block && condition==:CONDITIONNOTSUPPLIED || condition.is_a?(String)
|
39
|
+
msg = condition.is_a?(String) ? condition : yield
|
40
|
+
condition = msg.is_a?(String) ? eval(msg,block.binding) : msg
|
41
|
+
end
|
42
|
+
unless condition
|
43
|
+
file, line, _ = caller.first.split(':')
|
44
|
+
puts "#{msg && "#{msg} : "}assertion failed (#{file} line #{line})"
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def show(*a); puts *a.map(&:to_s); end
|
49
|
+
end
|
50
|
+
|
51
|
+
def RUIC(file_path=nil,&block)
|
52
|
+
if block
|
53
|
+
Dir.chdir(File.dirname($0)) do
|
54
|
+
RUIC.new.instance_eval(&block)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
RUIC.run(file_path)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
class UIC::Application
|
2
|
+
include UIC::FileBacked
|
3
|
+
|
4
|
+
attr_reader :metadata
|
5
|
+
def initialize(metadata,uia_path)
|
6
|
+
@metadata = metadata
|
7
|
+
self.file = uia_path
|
8
|
+
load_from_file if file_found?
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_from_file
|
12
|
+
self.doc = Nokogiri.XML(File.read(file,encoding:'utf-8'))
|
13
|
+
@assets = @doc.search('assets *').map do |el|
|
14
|
+
case el.name
|
15
|
+
when 'behavior' then UIC::Application::Behavior
|
16
|
+
when 'statemachine' then UIC::Application::StateMachine
|
17
|
+
when 'presentation' then UIC::Application::Presentation
|
18
|
+
when 'renderplugin' then UIC::Application::RenderPlugin
|
19
|
+
end.new(self,el)
|
20
|
+
end.group_by{ |asset| asset.el.name }
|
21
|
+
end
|
22
|
+
|
23
|
+
def errors?
|
24
|
+
!errors.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def errors
|
28
|
+
file_found? ? assets.flat_map(&:errors) : ["File not found: '#{file}'"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](asset_id_or_path)
|
32
|
+
all = assets
|
33
|
+
if asset_id_or_path.start_with?('#')
|
34
|
+
id = asset_id_or_path[1..-1]
|
35
|
+
all.find{ |asset| asset.id==id }
|
36
|
+
else
|
37
|
+
full_path = File.expand_path(asset_id_or_path,File.dirname(file))
|
38
|
+
all.find{ |asset| asset.file==full_path }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def unused_files
|
43
|
+
referenced_files - directory_files
|
44
|
+
end
|
45
|
+
|
46
|
+
def referenced_files
|
47
|
+
# TODO: state machines can reference external scripts
|
48
|
+
# TODO: behaviors can reference external scripts
|
49
|
+
assets.map{ |asset| path_to(asset.src) }
|
50
|
+
+ presentations.flat_map{ |pres| pres.presentation.referenced_files }
|
51
|
+
end
|
52
|
+
|
53
|
+
def assets
|
54
|
+
@assets.values.inject(:+)
|
55
|
+
end
|
56
|
+
|
57
|
+
def main_presentation
|
58
|
+
initial_id = @doc.at('assets')['initial']
|
59
|
+
presos = presentations
|
60
|
+
presos.find{ |pres| pres.id==initial_id } || presos.first
|
61
|
+
end
|
62
|
+
|
63
|
+
def main_presentation=(presentation)
|
64
|
+
# TODO: set to Presentation or PresentationAsset
|
65
|
+
# TODO: create a unique ID if none exists
|
66
|
+
@doc.at('assets')['initial'] = presentation.id
|
67
|
+
end
|
68
|
+
|
69
|
+
def image_usage
|
70
|
+
Hash[
|
71
|
+
(presentations + statemachines)
|
72
|
+
.map(&:image_usage)
|
73
|
+
.inject{ |h1,h2| h1.merge(h2){ |path,els1,els2| [*els1,*els2] } }
|
74
|
+
.sort_by do |path,assets|
|
75
|
+
parts = path.downcase.split '/'
|
76
|
+
[ parts.length, parts ]
|
77
|
+
end
|
78
|
+
].tap{ |h| h.extend(UIC::PresentableHash) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def image_paths
|
82
|
+
image_usage.keys
|
83
|
+
end
|
84
|
+
|
85
|
+
def presentations
|
86
|
+
@assets['presentation'] ||= []
|
87
|
+
end
|
88
|
+
|
89
|
+
def behaviors
|
90
|
+
@assets['behavior'] ||= []
|
91
|
+
end
|
92
|
+
|
93
|
+
def statemachines
|
94
|
+
@assets['statemachine'] ||= []
|
95
|
+
end
|
96
|
+
|
97
|
+
def renderplugins
|
98
|
+
@assets['renderplugin'] ||= []
|
99
|
+
end
|
100
|
+
|
101
|
+
def save_all!
|
102
|
+
# save!
|
103
|
+
presentations.each(&:save!)
|
104
|
+
end
|
105
|
+
|
106
|
+
def at(path)
|
107
|
+
parts = path.split(':')
|
108
|
+
preso = parts.length==2 ? self["##{parts.first}"] : main_presentation
|
109
|
+
raise "Cannot find presentation for #{id}" unless preso
|
110
|
+
preso.at(parts.last)
|
111
|
+
end
|
112
|
+
alias_method :/, :at
|
113
|
+
|
114
|
+
def xml
|
115
|
+
@doc.to_xml
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class << UIC
|
120
|
+
def Application(metadata,uia_path)
|
121
|
+
UIC::Application.new( metadata, uia_path )
|
122
|
+
end
|
123
|
+
alias_method :App, :Application
|
124
|
+
end
|
125
|
+
|
126
|
+
__END__
|
127
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
128
|
+
<application xmlns="http://nvidia.com/uicomposer"><assets/></application>
|
129
|
+
|
@@ -0,0 +1,448 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require 'set'
|
3
|
+
$depth = 0
|
4
|
+
class UIC::Asset
|
5
|
+
class Root
|
6
|
+
@properties = {}
|
7
|
+
class << self
|
8
|
+
attr_reader :name
|
9
|
+
def properties
|
10
|
+
(ancestors[1].respond_to?(:properties) ? ancestors[1].properties : {}).merge(@properties)
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
(@by_name.values - [self]).each{ |klass| yield klass }
|
15
|
+
end
|
16
|
+
include Enumerable
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"<#{@name}>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def properties
|
24
|
+
self.class.properties
|
25
|
+
end
|
26
|
+
|
27
|
+
def at(sub_path)
|
28
|
+
presentation.at(sub_path,@el)
|
29
|
+
end
|
30
|
+
alias_method :/, :at
|
31
|
+
|
32
|
+
attr_accessor :presentation, :el
|
33
|
+
def initialize( presentation, element )
|
34
|
+
@presentation = presentation
|
35
|
+
@el = element
|
36
|
+
end
|
37
|
+
|
38
|
+
def type
|
39
|
+
self.class.name
|
40
|
+
# self.class.name.split('::').last
|
41
|
+
end
|
42
|
+
|
43
|
+
def parent
|
44
|
+
presentation.parent_asset(@el)
|
45
|
+
end
|
46
|
+
|
47
|
+
def children
|
48
|
+
presentation.child_assets(@el)
|
49
|
+
end
|
50
|
+
|
51
|
+
def find(criteria={},&block)
|
52
|
+
criteria[:under] ||= self
|
53
|
+
presentation.find(criteria,&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Find the owning component (even if you are a component)
|
57
|
+
def component
|
58
|
+
presentation.owning_component(@el)
|
59
|
+
end
|
60
|
+
|
61
|
+
def component?
|
62
|
+
@el.name == 'Component'
|
63
|
+
end
|
64
|
+
|
65
|
+
def master?
|
66
|
+
presentation.master?(@el)
|
67
|
+
end
|
68
|
+
|
69
|
+
def slide?
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_slide?(slide_name_or_index)
|
74
|
+
presentation.has_slide?(@el,slide_name_or_index)
|
75
|
+
end
|
76
|
+
|
77
|
+
def slides
|
78
|
+
presentation.slides_for(@el)
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_slide(slide_name_or_index)
|
82
|
+
if has_slide?(slide_name_or_index)
|
83
|
+
UIC::SlideValues.new( self, slide_name_or_index )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def path
|
88
|
+
@path ||= @presentation.path_to(@el)
|
89
|
+
end
|
90
|
+
|
91
|
+
def name
|
92
|
+
properties['name'].get( self, presentation.slide_index(@el) )
|
93
|
+
end
|
94
|
+
|
95
|
+
def name=( new_name )
|
96
|
+
properties['name'].set( self, new_name, presentation.slide_index(@el) )
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get the value(s) of an attribute
|
100
|
+
def [](attribute_name, slide_name_or_index=nil)
|
101
|
+
if property = properties[attribute_name]
|
102
|
+
if slide_name_or_index
|
103
|
+
property.get( self, slide_name_or_index ) if has_slide?(slide_name_or_index)
|
104
|
+
else
|
105
|
+
UIC::ValuesPerSlide.new(@presentation,self,property)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Set the value of an attribute, either across all slides, or on a particular slide
|
111
|
+
# el['foo'] = 42
|
112
|
+
# el['foo',0] = 42
|
113
|
+
def []=( attribute_name, slide_name_or_index=nil, new_value )
|
114
|
+
if property = properties[attribute_name] then
|
115
|
+
property.set(self,new_value,slide_name_or_index)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_xml
|
120
|
+
@el.to_xml
|
121
|
+
end
|
122
|
+
def inspect
|
123
|
+
"<asset #{@el.name}##{@el['id']}>"
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
"<#{type} #{path}>"
|
128
|
+
end
|
129
|
+
|
130
|
+
def ==(other)
|
131
|
+
(self.class==other.class) && (el==other.el)
|
132
|
+
end
|
133
|
+
alias_method :eql?, :==
|
134
|
+
end
|
135
|
+
|
136
|
+
attr_reader :by_name
|
137
|
+
|
138
|
+
HIER = {}
|
139
|
+
%w[Asset Slide Scene].each{ |s| HIER[s] = 'Root' }
|
140
|
+
%w[Node Behavior Effect Image Layer MaterialBase RenderPlugin].each{ |s| HIER[s]='Asset' }
|
141
|
+
%w[Camera Component Group Light Model Text].each{ |s| HIER[s]='Node' }
|
142
|
+
%w[Material ReferencedMaterial].each{ |s| HIER[s]='MaterialBase' }
|
143
|
+
|
144
|
+
def initialize(xml)
|
145
|
+
@by_name = {'Root'=>Root}
|
146
|
+
|
147
|
+
doc = Nokogiri.XML(xml)
|
148
|
+
hack_in_slide_names!(doc)
|
149
|
+
|
150
|
+
HIER.each do |class_name,parent_class_name|
|
151
|
+
parent_class = @by_name[parent_class_name]
|
152
|
+
el = doc.root.at(class_name)
|
153
|
+
@by_name[class_name] = create_class(el,parent_class,el.name)
|
154
|
+
UIC::Asset.const_set( el.name, @by_name[class_name] ) # give the class instance a name by pointing a constant to it :/
|
155
|
+
end
|
156
|
+
|
157
|
+
# Extend well-known classes with script interfaces after they are created
|
158
|
+
@by_name['State'] = @by_name['Slide']
|
159
|
+
@by_name['Slide'].instance_eval do
|
160
|
+
attr_accessor :index, :name
|
161
|
+
define_method :inspect do
|
162
|
+
"<slide ##{index} of #{@el['component'] || @el.parent['component']}>"
|
163
|
+
end
|
164
|
+
define_method(:slide?){ true }
|
165
|
+
end
|
166
|
+
|
167
|
+
refmat = @by_name['ReferencedMaterial']
|
168
|
+
@by_name['MaterialBase'].instance_eval do
|
169
|
+
define_method :replace_with_referenced_material do
|
170
|
+
type=='ReferencedMaterial' ? self : presentation.replace_asset( self, 'ReferencedMaterial', name:name )
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Creates a class from MetaData.xml with accessors for the <Property> listed.
|
176
|
+
# Instances of the class are associated with a presentation and know how to
|
177
|
+
# get/set values in that XML based on value types, slides, defaults.
|
178
|
+
# Also used to create classes from effects, materials, and behavior preambles.
|
179
|
+
def create_class(el,parent_class,name='CustomAsset')
|
180
|
+
Class.new(parent_class) do
|
181
|
+
@name = name
|
182
|
+
@properties = Hash[ el.css("Property").map do |e|
|
183
|
+
type = e['type'] || (e['list'] ? 'String' : 'Float')
|
184
|
+
type = "Float" if type=="float"
|
185
|
+
property = UIC::Property.const_get(type).new(e)
|
186
|
+
[ property.name, UIC::Property.const_get(type).new(e) ]
|
187
|
+
end ]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def new_instance(presentation,el)
|
192
|
+
@by_name[el.name].new(presentation,el)
|
193
|
+
end
|
194
|
+
|
195
|
+
def hack_in_slide_names!(doc)
|
196
|
+
doc.at('Slide') << '<Property name="name" formalName="Name" type="String" default="Slide" hidden="True" />'
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def UIC.Meta(metadata_path)
|
201
|
+
UIC::Asset.new(File.read(metadata_path,encoding:'utf-8'))
|
202
|
+
end
|
203
|
+
|
204
|
+
class UIC::Property
|
205
|
+
class << self; attr_accessor :default; end
|
206
|
+
def initialize(el); @el = el; end
|
207
|
+
def name; @name||=@el['name']; end
|
208
|
+
def type; @type||=@el['type']; end
|
209
|
+
def formal; @formal||=@el['formalName'] || @el['name']; end
|
210
|
+
def min; @el['min']; end
|
211
|
+
def max; @el['max']; end
|
212
|
+
def description; @desc||=@el['description']; end
|
213
|
+
def default; @def ||= (@el['default'] || self.class.default); end
|
214
|
+
def get(asset,slide)
|
215
|
+
if asset.slide? || asset.has_slide?(slide)
|
216
|
+
asset.presentation.get_attribute(asset.el,name,slide) || default
|
217
|
+
end
|
218
|
+
end
|
219
|
+
def set(asset,new_value,slide_name_or_index)
|
220
|
+
asset.presentation.set_attribute(asset.el,name,slide_name_or_index,new_value)
|
221
|
+
end
|
222
|
+
def inspect
|
223
|
+
"<#{type} '#{name}'>"
|
224
|
+
end
|
225
|
+
|
226
|
+
class String < self
|
227
|
+
self.default = ''
|
228
|
+
end
|
229
|
+
MultiLineString = String
|
230
|
+
|
231
|
+
class Float < self
|
232
|
+
self.default = 0.0
|
233
|
+
def get(asset,slide); super.to_f; end
|
234
|
+
end
|
235
|
+
class Long < self
|
236
|
+
self.default = 0
|
237
|
+
def get(asset,slide); super.to_i; end
|
238
|
+
end
|
239
|
+
class Boolean < self
|
240
|
+
self.default = false
|
241
|
+
def get(asset,slide); super=='True'; end
|
242
|
+
def set(asset,new_value,slide_name_or_index)
|
243
|
+
super( asset, new_value ? 'True' : 'False', slide_name_or_index )
|
244
|
+
end
|
245
|
+
end
|
246
|
+
class Vector < self
|
247
|
+
self.default = '0 0 0'
|
248
|
+
def get(asset,slide)
|
249
|
+
VectorValue.new(asset,self,slide,super)
|
250
|
+
end
|
251
|
+
def set(asset,new_value,slide_name_or_index)
|
252
|
+
new_value = new_value.join(' ') if new_value.is_a?(Array)
|
253
|
+
super( asset, new_value, slide_name_or_index )
|
254
|
+
end
|
255
|
+
end
|
256
|
+
Rotation = Vector
|
257
|
+
Color = Vector
|
258
|
+
class Image < self
|
259
|
+
self.default = nil
|
260
|
+
def get(asset,slide)
|
261
|
+
if idref = super
|
262
|
+
result = asset.presentation.asset_by_id( idref[1..-1] )
|
263
|
+
slide ? result.on_slide( slide ) : result
|
264
|
+
end
|
265
|
+
end
|
266
|
+
def set(asset,new_value,slide)
|
267
|
+
raise "Setting image attributes not yet supported"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
class Texture < String
|
271
|
+
def get(asset,slide)
|
272
|
+
if path=super
|
273
|
+
path.empty? ? nil : path
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class ObjectRef < self
|
279
|
+
self.default = nil
|
280
|
+
def get(asset,slide)
|
281
|
+
ref = super
|
282
|
+
type = :absolute
|
283
|
+
obj = nil
|
284
|
+
unless ref=='' || ref.nil?
|
285
|
+
type = ref[0]=='#' ? :absolute : :path
|
286
|
+
ref = type==:absolute ? asset.presentation.asset_by_id( ref[1..-1] ) : asset.presentation.at( ref, asset.el )
|
287
|
+
end
|
288
|
+
ObjectReference.new(asset,self,slide,ref,type)
|
289
|
+
end
|
290
|
+
def set(asset,new_object,slide)
|
291
|
+
get(asset,slide).object = new_object
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
class ObjectReference
|
296
|
+
attr_reader :object, :type
|
297
|
+
def initialize(asset,property,slide,object=nil,type=nil)
|
298
|
+
@asset = asset
|
299
|
+
@name = property.name
|
300
|
+
@slide = slide
|
301
|
+
@object = object
|
302
|
+
@type = type
|
303
|
+
end
|
304
|
+
def object=(new_object)
|
305
|
+
raise "ObjectRef must be set to an asset (not a #{new_object.class.name})" unless new_object.is_a?(UIC::Asset::Root)
|
306
|
+
@object = new_object
|
307
|
+
write_value!
|
308
|
+
end
|
309
|
+
def type=(new_type)
|
310
|
+
raise "ObjectRef types must be either :absolute or :path (not #{new_type.inspect})" unless [:absolute,:path].include?(new_type)
|
311
|
+
@type = new_type
|
312
|
+
write_value!
|
313
|
+
end
|
314
|
+
private
|
315
|
+
def write_value!
|
316
|
+
path = case @object
|
317
|
+
when NilClass then ""
|
318
|
+
else case @type
|
319
|
+
when :absolute then "##{@object.el['id']}"
|
320
|
+
when :path then @asset.presentation.path_to( @object.el, @asset.el ).sub(/^[^:.]+:/,'')
|
321
|
+
# when :root then @asset.presentation.path_to( @object.el ).sub(/^[^:.]+:/,'')
|
322
|
+
end
|
323
|
+
end
|
324
|
+
@asset.presentation.set_attribute( @asset.el, @name, @slide, path )
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
Import = String #TODO: a real class
|
329
|
+
Mesh = String #TODO: a real class
|
330
|
+
Renderable = String #TODO: a real class
|
331
|
+
Font = String #TODO: a real class
|
332
|
+
FontSize = Long
|
333
|
+
|
334
|
+
StringListOrInt = String #TODO: a real class
|
335
|
+
|
336
|
+
class VectorValue
|
337
|
+
attr_reader :x, :y, :z
|
338
|
+
def initialize(asset,property,slide,str)
|
339
|
+
@asset = asset
|
340
|
+
@property = property
|
341
|
+
@slide = slide
|
342
|
+
@x, @y, @z = str.split(/\s+/).map(&:to_f)
|
343
|
+
end
|
344
|
+
def setall
|
345
|
+
@property.set( @asset, to_s, @slide )
|
346
|
+
end
|
347
|
+
def x=(n); @x=n; setall end
|
348
|
+
def y=(n); @y=n; setall end
|
349
|
+
def z=(n); @z=n; setall end
|
350
|
+
alias_method :r, :x
|
351
|
+
alias_method :g, :y
|
352
|
+
alias_method :b, :z
|
353
|
+
alias_method :r=, :x=
|
354
|
+
alias_method :g=, :y=
|
355
|
+
alias_method :b=, :z=
|
356
|
+
def inspect
|
357
|
+
"<#{@asset.path}.#{@property.name}: #{self}>"
|
358
|
+
end
|
359
|
+
def to_s
|
360
|
+
to_a.join(' ')
|
361
|
+
end
|
362
|
+
def to_a
|
363
|
+
[x,y,z]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
class UIC::SlideCollection
|
369
|
+
include Enumerable
|
370
|
+
attr_reader :length
|
371
|
+
def initialize(slides)
|
372
|
+
@length = slides.length-1
|
373
|
+
@slides = slides
|
374
|
+
@lookup = {}
|
375
|
+
slides.each do |s|
|
376
|
+
@lookup[s.index] = s
|
377
|
+
@lookup[s.name] = s
|
378
|
+
end
|
379
|
+
end
|
380
|
+
def each
|
381
|
+
@slides.each{ |s| yield(s) }
|
382
|
+
end
|
383
|
+
def [](index_or_name)
|
384
|
+
@lookup[ index_or_name ]
|
385
|
+
end
|
386
|
+
def inspect
|
387
|
+
"[ #{@slides.map(&:inspect).join ', '} ]"
|
388
|
+
end
|
389
|
+
def to_ary
|
390
|
+
@slides
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
class UIC::ValuesPerSlide
|
395
|
+
def initialize(presentation,asset,property)
|
396
|
+
raise unless presentation.is_a?(UIC::Presentation)
|
397
|
+
raise unless asset.is_a?(UIC::Asset::Root)
|
398
|
+
raise unless property.is_a?(UIC::Property)
|
399
|
+
@preso = presentation
|
400
|
+
@asset = asset
|
401
|
+
@el = asset.el
|
402
|
+
@property = property
|
403
|
+
end
|
404
|
+
def value
|
405
|
+
values.first
|
406
|
+
end
|
407
|
+
def [](slide_name_or_index)
|
408
|
+
@property.get( @asset, slide_name_or_index )
|
409
|
+
end
|
410
|
+
def []=(slide_name_or_index,new_value)
|
411
|
+
@property.set( @asset, new_value, slide_name_or_index )
|
412
|
+
end
|
413
|
+
def linked?
|
414
|
+
@preso.attribute_linked?(@el,@property.name)
|
415
|
+
end
|
416
|
+
def unlink
|
417
|
+
@preso.unlink_attribute( @el, @property.name )
|
418
|
+
end
|
419
|
+
def link
|
420
|
+
@preso.link_attribute( @el, @property.name )
|
421
|
+
end
|
422
|
+
def values
|
423
|
+
@asset.slides.map{ |s| self[s.name] }
|
424
|
+
end
|
425
|
+
def inspect
|
426
|
+
"<Values of '#{@asset.name}.#{@property.name}' across slides>"
|
427
|
+
end
|
428
|
+
alias_method :to_s, :inspect
|
429
|
+
end
|
430
|
+
|
431
|
+
class UIC::SlideValues
|
432
|
+
def initialize( asset, slide )
|
433
|
+
@asset = asset
|
434
|
+
@slide = slide
|
435
|
+
end
|
436
|
+
def [](attribute_name)
|
437
|
+
@asset[attribute_name,@slide]
|
438
|
+
end
|
439
|
+
def []=( attribute_name, new_value )
|
440
|
+
@asset[attribute_name,@slide] = new_value
|
441
|
+
end
|
442
|
+
def method_missing( name, *args, &blk )
|
443
|
+
asset.send(name,*args,&blk)
|
444
|
+
end
|
445
|
+
def inspect
|
446
|
+
"<#{@asset.inspect} on slide #{@slide.inspect}>"
|
447
|
+
end
|
448
|
+
end
|