private void LinkFn(CanvasAssetFrameEditScope scope, jQueryObject element, dynamic attr)
        {
            var frameCanvas = ((CanvasElement)element[0]);
            frameCanvas.Width = scope.Width;
            frameCanvas.Height = scope.Height;

            var mousedown = false;
            element.MouseDown((e) =>
            {
                mousedown = true;
            });
            element.MouseUp((e) =>
            {
                mousedown = false;
            });

            element.MouseMove((e) =>
                              {
                                  scope.Apply(() =>
                                              {
                                                  if (!mousedown) return;
                                                  if (scope.Edit)
                                                  {
                                                      var x = e.OffsetX;
                                                      var y = e.OffsetY;

                                                      var _x = (int)(x / ((double)scope.Width / scope.Frame.Width));
                                                      var _y = (int)(y / ((double)scope.Height / scope.Frame.Height));



                                                      var halfwidth = (scope.LineWidth / 2);
                                                      int[][] map;
                                                      int setValue;
                                                      switch (scope.EditType)
                                                      {
                                                          case AssetFrameEditType.ColorMap:
                                                              setValue = scope.EditPaletteIndex;
                                                              map = scope.Frame.ColorMap;
                                                              break;
                                                          case AssetFrameEditType.HurtMap:
                                                              setValue = scope.EditPaletteIndex;
                                                              map = scope.Frame.HurtSonicMap;
                                                              break;
                                                          case AssetFrameEditType.CollisionMap:
                                                              setValue = scope.EditPaletteIndex;
                                                              map = scope.Frame.CollisionMap;
                                                              break;
                                                          case AssetFrameEditType.Offset:
                                                              scope.Frame.OffsetX = _x;
                                                              scope.Frame.OffsetY = _y;
                                                              //special
                                                              return;
                                                          default:
                                                              throw new ArgumentOutOfRangeException();
                                                      }


                                                      if (scope.LineWidth == 1)
                                                      {

                                                          map[_x][_y] = setValue;
                                                      }
                                                      else
                                                      {
                                                          for (var k = -halfwidth; k < halfwidth; k++)
                                                          {
                                                              for (var c = -halfwidth; c < halfwidth; c++)
                                                              {
                                                                  map[Math.Min(Math.Max(0, _x + k), scope.Frame.Width)][Math.Min(Math.Max(0, _y + c), scope.Frame.Height)] = setValue;
                                                              }
                                                          }
                                                      }

                                                      scope.Frame.ClearCache();


                                                  }
 
                                              });
                              });



            var frameContext = (CanvasRenderingContext2D)frameCanvas.GetContext(CanvasContextId.Render2D);


            Action updateFrame = () =>
            {
                frameContext.Canvas.Width = frameContext.Canvas.Width;
                frameContext.Me().webkitImageSmoothingEnabled = false;
                frameContext.Me().mozImageSmoothingEnabled = false;
                frameContext.Me().imageSmoothingEnabled = false;
                frameContext.Scale((double)scope.Width / scope.Frame.Width, (double)scope.Height / scope.Frame.Height);

                scope.Frame.DrawUI(frameContext, new Point(0, 0), false, scope.EditType == AssetFrameEditType.CollisionMap, scope.EditType == AssetFrameEditType.HurtMap, scope.EditType == AssetFrameEditType.Offset, false, false);
            };
            scope.Watch("frame", updateFrame);
            scope.Watch("editType", updateFrame);
            scope.Watch("frame.width", updateFrame);
            scope.Watch("frame.height", updateFrame);
            scope.Watch("frame.offsetX", updateFrame);
            scope.Watch("frame.offsetY", updateFrame);

            scope.Watch("frame.hurtSonicMap", updateFrame, true);
            scope.Watch("frame.collisionMap", updateFrame, true);
            scope.Watch("frame.colorMap", updateFrame, true);
            scope.Watch("frame.palette", updateFrame, true);

            scope.Watch("editType", updateFrame);
        }
        private void LinkFn(CanvasPieceLayoutEditScope scope, jQueryObject element, dynamic attr)
        {
            element.Width(scope.Width);
            element.Height(scope.Height);

            var mouseDown = false;
            var lastPosition = new FloatPoint(scope.Width / 2f, scope.Height / 2f);
            LevelObjectPieceLayoutPiece movingPiece = null;


            element.MouseDown((e) =>
                              {
                                  lastPosition.X = e.OffsetX;
                                  lastPosition.Y = e.OffsetY;
                                  mouseDown = true;



                                  var posX = (e.OffsetX - scope.ZeroPosition.X) / scope.Scale;
                                  var posY = (e.OffsetY - scope.ZeroPosition.Y) / scope.Scale;


                                  foreach (var levelObjectPieceLayoutPiece in scope.PieceLayout.Pieces)
                                  {

                                      LevelObjectPiece piece = scope.ObjectData.Pieces[levelObjectPieceLayoutPiece.PieceIndex];
                                      var asset = scope.ObjectData.Assets[piece.AssetIndex];
                                      if (asset.Frames.Count > 0)
                                      {
                                          var frm = asset.Frames[0];

                                          if (pointInArea(levelObjectPieceLayoutPiece.X - frm.OffsetX, levelObjectPieceLayoutPiece.Y - frm.OffsetY, 30, posX, posY))
                                          {
                                              movingPiece = levelObjectPieceLayoutPiece;
                                              scope.SelectedPieceLayoutPiece = movingPiece;


                                              lastPosition.X = posX;
                                              lastPosition.Y = posY;
                                              return;

                                          }
                                      }
                                  }


                              });

            element.MouseUp((e) =>
                            {

                                mouseDown = false;
                                movingPiece = null;
                            });

            element.MouseMove((e) => scope.Apply(() =>
                                                 {
                                                     if (!mouseDown) return;

                                                     var x = e.OffsetX;
                                                     var y = e.OffsetY;



                                                     if (movingPiece != null)
                                                     {

                                                         float posX = (e.OffsetX - scope.ZeroPosition.X) / scope.Scale;
                                                         float posY = (e.OffsetY - scope.ZeroPosition.Y) / scope.Scale;

                                                         if (Math.Abs((int)(posX - lastPosition.X)) > 0)
                                                         {
                                                             movingPiece.X += (int)(posX - lastPosition.X);
                                                             lastPosition.X = posX;
                                                         }
                                                         if (Math.Abs((int)(posY - lastPosition.Y)) > 0)
                                                         {
                                                             movingPiece.Y += (int)(posY - lastPosition.Y);
                                                             lastPosition.Y = posY;
                                                         }
                                                     }
                                                     else
                                                     {
                                                         scope.ZeroPosition.X += (int)(x - lastPosition.X);
                                                         scope.ZeroPosition.Y += (int)(y - lastPosition.Y);

                                                         lastPosition.X = e.OffsetX;
                                                         lastPosition.Y = e.OffsetY;
                                                     }
                                                 }));



            element[0].Style.Display = "inline-block";
            var context = (CanvasRenderingContext2D)((CanvasElement)element[0]).GetContext(CanvasContextId.Render2D);
            scope.Scale = 1;
            scope.ZeroPosition = new Point(0, 0);

            Action updatePieceLayout = () =>
            {
                context.Canvas.Width = context.Canvas.Width;

                context.Me().webkitImageSmoothingEnabled = false;
                context.Me().mozImageSmoothingEnabled = false;
                context.Me().imageSmoothingEnabled = false;

                context.FillStyle = "#FFFFFF";
                context.FillRect(0, 0, scope.Width, scope.Height);

                context.BeginPath();
                context.Rect(0, 0, scope.Width, scope.Height);
                context.Clip();
                context.ClosePath();

                context.Translate(scope.ZeroPosition.X, scope.ZeroPosition.Y);
                context.Scale(scope.Scale, scope.Scale);
                scope.PieceLayout.DrawUI(context, scope.ShowImages, scope.PieceLayout.Pieces.IndexOf(scope.SelectedPieceLayoutPiece), scope.ObjectData);
            };

            scope.Watch("pieceLayout", updatePieceLayout);
            scope.Watch("pieceLayout.pieces", updatePieceLayout, true);
            scope.Watch("scale", updatePieceLayout);
            scope.Watch("showImages", updatePieceLayout);
            scope.Watch("zeroPosition", updatePieceLayout, true);
            scope.Watch("selectedPieceLayoutPiece", updatePieceLayout);

        }