Sunday, January 22, 2012

Apple bites

I have to admit that after watching Apple's iBooks Author video, I was trying to figure out how to get an OS 10.7 computer to download the authoring application and an iPad to test the results and imagining authoring all kinds of marvelous content but then I got to thinking...

Now I am thinking that it is almost a moral imperative to take a pass.  

Having an easy application to create digital materials is a wonderful idea.  Forcing those materials to live in a proprietary format, available for sale in an exclusive Apple store is not.  Isn't that what Steve Jobs said he didn't like about Flash?

I guess I agree with dougpete (with thanks for the links).

Thursday, January 19, 2012

Trying out Trello

A real nugget came through by Google Reader from Joel on Software - the guy behind the Joel Test of how good a software team is (mathclips.ca gets at most 3/12 on it, BTW).  His company, Fog Creek Software, produces Trello, an online collaboration tool, that is currently free.


The CLIPS team has been trying it out for a couple of weeks and I think it is really promising.  The notification history provides a progress log.  You can create multiple checklists and easily monitor progress and you can send notifications to specific members of the team.  You can see how the Trello team uses it, by going to their development board, likely after you have signed up.  Best of all, it feels like the value of using it exceeds the effort of maintaining it.

I expect that my massive following (100 readers according to Google Reader) will flood their servers to the breaking point moments after I press the Publish button since no one I have mentioned it to has heard about it.  Here is their announcement video which is a good introduction:


Friday, January 13, 2012

AS2 Farming out compile work to a swf

Thanks to Crystal's vivid imagination, the CLIPS team has created a Hops on Lines Tool that consists of 27 .as files averaging 25K or so.  When compiled, the .swf is about 700K.  When an activity uses the Hops Tool as well as other classes, the compile can be very slow or can max out available memory and fail.  We decided to farm out the job of compiling to another .swf and load it into any activities that require it.

Unfortunately, this means that the activity.swf cannot be run standalone.  Users will either have to be online, so that the Hops .swf can be found at mathclips.ca, or they will have to save the Hops .swf to a predictable location on their hard drive.



Originally, an instance of the Hops tool was created using a call to a static create method as described in a previous post.

     HopsOnLines.create(target, "instanceName", initObj);

To farm out this work and keep all the current code backwards compatible, we rename HopsOnLines to be OriginalHopsOnLines and make the new HopsOnLines.as contain:

class HopsOnLines extends MovieClip {

 public static function init(myCreatorReference:MovieClip){
  _root.theToolCreator = myCreatorReference;
 }

 public static function create(container:MovieClip, instanceName:String, initObj:Object, depth) {
  return _root.theToolCreator.create(container, instanceName, initObj, depth);
 }
}

In order to use this new version of the class, an initialization step must be performed to tell the class where the movieclip containing the compiled swf is.
The .fla used to create the .swf contains:

System.security.allowDomain("*");
import HopsOnLinesOld;
stop();

function create(target:MovieClip, toolName:String, initObject:Object, depth:Number){
 return HopsOnLinesOld.create(target, toolName, initObject, depth);
}

In this way, the .fla compiles the HopsOnLinesOld, with all its imported classes and exposes a create method that simply shuttles the job to the legacy creator.  This is one of the few times when the .fla is many times smaller than the compiled .swf.

In order to use this compiled swf. An activity must load it into a movieclip. When it is completed, call init to tell it where that movieclip is, and then any HopsOnLines.create statements will work without any modifications. Here is some sample code from an activity .fla:

import HopsOnLines.as;
System.security.allowDomain("*");

var testingLoader:MovieClipLoader = new MovieClipLoader();
var testingListener:Object = new Object();

testingListener._parent = this;
testingLoader.addListener(testingListener);

this.createEmptyMovieClip("testingContainer", this.getNextHighestDepth());
this.createEmptyMovieClip("testingLooper", this.getNextHighestDepth());

testingLoader.loadClip("http://www.myDomain.ca/HopsOnLinesCreator.swf", this.testingContainer);

testingListener.onLoadInit = function(which){
 trace("onLoadInit with "+which);
 this._parent.testingContainer.init(this._parent.testingContainer);
 this._parent.testingContainer.create(this._parent, "myHops_mc", {_x:50, _y:50});
 if (this._parent.myHops_mc == undefined){
  trace("onLoadInit has an error not picked up by onLoadError");
 }
}

There are a couple of things that I still wonder about. I get incompatible context errors related to security and sometimes they seem to make it not work. Also, if the file does not exist, onLoadInit seems to be called rather that onLoadError.  Also, I seemed to have the make the reference in the new .as file to _root - I had tried a static property and a _global but that did not work as well, I am not sure why.

Wednesday, October 26, 2011

Improving MovieClipProxy.as?

This is the fifth post in a series.  I made a couple of  "improvements" to MovieClipProxy.as and found out a thing or two before abandoning the idea due to our sloppy coding practices that would require more fixing than I was prepared to do.

I was also happy to receive a reply from Senocular indicating that there was not a simpler way just to override the _visible setter.  He wrote:

