vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 ---------------------------------------------------------------------------
2 -- Iriel's Virtual Frame Driver - Embedded library
3 --
4 -- Written by Iriel <iriel@vigilance-committee.org>
5 ---------------------------------------------------------------------------
6 -- IMPORTANT: Do not **EDIT** and distribute without changing MAJOR_VERSION
7  
8 IVF_Warnings = false;
9  
10 local lib = {};
11  
12 -- Return the library's current version
13 function lib:GetLibraryVersion()
14 -- You MUST update the major version whenever you make an incompatible
15 -- change
16 local MAJOR_VERSION = "KarlPrototype-2-dev";
17 -- You MUST update the minor version whenever you make a compatible
18 -- change (And check LibActivate is still valid!)
19 local MINOR_VERSION = 618;
20  
21 return MAJOR_VERSION, MINOR_VERSION;
22 end
23  
24 -- Activate a new instance of this library
25 function lib:LibActivate(stub, oldLib, oldList)
26 local maj, min = self:GetLibraryVersion();
27  
28 -- For now there's no migration
29 self:_Initialize();
30  
31 -- nil return makes stub do object copy
32 end
33  
34 ---------------------------------------------------------------------------
35 -- CODE NOTES
36 --
37 -- The single letter variable P is used for the 'merged properties' table
38 -- for a frame, that is the composite table created by stacking the various
39 -- inherited properties under one another.
40  
41 ---------------------------------------------------------------------------
42 -- PROPERTY HANDLERS
43 --
44 -- Property handlers are invoked by the instantiation engine to configure
45 -- newly created frames. They're all called with the same set of parameters:
46 --
47 -- object -- The frame/region object that's being configured.
48 -- key -- The name of the property that triggered the handler.
49 -- value -- The value of the property that triggered the handler.
50 -- props -- The 'processing properties' table, which has the following
51 -- entries:
52 --
53 -- props.engine -- The library instance that's handling instantiation
54 -- props.spec -- The specification object for the current object
55 -- props.name -- The name of the current object
56 -- props.object -- The current object
57 -- props.properties -- The merged properties for the current object
58 -- props:Error(msg) -- An error reporting function
59 -- props.object -- A table of any objects created as properties (such
60 -- as subtextures or fonts), indexed by their property
61 -- name.
62 --
63 -- If a property handler is registered for multiple keys, it is called
64 -- ONCE if any of the keys are defined on the object (or if the registration
65 -- entry has runAlways = true set on it it's called ONCE regardless).
66 --
67 -- Handlers are applied in the order they're registered in the _InitProperties
68 -- method.
69  
70 local function PH_SetValue(object, key, value, props)
71 local methodName = "Set" .. key;
72 local method = object[methodName];
73 if (not method) then
74 error("Missing method '" .. methodName .. "'");
75 end
76 method(object, value);
77 end
78  
79 local function Create_PH_MethodCaller(methodName)
80 return function(object, key, value)
81 local method = object[methodName];
82 if (not method) then
83 error("Missing method '" .. methodName .. "'");
84 end
85 method(object, value);
86 end
87 end
88  
89 local function PH_SetSpecialTexture(object, key, value, props)
90 local tex = props.objects[key];
91 if (not tex) then
92 error("Missing texture");
93 end
94 PH_SetValue(object, key, tex, props);
95 end
96  
97 local function PH_SetSpecialFrame(object, key, value, props)
98 local frame = props.objects[key];
99 if (not frame) then
100 error("Missing frame");
101 end
102 PH_SetValue(object, key, frame, props);
103 end
104  
105 local function Create_PH_SpecialFontSetter(methodName)
106 return function(object, key, value, props)
107 local font = props.objects[key];
108 PH_SetValue(object, methodName, font, props);
109 end
110 end
111  
112 local function Create_PH_HTMLFontSetter(whichFont)
113 return function(object, key, value, props)
114 local font = props.objects[key];
115 if (not font) then
116 error("Missing Font");
117 end
118 object:SetFont(whichFont, font);
119 end
120 end
121  
122 local function PH_SetAnchors(object, key, value, props)
123 if (props.spec.type == "Font") then
124 return;
125 end
126 local parent = props.parent;
127 local P = props.properties;
128 local anchors = P.Anchors;
129 local allPoints = P.SetAllPoints;
130 if (anchors) then
131 -- If we have explicit anchors, process them all
132 object:ClearAllPoints();
133 local parname = parent and parent:GetName();
134 for _,a in ipairs(anchors) do
135 local p,rel,rp,x,y = a[1], a[2], a[3], a[4], a[5];
136 if (rel) then
137 rel = string.gsub(rel, "%$parent", parname or '');
138 end
139 if (not rel or rel == '') then rel = parent; end
140 object:SetPoint(p, rel, rp, x, y);
141 end
142 elseif ((allPoints) or (allPoints == nil)) then
143 -- Otherwise if we've explicitly been asked to set all points,
144 -- or the flag has not been set at all, then try and set all
145 -- points to the parent.
146 if (parent) then
147 object:SetAllPoints(parent);
148 else
149 -- TODO: Use 'screen' parent code once 1.11 launches
150 end
151 end
152 end
153  
154 local function PH_SetFont(object, key, value, props)
155 local P = props.properties;
156 local fontPath = P.Font;
157 local height = P.FontHeight or 0;
158 local outline = P.Outline;
159 local monochrome = P.Monochrome;
160 local flags = nil;
161 if (outline == "NORMAL") then
162 flags = "OUTLINE";
163 elseif (outline == "THICK") then
164 flags = "OUTLINE,THICKOUTLINE";
165 end
166 if (monochrome) then
167 if (flags) then
168 flags = flags .. ",MONOCHROME";
169 else
170 flags = "MONOCHROME";
171 end
172 end
173 object:SetFont(fontPath, height, flags);
174 end
175  
176 local function PH_SetShadow(object, key, value, props)
177 local C = value.color;
178 local O = value.offset;
179 if (value.color) then
180 object:SetShadowColor(C[1], C[2], C[3], C[4]);
181 end
182 if (value.offset) then
183 object:SetShadowOffset(C[1], C[2]);
184 end
185 end
186  
187 ---------------------------------------------------------------------------
188 -- LIBRARY METHODS
189 --
190 -- These are the actual library methods. Method names beginning with an
191 -- underscore are intended for internal use only.
192 --
193 local VFMETHODS = {};
194 setmetatable(lib, { __index = VFMETHODS } );
195  
196 function VFMETHODS:_Initialize()
197 self.specs = {};
198 self.scriptNames = {};
199 self.propertyHandlers = {};
200 self.propertyNames = {};
201 self.workTables = {};
202  
203 self:_InitProperties();
204 end
205  
206 function VFMETHODS:_GetWorkTable()
207 local tbl = next(self.workTables);
208 if (not tbl) then
209 return {};
210 end
211 self.workTables[tbl] = nil;
212 return tbl;
213 end
214  
215 function VFMETHODS:_ReleaseWorkTable(tbl)
216 for k,v in pairs(tbl) do
217 tbl[k] = nil;
218 end
219 table.setn(tbl, 0);
220 self.workTables[tbl] = true;
221 end
222  
223 -- Setup function for registering a new property handler with the
224 -- generation code. See PROPERTY HANDLERS section above.
225 --
226 -- func - The property handling function to use.
227 -- ... - One or more property names that the function handles.
228 --
229 -- Returns the property handler entry so that it can have flags set on
230 -- it if necessary.
231 function VFMETHODS:_AddPropertyHandler(func, ...)
232 local entry = {
233 names = arg;
234 func = func;
235 };
236 table.insert(self.propertyHandlers, entry);
237 for _, n in ipairs(arg) do
238 local curHandler = self.propertyNames[n];
239 if (curHandler) then
240 self:Warning("Duplicate property handler for '" .. n .. "'");
241 else
242 self.propertyNames[n] = entry;
243 end
244 end
245 return entry;
246 end
247  
248 function VFMETHODS:_InitProperties()
249 -- Block special properties
250 self.propertyNames["type"] = true;
251 self.propertyNames["name"] = true;
252 self.propertyNames["inherits"] = true;
253 self.propertyNames["Parent"] = true;
254  
255 ---------------------------------------------------------------------------
256 -- Group 0, basic properties
257 self:_AddPropertyHandler(PH_SetValue, "Alpha");
258 self:_AddPropertyHandler(PH_SetValue, "DrawLayer");
259 self:_AddPropertyHandler(
260 function(object, key, value, props)
261 if (value) then
262 object:Hide();
263 else
264 object:Show();
265 end
266 end, "Hidden");
267 self:_AddPropertyHandler(PH_SetValue, "ID");
268 self:_AddPropertyHandler(
269 function(object, key, value, props)
270 if (value == "PARENT") then
271 local par = props.parent;
272 if (par) then
273 value = par:GetFrameStrata();
274 else
275 value = "MEDIUM";
276 end
277 end
278 object:SetFrameStrata(value);
279 end, "FrameStrata");
280 self:_AddPropertyHandler(PH_SetValue, "Movable");
281 self:_AddPropertyHandler(PH_SetValue, "Resizable");
282 self:_AddPropertyHandler(
283 function(object, key, value, props)
284 if (value[1]) then
285 object:SetWidth(value[1]);
286 end
287 if (value[2]) then
288 object:SetHeight(value[2]);
289 end
290 end, "Size");
291 self:_AddPropertyHandler(PH_SetValue, "FrameLevel");
292 self:_AddPropertyHandler(PH_SetAnchors,
293 "SetAllPoints", "Anchors").runAlways = true;
294 self:_AddPropertyHandler(PH_SetValue, "TopLevel");
295  
296 ---------------------------------------------------------------------------
297 -- Group 1, sub-objects
298 self:_AddPropertyHandler(PH_SetValue, "Texture");
299 self:_AddPropertyHandler(PH_SetFont,
300 "Font", "FontHeight", "Outline", "Monochrome");
301 self:_AddPropertyHandler(Create_PH_SpecialFontSetter("FontObject")
302 , "FontString");
303 self:_AddPropertyHandler(Create_PH_SpecialFontSetter("TextFontObject"),
304 "NormalText");
305 self:_AddPropertyHandler(PH_SetSpecialTexture, "NormalTexture");
306 self:_AddPropertyHandler(PH_SetValue, "Backdrop");
307 self:_AddPropertyHandler(PH_SetSpecialTexture, "CheckedTexture");
308 self:_AddPropertyHandler(PH_SetSpecialTexture, "DisabledCheckedTexture");
309 self:_AddPropertyHandler(Create_PH_SpecialFontSetter("DisabledFontObject"),
310 "DisabledText");
311 self:_AddPropertyHandler(PH_SetSpecialTexture, "DisabledTexture");
312 self:_AddPropertyHandler(Create_PH_HTMLFontSetter("H1"),
313 "FontStringHeader1");
314 self:_AddPropertyHandler(Create_PH_HTMLFontSetter("H2"),
315 "FontStringHeader2");
316 self:_AddPropertyHandler(Create_PH_HTMLFontSetter("H3"),
317 "FontStringHeader3");
318 self:_AddPropertyHandler(Create_PH_SpecialFontSetter("HighlightFontObject"),
319 "HighlightText");
320 self:_AddPropertyHandler(PH_SetSpecialTexture, "HighlightTexture");
321 self:_AddPropertyHandler(PH_SetSpecialTexture, "PushedTexture");
322 self:_AddPropertyHandler(PH_SetSpecialFrame, "ScrollChild");
323 self:_AddPropertyHandler(
324 function(object, key, value, props)
325 -- *** UGLY ***
326 local tex = props.objects[key];
327 object:SetStatusBarTexture(tex:GetTexture());
328 end, "StatusBarTexture");
329 self:_AddPropertyHandler(PH_SetSpecialTexture, "ThumbTexture");
330 --self:_AddPropertyHandler(PH_SetValue, "ArrowModel"); -- Missing (Minimap)
331 --self:_AddPropertyHandler(PH_SetValue, "PlayerModel"); -- Missing
332 self:_AddPropertyHandler(PH_SetValue, "Model");
333  
334 ---------------------------------------------------------------------------
335 -- Group 2 - Colors
336 self:_AddPropertyHandler(
337 function(object, key, value, props)
338 object:SetHighlightTextColor(value[1], value[2], value[3], value[4]);
339 end, "HighlightColor");
340 self:_AddPropertyHandler(
341 function(object, key, value, props)
342 object:SetTexture(value[1], value[2], value[3], value[4]);
343 end, "Color");
344 self:_AddPropertyHandler(
345 function(object, key, value, props)
346 object:SetStatusBarColor(value[1], value[2], value[3], value[4]);
347 end, "BarColor");
348  
349 ---------------------------------------------------------------------------
350 -- Group 3 - Configuration
351  
352 self:_AddPropertyHandler(Create_PH_MethodCaller("SetBlendMode"),
353 "AlphaMode");
354 --self:_AddPropertyHandler(PH_SetValue, "AutoFocus"); -- 1.11
355 --self:_AddPropertyHandler(PH_SetValue, "BlinkSpeed"); -- Missing (EditBox)
356 self:_AddPropertyHandler(Create_PH_MethodCaller("SetTimeVisible"),
357 "DisplayDuration");
358 self:_AddPropertyHandler(PH_SetValue, "FogFar");
359 self:_AddPropertyHandler(PH_SetValue, "FogNear");
360 self:_AddPropertyHandler(PH_SetValue, "HistoryLines");
361 self:_AddPropertyHandler(PH_SetValue, "HyperlinkFormat");
362 -- IgnoreArrows -- GetAltArrowKeyMode ?
363 -- InsertMode -- 1.11
364 self:_AddPropertyHandler(PH_SetValue, "JustifyH");
365 self:_AddPropertyHandler(PH_SetValue, "JustifyV");
366 self:_AddPropertyHandler(PH_SetValue, "MaxBytes");
367 self:_AddPropertyHandler(PH_SetValue, "MaxLetters");
368 self:_AddPropertyHandler(PH_SetValue, "MaxLines");
369 self:_AddPropertyHandler(function (object, key, value, props)
370 local P = props.properties;
371 local min, max = P.MinValue, P.MaxValue;
372 if ((not min) or (not max)) then
373 local omin, omax = object:GetMinMaxValues();
374 min = min or omin;
375 max = max or omax;
376 end
377 object:SetMinMaxValues(min, max);
378 end, "MinValue", "MaxValue");
379 self:_AddPropertyHandler(PH_SetValue, "ModelScale");
380 self:_AddPropertyHandler(PH_SetValue, "NonSpaceWrap");
381 self:_AddPropertyHandler(PH_SetValue, "Orientation");
382 self:_AddPropertyHandler(PH_SetValue, "Spacing");
383 self:_AddPropertyHandler(PH_SetValue, "ValueStep");
384 self:_AddPropertyHandler(
385 function(object, key, value, props)
386 local max = value.max;
387 if (max) then
388 object:SetMaxResize(max[1], max[2]);
389 end
390 local min = value.min;
391 if (min) then
392 object:SetMinResize(max[1], max[2]);
393 end
394 end, "ResizeBounds");
395 self:_AddPropertyHandler(PH_SetShadow, "Shadow");
396 self:_AddPropertyHandler(
397 function(object, key, value, props)
398 object:SetTexCoord(value.left, value.right,
399 value.top, value.bottom);
400 end, "TexCoords");
401 self:_AddPropertyHandler(
402 function(object, key, value, props)
403 object:SetTextInsets(value.left, value.right,
404 value.top, value.bottom);
405 end, "TextInsets");
406  
407 ---------------------------------------------------------------------------
408 -- Group 4 - State
409  
410 self:_AddPropertyHandler(PH_SetValue, "Checked");
411 self:_AddPropertyHandler(PH_SetValue, "Text");
412 self:_AddPropertyHandler(PH_SetValue, "Value");
413  
414 -- Others
415  
416 -- File -- Missing (SimpleHTML)
417 -- MultiLine -- 1.11
418 -- Numeric - 1.11
419 -- Password -- Missing
420  
421 -- ColorValueTexture -- Missing
422 -- ColorValueThumbTexture -- Missing
423 -- ColorWheelTexture -- Missing
424 -- ColorWheelThumbTexture -- Missing
425 -- FogColor -- todo
426 -- Gradient -- todo
427 -- HitRectInsets -- missing
428 -- PushedTexOffset -- missing
429 -- TitleRegion -- missing
430 end
431  
432 function VFMETHODS:_Prepare(spec, path)
433 local myName;
434 if (spec.name) then
435 myName = spec.name .. "<" .. (spec.type or '?') .. ">";
436 else
437 myName = "<" .. (spec.type or '?') .. ">";
438 end
439  
440 if (not path) then
441 path = myName;
442 else
443 path = path .. ":" .. myName;
444 end
445  
446 for k,v in pairs(spec) do
447 if ((type(v) == "function") and string.find(k,"^On")) then
448 self.scriptNames[k] = true;
449 elseif (type(v) == "table" and v.type) then
450 self:_Prepare(v, path .. "[" .. k .. "]");
451 elseif (not self.propertyNames[k]) then
452 self:Warning("Unsupported property '" .. k .. "' used by "
453 .. path);
454 end
455 end
456 end
457  
458 function VFMETHODS:Register(name, spec)
459 -- self:Debug("Registering '" .. name .. "'");
460 self:_Prepare(spec);
461 self.specs[name] = spec;
462 end
463  
464 function VFMETHODS:Debug(msg)
465 ChatFrame2:AddMessage("[VirtualFrames] " .. msg);
466 end
467  
468 function VFMETHODS:Warning(msg)
469 if (IVF_Warnings) then
470 DEFAULT_CHAT_FRAME:AddMessage("[VirtualFrames] WARNING: " .. msg);
471 end
472 end
473  
474 function VFMETHODS:Error(msg)
475 DEFAULT_CHAT_FRAME:AddMessage("[VirtualFrames] ERROR: " .. msg);
476 message(msg);
477 end
478  
479 function VFMETHODS:Instantiate(template, name, parent, properties, noOnLoad)
480 local spec = self.specs[template];
481 if (not spec) then
482 self:Error("No template for '" .. template .. "' defined");
483 return;
484 end
485  
486 if (type(parent) == "string") then
487 local parentObj = getglobal(parent);
488 if (not parentObj) then
489 self:Error("Parent '" .. parentObj .. "' not found");
490 return;
491 end
492 parent = parentObj;
493 end
494  
495 if (properties) then
496 for key, value in pairs(properties) do
497 if ((type(value) == "function") and string.find(key, "^On")) then
498 self.scriptNames[key] = true;
499 elseif (not self.propertyNames[key]) then
500 self:Warning("Unsupported property '" .. key .. "' in input.");
501 end
502 end
503 end
504  
505 local context = self:_GetWorkTable();
506 context.specs = self:_GetWorkTable();
507  
508 local obj, objname = self:_ObjectCreate(context, spec, name,
509 parent, properties);
510 local P = self:_ObjectComplete(context,
511 spec, obj, objname, properties);
512  
513 self:_ObjectActivate(context, spec, obj, properties, noOnLoad);
514  
515 self:_ReleaseWorkTable(context.specs);
516 self:_ReleaseWorkTable(context);
517 context = nil;
518 if (properties) then
519 local meta = getmetatable(properties);
520 if (meta) then
521 meta.__index = nil;
522 end
523 end
524 return obj, objname;
525 end
526  
527 function VFMETHODS:_LayerProperties(spec, P)
528 if (P) then
529 local meta = getmetatable(P);
530 if (not meta) then
531 meta = {};
532 setmetatable(P, meta);
533 end
534 if (not meta.__index) then
535 meta.__index = spec;
536 end
537 else
538 P = spec;
539 end
540  
541 return P;
542 end
543  
544 -- CREATE: This handles creating an object and building the merged
545 -- property structure for the remainder of the process.
546 --
547 -- context - The context structure for the instantiation process
548 -- spec - The spec structure defining the object to create
549 -- name - The requested object name (nil to use spec)
550 -- parent - The parent object (nil to use spec)
551 -- props - Source properties for the processing run
552 --
553 -- Returns the created object, its name, and its parent object
554 function VFMETHODS:_ObjectCreate(context, spec, name, parent, props)
555 --self:Debug(" Create "..spec.type.." (" .. (spec.name or "") ..") "
556 --..(name or '?'));
557  
558 local P = self:_LayerProperties(spec, props);
559  
560 local object, inheritFont;
561 local objType = rawget(spec, "type");
562 local inherits = rawget(spec, "inherits");
563 if (inherits) then
564 if ((objType == "FontString") or (objType == "Font")) then
565 font = getglobal(inherits);
566 if (font and font.IsObjectType and font:IsObjectType("Font")) then
567 inheritFont = font;
568 end
569 end
570 if (not inheritFont) then
571 -- self:Debug(" Inherits from " .. spec.inherits);
572 local ispec = self.specs[inherits];
573 if (not ispec) then
574 self:Error("No template for '" .. inherits .. "' defined");
575 elseif (rawget(ispec, "type") ~= objType) then
576 self:Error("Type mismatch with template '" .. inherits .. "'");
577 else
578 local pmeta = getmetatable(spec);
579 if (not pmeta) then
580 pmeta = {};
581 setmetatable(spec, pmeta);
582 end
583 pmeta.__index = ispec;
584 object = self:_ObjectCreate(context, ispec, name, parent, P);
585 end
586 end
587 end
588  
589 if (not object) then
590 if (not parent) then
591 local PParent = P.Parent;
592 if (PParent) then
593 parent = getglobal(PParent);
594 if (not parent) then
595 self:Warning("Unable to find parent frame '" .. PParent .. "'");
596 end
597 end
598 end
599  
600 if (objType == "Texture") then
601 object = parent:CreateTexture(name);
602 elseif (objType == "FontString") then
603 object = parent:CreateFontString(name);
604 if (inheritFont) then
605 object:SetFontObject(inheritFont);
606 end
607 elseif (objType == "Font") then
608 object = CreateFont(name or " unnamed font ");
609 if (inheritFont) then
610 object:SetFontObject(inheritFont);
611 end
612 else
613 object = CreateFrame(objType, name, parent);
614 end
615  
616 context.specs[object] = spec;
617 end
618  
619 return object, name, parent;
620 end
621  
622 local function PW_ErrorMethod(self, error)
623 local context = self.name;
624 local spec = self.spec;
625 if (not context and spec.name) then
626 context = "[" .. spec.name .. "]";
627 end
628 if (not context and spec.type) then
629 context = "[" .. spec.type .. "]";
630 end
631 if (not context) then
632 context = "?";
633 end
634 if (self.curName) then
635 context = context .. ": " .. self.curName;
636 end
637 self.engine:Error(context .. ": " .. error);
638 end
639  
640 -- COMPLETE: This handles creating child objects, then applying properties
641 -- to the object and child objects.
642 --
643 -- context - The context structure for the instantiation process
644 -- spec - The spec structure defining the object to create
645 -- object - The object to be completed
646 -- name - The requested object name (nil to use spec)
647 -- props - Source properties for the processing run
648 -- noApply - If true, suppress application of properties on the object
649 --
650 -- Returns the merged properties of the object.
651 --
652 -- Completion works as follows:
653 --
654 -- 1) If this spec inherits from another one, then call _ObjectComplete
655 -- for the same object but with the inherited spec, props == the
656 -- merged properties for the object, and and noApply = true, continue
657 -- when that returns.
658 -- 2) _ObjectCreate all child objects declared by THIS spec (not including
659 -- special property objects) with this as parent.
660 -- 3) If noApply is false, then _ObjectCreate all property objects.
661 -- 4) _ObjectComplete all child objects declared by THIS spec.
662 -- 5) if noApply is false, then _ObjectComplete all property objects.
663 -- 6) if noApply is false, then _ObjectActivate all property objects.
664 -- 7) if noApply is false, then apply all relevant property handlers.
665 -- 8) _ObjectActivate all child objects declared by THIS spec.
666 -- 9) return merged properties.
667 function VFMETHODS:_ObjectComplete(context, spec, object, name, props, noApply)
668 --self:Debug(" Complete "..spec.type.." (" .. (spec.name or "") ..") "
669 --..(name or '?'));
670  
671 local P = self:_LayerProperties(spec, props);
672 local baseSpec = context.specs[object];
673 local objType = rawget(spec, "type");
674 local inherited = false;
675 if ((baseSpec ~= spec) and (objType ~= 'Font')) then
676 local inherits = rawget(spec, "inherits");
677 local ispec = self.specs[inherits];
678 if (ispec) then
679 inherited = true;
680 P = self:_ObjectComplete(context, ispec, object, name, P, true);
681 end
682 end
683  
684 -- Create sub objects
685 local childObjects = self:_GetWorkTable();
686 local propObjects = self:_GetWorkTable();
687  
688 for k, v in ipairs(spec) do
689 local cname = v.name;
690 if (cname) then
691 cname = string.gsub(cname, "%$parent", name or '');
692 end
693 childObjects[k] = self:_ObjectCreate(context, v, cname, object);
694 end
695  
696 if (not noApply) then
697 for n in pairs(self.propertyNames) do
698 local v = P[n];
699 if ((type(v) == "table") and (v.type)) then
700 local cname = v.name;
701 if (cname) then
702 cname = string.gsub(cname, "%$parent", name or '');
703 end
704 propObjects[n] = self:_ObjectCreate(context, v, cname, object);
705 end
706 end
707 end
708  
709 -- Now complete child objects
710 for k, spec in ipairs(spec) do
711 local obj = childObjects[k];
712 self:_ObjectComplete(context, spec, obj, obj:GetName());
713 end
714  
715 if (not noApply) then
716 for k, obj in pairs(propObjects) do
717 local spec = P[k];
718 self:_ObjectComplete(context, spec, obj, obj:GetName());
719 end
720  
721 -- Populate this frame's properties
722 for k, obj in pairs(propObjects) do
723 local spec = P[k];
724 self:_ObjectActivate(context, spec, obj);
725 end
726  
727 local propWorker = self:_GetWorkTable();
728 propWorker.engine = self;
729 propWorker.spec = spec;
730 propWorker.name = name;
731 propWorker.object = object;
732 propWorker.properties = P;
733 propWorker.parent = object.GetParent and object:GetParent();
734 propWorker.Error = PW_ErrorMethod;
735 propWorker.objects = propObjects;
736  
737 for _,p in ipairs(self.propertyHandlers) do
738 for _,n in ipairs(p.names) do
739 local v = P[n];
740 if ((v ~= nil) or (p.runAlways)) then
741 propWorker.curName = n;
742 local ok, err = pcall(p.func,
743 object, n, v,
744 propWorker, p);
745 if (not ok) then
746 propWorker:Error("Failed: " .. err);
747 end
748 break;
749 end
750 end
751 end
752  
753 self:_ReleaseWorkTable(propWorker);
754 propWorker = nil;
755 end
756  
757 -- Activate child objects
758 for k, spec in ipairs(spec) do
759 local obj = childObjects[k];
760 self:_ObjectActivate(context, spec, obj);
761 end
762  
763 self:_ReleaseWorkTable(childObjects);
764 self:_ReleaseWorkTable(propObjects);
765 regionObjects, childObjects, propObjects = nil, nil, nil;
766  
767 return P;
768 end
769  
770 -- ACTIVATE: Apply scripts and invoke OnLoad if necessary.
771 --
772 -- context - The context structure for the instantiation process
773 -- spec - The spec structure defining the object to create
774 -- object - The object to activate
775 -- props - Source properties for the processing run
776 -- noOnLoad - If true, don't call OnLoad method if it exists
777 function VFMETHODS:_ObjectActivate(context, spec, object, props, noOnLoad)
778 --self:Debug(" Activate "..spec.type.." (" .. (spec.name or "") ..") "
779 --..(object:GetName() or '?'));
780 local P = self:_LayerProperties(spec, props);
781  
782 local HS = object.HasScript;
783 local OnLoad;
784 for scriptName in pairs(self.scriptNames) do
785 local script = P[scriptName];
786 if (type(script) == "function") then
787 if (HS and HS(object, scriptName)) then
788 object:SetScript(scriptName, script);
789 if (scriptName == "OnLoad") then
790 OnLoad = script;
791 end
792 else
793 self:Error("Attempted to set " .. k .. " script on a "
794 .. spec.type);
795 end
796 end
797 end
798  
799 if (OnLoad and (not noOnLoad)) then
800 -- self:Debug("Firing OnLoad " .. tostring(object:GetName() or object));
801 local oldthis = this;
802 this = object;
803 local ok,err = pcall(OnLoad);
804 if (not ok) then
805 self:Error("OnLoad failed for " .. spec.type );
806 self:Error(tostring(err));
807 end
808 this = oldthis;
809 end
810 end
811  
812 -- Register this instance with the stub
813 IrielVirtualFrames:Register(lib);
814 lib = nil; -- Let GC clean it up later