source: Dev/branches/rest-dojo-ui/client/dojox/gfx/silverlight.js @ 260

Last change on this file since 260 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 25.3 KB
Line 
1define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/Color",
2                "dojo/_base/array", "dojo/dom-geometry", "dojo/dom", "dojo/_base/sniff",
3                "./_base", "./shape", "./path"],
4  function(kernel,lang,declare,color,arr,domGeom,dom,has,g,gs,pathLib){
5/*=====
6        dojox.gfx.silverlight = {
7        // module:
8        //              dojox/gfx/silverlight
9        // summary:
10        //              This the graphics rendering bridge for the Microsoft Silverlight plugin.
11        //              Silverlight is a faster implementation on IE6-8 than the default 2d graphics, VML
12        };
13        g = dojox.gfx;
14        pathLib.Path = dojox.gfx.path.Path;
15        pathLib.TextPath = dojox.gfx.path.TextPath;
16        sl.Shape = dojox.gfx.canvas.Shape;
17        gs.Shape = dojox.gfx.shape.Shape;
18        gs.Rect = dojox.gfx.shape.Rect;
19        gs.Ellipse = dojox.gfx.shape.Ellipse;
20        gs.Circle = dojox.gfx.shape.Circle;
21        gs.Line = dojox.gfx.shape.Line;
22        gs.PolyLine = dojox.gfx.shape.PolyLine;
23        gs.Image = dojox.gfx.shape.Image;
24        gs.Text = dojox.gfx.shape.Text;
25        gs.Surface = dojox.gfx.shape.Surface;
26  =====*/
27
28        var sl = g.silverlight = {};
29        kernel.experimental("dojox.gfx.silverlight");
30
31        var dasharray = {
32                        solid:                          "none",
33                        shortdash:                      [4, 1],
34                        shortdot:                       [1, 1],
35                        shortdashdot:           [4, 1, 1, 1],
36                        shortdashdotdot:        [4, 1, 1, 1, 1, 1],
37                        dot:                            [1, 3],
38                        dash:                           [4, 3],
39                        longdash:                       [8, 3],
40                        dashdot:                        [4, 3, 1, 3],
41                        longdashdot:            [8, 3, 1, 3],
42                        longdashdotdot:         [8, 3, 1, 3, 1, 3]
43                },
44                fontweight = {
45                        normal: 400,
46                        bold:   700
47                },
48                caps  = {butt: "Flat", round: "Round", square: "Square"},
49                joins = {bevel: "Bevel", round: "Round"},
50                fonts = {
51                        serif: "Times New Roman",
52                        times: "Times New Roman",
53                        "sans-serif": "Arial",
54                        helvetica: "Arial",
55                        monotone: "Courier New",
56                        courier: "Courier New"
57                };
58
59        function hexColor(/*String|Array|dojo.Color*/ color){
60                // summary: converts a color object to a Silverlight hex color string (#aarrggbb)
61                var c = g.normalizeColor(color),
62                        t = c.toHex(), a = Math.round(c.a * 255);
63                a = (a < 0 ? 0 : a > 255 ? 255 : a).toString(16);
64                return "#" + (a.length < 2 ? "0" + a : a) + t.slice(1); // String
65        }
66
67        declare("dojox.gfx.silverlight.Shape", gs.Shape, {
68                // summary: Silverlight-specific implementation of dojox.gfx.Shape methods
69
70                setFill: function(fill){
71                        // summary: sets a fill object (Silverlight)
72                        // fill: Object: a fill object
73                        //      (see dojox.gfx.defaultLinearGradient,
74                        //      dojox.gfx.defaultRadialGradient,
75                        //      dojox.gfx.defaultPattern,
76                        //      or dojo.Color)
77
78                        var p = this.rawNode.getHost().content, r = this.rawNode, f;
79                        if(!fill){
80                                // don't fill
81                                this.fillStyle = null;
82                                this._setFillAttr(null);
83                                return this;    // self
84                        }
85                        if(typeof(fill) == "object" && "type" in fill){
86                                // gradient
87                                switch(fill.type){
88                                        case "linear":
89                                                this.fillStyle = f = g.makeParameters(g.defaultLinearGradient, fill);
90                                                var lgb = p.createFromXaml("<LinearGradientBrush/>");
91                                                lgb.mappingMode = "Absolute";
92                                                lgb.startPoint = f.x1 + "," + f.y1;
93                                                lgb.endPoint = f.x2 + "," + f.y2;
94                                                arr.forEach(f.colors, function(c){
95                                                        var t = p.createFromXaml("<GradientStop/>");
96                                                        t.offset = c.offset;
97                                                        t.color = hexColor(c.color);
98                                                        lgb.gradientStops.add(t);
99                                                });
100                                                this._setFillAttr(lgb);
101                                                break;
102                                        case "radial":
103                                                this.fillStyle = f = g.makeParameters(g.defaultRadialGradient, fill);
104                                                var rgb = p.createFromXaml("<RadialGradientBrush/>"),
105                                                        c = g.matrix.multiplyPoint(g.matrix.invert(this._getAdjustedMatrix()), f.cx, f.cy),
106                                                        pt = c.x + "," + c.y;
107                                                rgb.mappingMode = "Absolute";
108                                                rgb.gradientOrigin = pt;
109                                                rgb.center = pt;
110                                                rgb.radiusX = rgb.radiusY = f.r;
111                                                arr.forEach(f.colors, function(c){
112                                                        var t = p.createFromXaml("<GradientStop/>");
113                                                        t.offset = c.offset;
114                                                        t.color = hexColor(c.color);
115                                                        rgb.gradientStops.add(t);
116                                                });
117                                                this._setFillAttr(rgb);
118                                                break;
119                                        case "pattern":
120                                                // don't fill: Silverlight doesn't define TileBrush for some reason
121                                                this.fillStyle = null;
122                                                this._setFillAttr(null);
123                                                break;
124                                }
125                                return this;    // self
126                        }
127                        // color object
128                        this.fillStyle = f = g.normalizeColor(fill);
129                        var scb = p.createFromXaml("<SolidColorBrush/>");
130                        scb.color = f.toHex();
131                        scb.opacity = f.a;
132                        this._setFillAttr(scb);
133                        return this;    // self
134                },
135                _setFillAttr: function(f){
136                        this.rawNode.fill = f;
137                },
138
139                setStroke: function(stroke){
140                        // summary: sets a stroke object (Silverlight)
141                        // stroke: Object: a stroke object
142                        //      (see dojox.gfx.defaultStroke)
143
144                        var p = this.rawNode.getHost().content, r = this.rawNode;
145                        if(!stroke){
146                                // don't stroke
147                                this.strokeStyle = null;
148                                r.stroke = null;
149                                return this;
150                        }
151                        // normalize the stroke
152                        if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof color){
153                                stroke = {color: stroke};
154                        }
155                        var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
156                        s.color = g.normalizeColor(s.color);
157                        // generate attributes
158                        if(s){
159                                var scb = p.createFromXaml("<SolidColorBrush/>");
160                                scb.color = s.color.toHex();
161                                scb.opacity = s.color.a;
162                                r.stroke = scb;
163                                r.strokeThickness = s.width;
164                                r.strokeStartLineCap = r.strokeEndLineCap = r.strokeDashCap =
165                                        caps[s.cap];
166                                if(typeof s.join == "number"){
167                                        r.strokeLineJoin = "Miter";
168                                        r.strokeMiterLimit = s.join;
169                                }else{
170                                        r.strokeLineJoin = joins[s.join];
171                                }
172                                var da = s.style.toLowerCase();
173                                if(da in dasharray){ da = dasharray[da]; }
174                                if(da instanceof Array){
175                                        da = lang.clone(da);
176                                        var i;
177                                        /*
178                                        for(var i = 0; i < da.length; ++i){
179                                                da[i] *= s.width;
180                                        }
181                                        */
182                                        if(s.cap != "butt"){
183                                                for(i = 0; i < da.length; i += 2){
184                                                        //da[i] -= s.width;
185                                                        --da[i]
186                                                        if(da[i] < 1){ da[i] = 1; }
187                                                }
188                                                for(i = 1; i < da.length; i += 2){
189                                                        //da[i] += s.width;
190                                                        ++da[i];
191                                                }
192                                        }
193                                        r.strokeDashArray = da.join(",");
194                                }else{
195                                        r.strokeDashArray = null;
196                                }
197                        }
198                        return this;    // self
199                },
200
201                _getParentSurface: function(){
202                        var surface = this.parent;
203                        for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
204                        return surface;
205                },
206
207                _applyTransform: function() {
208                        var tm = this._getAdjustedMatrix(), r = this.rawNode;
209                        if(tm){
210                                var p = this.rawNode.getHost().content,
211                                        mt = p.createFromXaml("<MatrixTransform/>"),
212                                        mm = p.createFromXaml("<Matrix/>");
213                                mm.m11 = tm.xx;
214                                mm.m21 = tm.xy;
215                                mm.m12 = tm.yx;
216                                mm.m22 = tm.yy;
217                                mm.offsetX = tm.dx;
218                                mm.offsetY = tm.dy;
219                                mt.matrix = mm;
220                                r.renderTransform = mt;
221                        }else{
222                                r.renderTransform = null;
223                        }
224                        return this;
225                },
226
227                setRawNode: function(rawNode){
228                        // summary:
229                        //      assigns and clears the underlying node that will represent this
230                        //      shape. Once set, transforms, gradients, etc, can be applied.
231                        //      (no fill & stroke by default)
232                        rawNode.fill = null;
233                        rawNode.stroke = null;
234                        this.rawNode = rawNode;
235                        this.rawNode.tag = this.getUID();                                               
236                },
237
238                // move family
239
240                _moveToFront: function(){
241                        // summary: moves a shape to front of its parent's list of shapes (Silverlight)
242                        var c = this.parent.rawNode.children, r = this.rawNode;
243                        c.remove(r);
244                        c.add(r);
245                        return this;    // self
246                },
247                _moveToBack: function(){
248                        // summary: moves a shape to back of its parent's list of shapes (Silverlight)
249                        var c = this.parent.rawNode.children, r = this.rawNode;
250                        c.remove(r);
251                        c.insert(0, r);
252                        return this;    // self
253                },
254
255                _getAdjustedMatrix: function(){
256                        // summary: returns the adjusted ("real") transformation matrix
257                        return this.matrix;     // dojox.gfx.Matrix2D
258                }
259        });
260
261        declare("dojox.gfx.silverlight.Group", sl.Shape, {
262                // summary: a group shape (Silverlight), which can be used
263                //      to logically group shapes (e.g, to propagate matricies)
264                constructor: function(){
265                        gs.Container._init.call(this);
266                },
267                setRawNode: function(rawNode){
268                        // summary: sets a raw Silverlight node to be used by this shape
269                        // rawNode: Node: an Silverlight node
270                        this.rawNode = rawNode;
271                        this.rawNode.tag = this.getUID();                                               
272                       
273                }
274        });
275        sl.Group.nodeType = "Canvas";
276
277        declare("dojox.gfx.silverlight.Rect", [sl.Shape, gs.Rect], {
278                // summary: a rectangle shape (Silverlight)
279                setShape: function(newShape){
280                        // summary: sets a rectangle shape object (Silverlight)
281                        // newShape: Object: a rectangle shape object
282                        this.shape = g.makeParameters(this.shape, newShape);
283                        this.bbox = null;
284                        var r = this.rawNode, n = this.shape;
285                        r.width   = n.width;
286                        r.height  = n.height;
287                        r.radiusX = r.radiusY = n.r;
288                        return this._applyTransform();  // self
289                },
290                _getAdjustedMatrix: function(){
291                        // summary: returns the adjusted ("real") transformation matrix
292                        var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
293                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox.gfx.Matrix2D
294                }
295        });
296        sl.Rect.nodeType = "Rectangle";
297
298        declare("dojox.gfx.silverlight.Ellipse", [sl.Shape, gs.Ellipse], {
299                // summary: an ellipse shape (Silverlight)
300                setShape: function(newShape){
301                        // summary: sets an ellipse shape object (Silverlight)
302                        // newShape: Object: an ellipse shape object
303                        this.shape = g.makeParameters(this.shape, newShape);
304                        this.bbox = null;
305                        var r = this.rawNode, n = this.shape;
306                        r.width  = 2 * n.rx;
307                        r.height = 2 * n.ry;
308                        return this._applyTransform();  // self
309                },
310                _getAdjustedMatrix: function(){
311                        // summary: returns the adjusted ("real") transformation matrix
312                        var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.rx, dy: s.cy - s.ry};
313                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox.gfx.Matrix2D
314                }
315        });
316        sl.Ellipse.nodeType = "Ellipse";
317
318        declare("dojox.gfx.silverlight.Circle", [sl.Shape, gs.Circle], {
319                // summary: a circle shape (Silverlight)
320                setShape: function(newShape){
321                        // summary: sets a circle shape object (Silverlight)
322                        // newShape: Object: a circle shape object
323                        this.shape = g.makeParameters(this.shape, newShape);
324                        this.bbox = null;
325                        var r = this.rawNode, n = this.shape;
326                        r.width = r.height = 2 * n.r;
327                        return this._applyTransform();  // self
328                },
329                _getAdjustedMatrix: function(){
330                        // summary: returns the adjusted ("real") transformation matrix
331                        var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.r, dy: s.cy - s.r};
332                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox.gfx.Matrix2D
333                }
334        });
335        sl.Circle.nodeType = "Ellipse";
336
337        declare("dojox.gfx.silverlight.Line", [sl.Shape, gs.Line], {
338                // summary: a line shape (Silverlight)
339                setShape: function(newShape){
340                        // summary: sets a line shape object (Silverlight)
341                        // newShape: Object: a line shape object
342                        this.shape = g.makeParameters(this.shape, newShape);
343                        this.bbox = null;
344                        var r = this.rawNode, n = this.shape;
345                        r.x1 = n.x1; r.y1 = n.y1; r.x2 = n.x2; r.y2 = n.y2;
346                        return this;    // self
347                }
348        });
349        sl.Line.nodeType = "Line";
350
351        declare("dojox.gfx.silverlight.Polyline", [sl.Shape, gs.Polyline], {
352                // summary: a polyline/polygon shape (Silverlight)
353                setShape: function(points, closed){
354                        // summary: sets a polyline/polygon shape object (Silverlight)
355                        // points: Object: a polyline/polygon shape object
356                        if(points && points instanceof Array){
357                                // branch
358                                // points: Array: an array of points
359                                this.shape = g.makeParameters(this.shape, {points: points});
360                                if(closed && this.shape.points.length){
361                                        this.shape.points.push(this.shape.points[0]);
362                                }
363                        }else{
364                                this.shape = g.makeParameters(this.shape, points);
365                        }
366                        this.bbox = null;
367                        this._normalizePoints();
368                        var p = this.shape.points, rp = [];
369                        for(var i = 0; i < p.length; ++i){
370                                rp.push(p[i].x, p[i].y);
371                        }
372                        this.rawNode.points = rp.join(",");
373                        return this;    // self
374                }
375        });
376        sl.Polyline.nodeType = "Polyline";
377
378        declare("dojox.gfx.silverlight.Image", [sl.Shape, gs.Image], {
379                // summary: an image (Silverlight)
380                setShape: function(newShape){
381                        // summary: sets an image shape object (Silverlight)
382                        // newShape: Object: an image shape object
383                        this.shape = g.makeParameters(this.shape, newShape);
384                        this.bbox = null;
385                        var r = this.rawNode, n = this.shape;
386                        r.width  = n.width;
387                        r.height = n.height;
388                        r.source = n.src;
389                        return this._applyTransform();  // self
390                },
391                _getAdjustedMatrix: function(){
392                        // summary: returns the adjusted ("real") transformation matrix
393                        var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
394                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox.gfx.Matrix2D
395                },
396                setRawNode: function(rawNode){
397                        // summary:
398                        //      assigns and clears the underlying node that will represent this
399                        //      shape. Once set, transforms, gradients, etc, can be applied.
400                        //      (no fill & stroke by default)
401                        this.rawNode = rawNode;
402                        this.rawNode.tag = this.getUID();                                               
403                }
404        });
405        sl.Image.nodeType = "Image";
406
407        declare("dojox.gfx.silverlight.Text", [sl.Shape, gs.Text], {
408                // summary: an anchored text (Silverlight)
409                setShape: function(newShape){
410                        // summary: sets a text shape object (Silverlight)
411                        // newShape: Object: a text shape object
412                        this.shape = g.makeParameters(this.shape, newShape);
413                        this.bbox = null;
414                        var r = this.rawNode, s = this.shape;
415                        r.text = s.text;
416                        r.textDecorations = s.decoration === "underline" ? "Underline" : "None";
417                        r["Canvas.Left"] = -10000;
418                        r["Canvas.Top"]  = -10000;
419                        if(!this._delay){
420                                this._delay = window.setTimeout(lang.hitch(this, "_delayAlignment"), 10);
421                        }
422                        return this;    // self
423                },
424                _delayAlignment: function(){
425                        // handle alignment
426                        var r = this.rawNode, s = this.shape, w, h;
427                        try{
428                                w = r.actualWidth;
429                                h = r.actualHeight;
430                        }catch(e){
431                                // bail out if the node is hidden
432                                return;
433                        }
434                        var x = s.x, y = s.y - h * 0.75;
435                        switch(s.align){
436                                case "middle":
437                                        x -= w / 2;
438                                        break;
439                                case "end":
440                                        x -= w;
441                                        break;
442                        }
443                        this._delta = {dx: x, dy: y};
444                        r["Canvas.Left"] = 0;
445                        r["Canvas.Top"]  = 0;
446                        this._applyTransform();
447                        delete this._delay;
448                },
449                _getAdjustedMatrix: function(){
450                        // summary: returns the adjusted ("real") transformation matrix
451                        var matrix = this.matrix, delta = this._delta, x;
452                        if(matrix){
453                                x = delta ? [matrix, delta] : matrix;
454                        }else{
455                                x = delta ? delta : {};
456                        }
457                        return new g.Matrix2D(x);
458                },
459                setStroke: function(){
460                        // summary: ignore setting a stroke style
461                        return this;    // self
462                },
463                _setFillAttr: function(f){
464                        this.rawNode.foreground = f;
465                },
466                setRawNode: function(rawNode){
467                        // summary:
468                        //      assigns and clears the underlying node that will represent this
469                        //      shape. Once set, transforms, gradients, etc, can be applied.
470                        //      (no fill & stroke by default)
471                        this.rawNode = rawNode;
472                        this.rawNode.tag = this.getUID();                                               
473                },
474                getTextWidth: function(){
475                        // summary: get the text width in pixels
476                        return this.rawNode.actualWidth;
477                }
478        });
479        sl.Text.nodeType = "TextBlock";
480
481        declare("dojox.gfx.silverlight.Path", [sl.Shape, pathLib.Path], {
482                // summary: a path shape (Silverlight)
483                _updateWithSegment: function(segment){
484                        // summary: updates the bounding box of path with new segment
485                        // segment: Object: a segment
486                        this.inherited(arguments);
487                        var p = this.shape.path;
488                        if(typeof(p) == "string"){
489                                this.rawNode.data = p ? p : null;
490                        }
491                },
492                setShape: function(newShape){
493                        // summary: forms a path using a shape (Silverlight)
494                        // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
495                        this.inherited(arguments);
496                        var p = this.shape.path;
497                        this.rawNode.data = p ? p : null;
498                        return this;    // self
499                }
500        });
501        sl.Path.nodeType = "Path";
502
503        declare("dojox.gfx.silverlight.TextPath", [sl.Shape, pathLib.TextPath], {
504                // summary: a textpath shape (Silverlight)
505                _updateWithSegment: function(segment){
506                        // summary: updates the bounding box of path with new segment
507                        // segment: Object: a segment
508                },
509                setShape: function(newShape){
510                        // summary: forms a path using a shape (Silverlight)
511                        // newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
512                },
513                _setText: function(){
514                }
515        });
516        sl.TextPath.nodeType = "text";
517
518        var surfaces = {}, nullFunc = new Function;
519
520        declare("dojox.gfx.silverlight.Surface", gs.Surface, {
521                // summary: a surface object to be used for drawings (Silverlight)
522                constructor: function(){
523                        gs.Container._init.call(this);
524                },
525                destroy: function(){
526                        window[this._onLoadName] = nullFunc;
527                        delete surfaces[this._nodeName];
528                        this.inherited(arguments);
529                },
530                setDimensions: function(width, height){
531                        // summary: sets the width and height of the rawNode
532                        // width: String: width of surface, e.g., "100px"
533                        // height: String: height of surface, e.g., "100px"
534                        this.width  = g.normalizedLength(width);        // in pixels
535                        this.height = g.normalizedLength(height);       // in pixels
536                        var p = this.rawNode && this.rawNode.getHost();
537                        if(p){
538                                p.width = width;
539                                p.height = height;
540                        }
541                        return this;    // self
542                },
543                getDimensions: function(){
544                        // summary: returns an object with properties "width" and "height"
545                        var p = this.rawNode && this.rawNode.getHost();
546                        var t = p ? {width: p.content.actualWidth, height: p.content.actualHeight} : null;
547                        if(t.width  <= 0){ t.width  = this.width; }
548                        if(t.height <= 0){ t.height = this.height; }
549                        return t;       // Object
550                }
551        });
552
553        sl.createSurface = function(parentNode, width, height){
554                // summary: creates a surface (Silverlight)
555                // parentNode: Node: a parent node
556                // width: String: width of surface, e.g., "100px"
557                // height: String: height of surface, e.g., "100px"
558
559                if(!width && !height){
560                        var pos = domGeom.position(parentNode);
561                        width  = width  || pos.w;
562                        height = height || pos.h;
563                }
564                if(typeof width == "number"){
565                        width = width + "px";
566                }
567                if(typeof height == "number"){
568                        height = height + "px";
569                }
570
571                var s = new sl.Surface();
572                parentNode = dom.byId(parentNode);
573                s._parent = parentNode;
574                s._nodeName = g._base._getUniqueId();
575
576                // create an empty canvas
577                var t = parentNode.ownerDocument.createElement("script");
578                t.type = "text/xaml";
579                t.id = g._base._getUniqueId();
580                t.text = "<?xml version='1.0'?><Canvas xmlns='http://schemas.microsoft.com/client/2007' Name='" +
581                        s._nodeName + "'/>";
582                parentNode.parentNode.insertBefore(t, parentNode);
583                s._nodes.push(t);
584
585                // build the object
586                var obj, pluginName = g._base._getUniqueId(),
587                        onLoadName = "__" + g._base._getUniqueId() + "_onLoad";
588                s._onLoadName = onLoadName;
589                window[onLoadName] = function(sender){
590                        if(!s.rawNode){
591                                s.rawNode = dom.byId(pluginName).content.root;
592                                // register the plugin with its parent node
593                                surfaces[s._nodeName] = parentNode;
594                                s.onLoad(s);
595                        }
596                };
597                if(has("safari")){
598                        obj = "<embed type='application/x-silverlight' id='" +
599                        pluginName + "' width='" + width + "' height='" + height +
600                        " background='transparent'" +
601                        " source='#" + t.id + "'" +
602                        " windowless='true'" +
603                        " maxFramerate='60'" +
604                        " onLoad='" + onLoadName + "'" +
605                        " onError='__dojoSilverlightError'" +
606                        " /><iframe style='visibility:hidden;height:0;width:0'/>";
607                }else{
608                        obj = "<object type='application/x-silverlight' data='data:application/x-silverlight,' id='" +
609                        pluginName + "' width='" + width + "' height='" + height + "'>" +
610                        "<param name='background' value='transparent' />" +
611                        "<param name='source' value='#" + t.id + "' />" +
612                        "<param name='windowless' value='true' />" +
613                        "<param name='maxFramerate' value='60' />" +
614                        "<param name='onLoad' value='" + onLoadName + "' />" +
615                        "<param name='onError' value='__dojoSilverlightError' />" +
616                        "</object>";
617                }
618                parentNode.innerHTML = obj;
619
620                var pluginNode = dom.byId(pluginName);
621                if(pluginNode.content && pluginNode.content.root){
622                        // the plugin was created synchronously
623                        s.rawNode = pluginNode.content.root;
624                        // register the plugin with its parent node
625                        surfaces[s._nodeName] = parentNode;
626                }else{
627                        // the plugin is being created asynchronously
628                        s.rawNode = null;
629                        s.isLoaded = false;
630                }
631                s._nodes.push(pluginNode);
632
633                s.width  = g.normalizedLength(width);   // in pixels
634                s.height = g.normalizedLength(height);  // in pixels
635
636                return s;       // dojox.gfx.Surface
637        };
638
639        // the function below is meant to be global, it is called from
640        // the Silverlight's error handler
641        __dojoSilverlightError = function(sender, err){
642                var t = "Silverlight Error:\n" +
643                        "Code: " + err.ErrorCode + "\n" +
644                        "Type: " + err.ErrorType + "\n" +
645                        "Message: " + err.ErrorMessage + "\n";
646                switch(err.ErrorType){
647                        case "ParserError":
648                                t += "XamlFile: " + err.xamlFile + "\n" +
649                                        "Line: " + err.lineNumber + "\n" +
650                                        "Position: " + err.charPosition + "\n";
651                                break;
652                        case "RuntimeError":
653                                t += "MethodName: " + err.methodName + "\n";
654                                if(err.lineNumber != 0){
655                                        t +=
656                                                "Line: " + err.lineNumber + "\n" +
657                                                "Position: " + err.charPosition + "\n";
658                                }
659                                break;
660                }
661        };
662
663        // Extenders
664
665        var Font = {
666                _setFont: function(){
667                        // summary: sets a font object (Silverlight)
668                        var f = this.fontStyle, r = this.rawNode, t = f.family.toLowerCase();
669                        r.fontStyle = f.style == "italic" ? "Italic" : "Normal";
670                        r.fontWeight = f.weight in fontweight ? fontweight[f.weight] : f.weight;
671                        r.fontSize = g.normalizedLength(f.size);
672                        r.fontFamily = t in fonts ? fonts[t] : f.family;
673
674                        // update the transform
675                        if(!this._delay){
676                                this._delay = window.setTimeout(lang.hitch(this, "_delayAlignment"), 10);
677                        }
678                }
679        };
680
681        var C = gs.Container, Container = {
682                add: function(shape){
683                        // summary: adds a shape to a group/surface
684                        // shape: dojox.gfx.Shape: a Silverlight shape object
685                        if(this != shape.getParent()){
686                                C.add.apply(this, arguments);
687                                this.rawNode.children.add(shape.rawNode);
688                        }
689                        return this;    // self
690                },
691                remove: function(shape, silently){
692                        // summary: remove a shape from a group/surface
693                        // shape: dojox.gfx.Shape: a Silverlight shape object
694                        // silently: Boolean?: if true, regenerate a picture
695                        if(this == shape.getParent()){
696                                var parent = shape.rawNode.getParent();
697                                if(parent){
698                                        parent.children.remove(shape.rawNode);
699                                }
700                                C.remove.apply(this, arguments);
701                        }
702                        return this;    // self
703                },
704                clear: function(){
705                        // summary: removes all shapes from a group/surface
706                        this.rawNode.children.clear();
707                        return C.clear.apply(this, arguments);
708                },
709                _moveChildToFront: C._moveChildToFront,
710                _moveChildToBack:  C._moveChildToBack
711        };
712
713        var Creator = {
714                createObject: function(shapeType, rawShape){
715                        // summary: creates an instance of the passed shapeType class
716                        // shapeType: Function: a class constructor to create an instance of
717                        // rawShape: Object: properties to be passed in to the classes "setShape" method
718                        if(!this.rawNode){ return null; }
719                        var shape = new shapeType();
720                        var node = this.rawNode.getHost().content.createFromXaml("<" + shapeType.nodeType + "/>");
721                        shape.setRawNode(node);
722                        shape.setShape(rawShape);
723                        this.add(shape);
724                        return shape;   // dojox.gfx.Shape
725                }
726        };
727
728        lang.extend(sl.Text, Font);
729        //dojo.extend(sl.TextPath, Font);
730
731        lang.extend(sl.Group, Container);
732        lang.extend(sl.Group, gs.Creator);
733        lang.extend(sl.Group, Creator);
734
735        lang.extend(sl.Surface, Container);
736        lang.extend(sl.Surface, gs.Creator);
737        lang.extend(sl.Surface, Creator);
738
739        function mouseFix(s, a){
740                var ev = {target: s, currentTarget: s, preventDefault: function(){}, stopPropagation: function(){}};
741                try{
742                        if(a.source){
743                                // support silverlight 2.0
744                                ev.target = a.source;
745                                var gfxId = ev.target.tag;                             
746                                ev.gfxTarget = gs.byId(gfxId);
747                        }
748                }catch(e){
749                        // a.source does not exist in 1.0
750                }
751       
752                if(a){
753                        try{
754                                ev.ctrlKey = a.ctrl;
755                                ev.shiftKey = a.shift;
756                                var p = a.getPosition(null);
757                                ev.x = ev.offsetX = ev.layerX = p.x;
758                                ev.y = ev.offsetY = ev.layerY = p.y;
759                                // calculate clientX and clientY
760                                var parent = surfaces[s.getHost().content.root.name];
761                                var t = domGeom.position(parent);
762                                ev.clientX = t.x + p.x;
763                                ev.clientY = t.y + p.y;
764                        }catch(e){
765                                // squelch bugs in MouseLeave's implementation
766                        }
767                }
768                return ev;
769        }
770       
771        function keyFix(s, a){
772                var ev = {
773                        keyCode:  a.platformKeyCode,
774                        ctrlKey:  a.ctrl,
775                        shiftKey: a.shift
776                };
777                try{
778                        if(a.source){
779                                // source is defined from Silverlight 2+
780                                ev.target = a.source;
781                                ev.gfxTarget = gs.byId(ev.target.tag);
782                        }
783                }catch(e){
784                        // a.source does not exist in 1.0
785                }
786                return ev;
787        }
788       
789        var eventNames = {
790                onclick:                {name: "MouseLeftButtonUp", fix: mouseFix},
791                onmouseenter:   {name: "MouseEnter", fix: mouseFix},
792                onmouseleave:   {name: "MouseLeave", fix: mouseFix},
793                onmouseover:    {name: "MouseEnter", fix: mouseFix},
794                onmouseout:             {name: "MouseLeave", fix: mouseFix},
795                onmousedown:    {name: "MouseLeftButtonDown", fix: mouseFix},
796                onmouseup:              {name: "MouseLeftButtonUp", fix: mouseFix},
797                onmousemove:    {name: "MouseMove", fix: mouseFix},
798                onkeydown:              {name: "KeyDown", fix: keyFix},
799                onkeyup:                {name: "KeyUp", fix: keyFix}
800        };
801       
802        var eventsProcessing = {
803                connect: function(name, object, method){
804                        var token, n = name in eventNames ? eventNames[name] :
805                                {name: name, fix: function(){ return {}; }};
806                        if(arguments.length > 2){
807                                token = this.getEventSource().addEventListener(n.name,
808                                        function(s, a){ lang.hitch(object, method)(n.fix(s, a)); });
809                        }else{
810                                token = this.getEventSource().addEventListener(n.name,
811                                        function(s, a){ object(n.fix(s, a)); });
812                        }
813                        return {name: n.name, token: token};
814                },
815                disconnect: function(token){
816                        try{
817                                this.getEventSource().removeEventListener(token.name, token.token);
818                        }catch(e){
819                                // bail out if the node is hidden
820                        }
821                }
822        };
823       
824        lang.extend(sl.Shape, eventsProcessing);
825        lang.extend(sl.Surface, eventsProcessing);
826       
827        // patch dojox.gfx
828        g.equalSources = function(a, b){
829                // summary: compares event sources, returns true if they are equal
830                return a && b && a.equals(b);
831        };
832       
833        return sl;
834});
835
Note: See TracBrowser for help on using the repository browser.