AS3 supports native implementation overrides for getter/setters, but not AS1/AS2
In the last post, I left off wondering whether I was willing to write a getter/setter for all the properties, methods and functions of my ubPod class.

I wrote two functions for MovieClipProxy.as to add additional properties and functions to a MovieClipProxy instance, namely addProp and addFunction:

public function addProp(propName:String){
 var getterFunction:Function = function(){
  return this._mc[arguments.callee.name];
 }
 getterFunction.name = propName;
 var setterFunction:Function = function(newVal):Void{
  this._mc[arguments.callee.name] = newVal;
 }
 setterFunction.name = propName;

 this.addProperty(propName, getterFunction, setterFunction);
}
public function addFunction(propName:String){
 this[propName] = function(a, b, c, d, e, f, g, h, i, j){
  return this._mc[arguments.callee.name].call(arguments.callee.mcp_instance, a, b, c, d, e, f, g, h, i, j);
 }
 this[propName].name = propName;
 this[propName].mcp_instance = this._mc;

 //no luck getting getters and setters to work for functions
    /*
 var getterFunction:Function = function(){
  trace("in mcp getter function with name "+arguments.callee["name"]+" from "+arguments.callee);
  trace("addFunction getter");
  return this._mc[arguments.callee.name];
 }
 getterFunction.name = propName;
 var setterFunction:Function = function(f:Function){
  trace("in mcp setter function with name "+arguments.callee["name"]+" from "+arguments.callee);
  trace("addFunction setter");
  //this._mc[arguments.callee.name] = newVal;
  this._mc[arguments.callee.name] = function(a, b, c, d, e, f, g, h, i, j){return f.call(arguments.callee.mcp_instance, a, b, c, d, e, f, g, h, i, j)};
 }
 setterFunction.name = propName;
 setterFunction.mcp_instance = this._mc;

 this.addProperty(propName, getterFunction, setterFunction);
 */
}

which are invoked pretty simply with code like:

mcp.addProp("side");
mcp.addFunction("scale");

Next, I wondered if there was a way to get my ubPod class to reveal more of its properties and methods in a for..in loop. The new learning here relates to ASSetPropFlags (of which the compiler is unaware) which allowed me to write a function like:

_global["ASSetPropFlags"](ubPod.prototype,null,6,true);

for (var i in ubPod.prototype){    
    var thing = ubPod.prototype[i];
    var typeThing:String = typeof(thing)
    if (typeThing == "function" && i != "__constructor__"){
        mcp.addFunction(i);
    } else if (typeThing == 'number' || typeThing == 'string' || typeThing == 'boolean' || (typeThing == 'object' && i != "__proto__")){
        mcp.addProp(i);
    } else {
        trace("did nothing for "+i);
    }
}

Maybe some of this will help folks still in AS2 land.  I am left still pretty foggy about __proto__, prototype, extends and casting.

Here are two challenges:
  1. Find the error in the code shared in the previous post.
  2. Modify my addFunction method to allow for a getter and setter as well as a function definition to be established.

Monday, October 24, 2011

Actionscript 2: Catching when an instance of a Class that extends MovieClip is made visible

You just don't get blog post titles as precise as that every day!

I have been telling a story today about trying to catch when a movieclip's _visible property is set.  First, I showed how we create classes that extend MovieClip.  Next, I described the problems that I am having writing a set and get function for _visibleThird, I showed how MovieClipProxy could be used on a simple MovieClip to catch the setting of _visible.  Now, I am going to finish the story and show how it can be done for a class like ubSquare.

The first step is to make a slight adjustment to MovieClipProxy.   Its constructor is written to either take 3 parameters and create an empty MovieClip or 4 parameters and attach a movieclip from the library.  I changed it so that if it is sent more, it will use the first parameter to create the movieclip.

In the first post's example, we created the ubSquare using:

this.mySquare_ubS = ubSquare.create(this, "mySquare_mc", {_x:50, _y:75, _side:10});

So if we change the constructor of MovieClipProxy to read:

 function MovieClipProxy(a,b,c,d,e) {
  var mc, mc2;
  if (arguments.length == 3) {
   mc = __initEmpty(a,b,c);
  } else if (arguments.length == 4){
   mc = __initAttached(a,b,c,d);
  } else {
   mc = a(b,c,d,e);
  }
  __applyPrototyped(mc);
 }

Then we can invoke it with:
 var mcp:MovieClipProxy = new MovieClipProxy(ubSquare.create, container, instanceName, initObj, depth);

and the created MovieClip will now be a ubSquare.

But, ubSquare had a side property and a scale method that are not handled by MovieClipProxy.  I can create a ubSquareProxy Class

import edu.clips.test.MovieClipProxy;
import edu.clips.test.ubSquare;

class edu.clips.test.ubSquareProxy extends MovieClipProxy {
 
 public static function create(container:MovieClip, instanceName:String,
         initObj:Object, depth:Number) {
  if (depth == undefined) depth = container.getNextHighestDepth();
  var mcp:MovieClipProxy = new MovieClipProxy(ubSquare.create, container, instanceName, initObj, depth);

  //define all the ubSquare properties, methods and functions
  mcp["scale"] = function(newScale:Number){
   trace("in ubSquareProxy.scale "+ mcp._mc);
   mcp._mc.scale(newScale);
  }
  mcp.addProperty("side", 
      function(){trace("addProperty getter");return this._mc.side}, 
      function(newSide){trace("addProperty setter");this._mc.side = newSide});
  return mcp;
 }
}

and create it using:

this.mySquare_ubS = ubSquareProxy.create(this, "mySquare_mc", {_x:50, _y:75, _side:10});

Now the questions that I am left with are these:
  1. Is it worth the time to apply this method to my ubPod class with 80 documented properties, 23 methods and 7 event handlers just to capture when the one MovieClip property, _visible, changes?
  2. Is there a way to use __proto__ or prototype or constructor to access the MovieClip's setter for _visible and just change that to broadcast an event?
  3. Should ubSquareProxy extend MovieClipProxy, MovieClip or nothing?

Actionscript 2: One Way to catch when a MovieClip becomes visible

In my previous post, I outlined the difficulties that I have been having reacting to when a MovieClip becomes visible.  I think the big reason for these difficulties is that _visible is a MovieClip property that is impossible to override with getters and setters.

However, I happened to be trolling around Senocular's site and found his MovieClipProxy class.  This class creates an object with all of the standard MovieClip properties with getter and setter functions and all the standard MovieClip methods together with the standard functions, like onEnterFrame, envoked using the call statement and the correct scope.

If I change the setter and getter for _visible as follows:

 function get _visible():Boolean {
  trace("get _visible");
  return _mc._visible; 
 }
 function set _visible(v:Boolean):Void {
  trace("set _visible");
  this._xscale *=2;
  _mc._visible = v; 
 }

Note that I am just setting the _xscale when _visible is set just for a double visual confirmation.

If you create a new Actionscript 2 .fla tester file with the code:

import edu.clips.test.MovieClipProxy;

var mcp:MovieClipProxy = 
 new MovieClipProxy(this, "test", 1);

trace("_xscale before first set _visible "+mcp._xscale);
mcp._visible = false;

mcp.clear();
mcp.lineStyle(2, 0x0000FF, 100, true);
mcp.moveTo(0, 0);
mcp.lineTo(200, 100);

trace("_xscale before second set _visible "+mcp._xscale);
mcp._visible = false;
trace("_xscale after second _visible "+mcp._xscale);

this.test._visible = true;
trace("_xscale after movieClip set _visible "+mcp._xscale);
trace("or "+this.test._xscale);

and test it, you get the output:

_xscale before first set _visible 100
set _visible
get _visible
_xscale before second set _visible 200
set _visible
get _visible
_xscale after second _visible 400
_xscale after movieClip set _visible 400
or 400

When you reference the MovieClipProxy object mcp, the setters and getters are used and applied to the  MovieClip this.test.  When you reference this.test._visible directly, the setter is not used.

Now you are in the position to capturing the setting of _visible and do something more sensible than upscaling, as long as you create a MovieClipProxy and reference it.

This still leaves the question of whether this approach can be bolted on to the method we are using to create Classes that extend MovieClip.


Actionscript 2: Trouble overriding setter for MovieClip Properties like _visible

In my previous post, I described how we create classes to extend MovieClip.

Continuing with the ubSquare example, now let's suppose that I want to scale my square whenever it becomes visible.  Well, _visible is a property of the class, just like side was so how about adding some code like:

//at the top with _side
private var __visible:Boolean = true;

//with the side getter and setters
public function get _visible():Boolean{
 trace("in ubSquare get _visible");
 return this.__visible;
}
public function set _visible(newVis:Boolean):Void{
 trace("in ubSquare set _visible");
 this.__visible = newVis;
 this._visible = newVis;
}

This is just like what I did for side, except that I can't just change my private __visible property and expect the movieclip to change, so I add the last line to tell the movieclip to actually change its visibility.

There are two problems with this:
  1. If I put a line like:
    this.mySquare_ubS._visible = false;
    in my tester, the set function is not called.
  2. If I put a line like
    this._visible = true;
    in my scale method, I get 256 levels of recursion since the set for _visible calls itself.
One way to fix the second problem is to change the last line of the set _visible function from:
this._visible = newVis;
to
setProperty(this, _visible, newVis);

The output becomes:

scale making movieclip visible true
in ubSquare set _visible
in ubSquare get _visible

This, of course, begs three questions:
  1. what is the point of writing a setter for _visible if it can be avoided by using a (deprecated) setProperty operation?
  2. why is a get _visible call made when I set _visible? The line in the scale method (this._visible = true) calls both the setter and the getter.  I was sure I had a good link that explained why but cannot for the life of me find it now.
  3. how do I solve the first problem which was the important one?  I want to be able to notice when anything makes my square visible, not just when some of my own class code does.
I have figured out one way to catch the setting of _visible for a MovieClip, which I will blog about next, but have yet to figure out how to apply it to a Class that extends MovieClip.