automatically reload images when they change on disk

This commit is contained in:
Jeremy Penner 2011-02-01 08:31:41 -08:00
parent 710ea0e879
commit fe0e8713a9
9 changed files with 180 additions and 58 deletions

View file

@ -1,5 +1,7 @@
package package
{ {
import flash.display.BitmapData;
import flash.filesystem.File;
import net.flashpunk.Entity; import net.flashpunk.Entity;
import net.flashpunk.Graphic; import net.flashpunk.Graphic;
import net.flashpunk.graphics.Image; import net.flashpunk.graphics.Image;
@ -19,6 +21,14 @@ package
super(sidebar, img.scaledHeight, img); super(sidebar, img.scaledHeight, img);
} }
public function OnImgReload(bmp:BitmapData, file:File): void
{
var imgNew:Image = new Image(bmp);
imgNew.scale = sidebar.width / imgNew.width;
imgNew.alpha = img.alpha;
img = imgNew;
graphic = img;
}
override public function Fade(pct:Number):void override public function Fade(pct:Number):void
{ {
super.Fade(pct); super.Fade(pct);

View file

@ -9,11 +9,11 @@ package
*/ */
public class EvNewImg extends Event public class EvNewImg extends Event
{ {
public var rel: String; public var urp: String;
public var bmp: BitmapData; public var bmp: BitmapData;
public function EvNewImg(type: String, rel: String, bmp: BitmapData) public function EvNewImg(type: String, urp: String, bmp: BitmapData)
{ {
this.rel = rel; this.urp = urp;
this.bmp = bmp; this.bmp = bmp;
super(type); super(type);
} }

View file

@ -1,6 +1,8 @@
package package
{ {
import flash.display.Bitmap;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.filesystem.File;
import flash.geom.Point; import flash.geom.Point;
import net.flashpunk.Entity; import net.flashpunk.Entity;
import net.flashpunk.Graphic; import net.flashpunk.Graphic;
@ -15,19 +17,35 @@ package
public class Factory extends EntitySidebarImg public class Factory extends EntitySidebarImg
{ {
private var bmp: BitmapData; private var bmp: BitmapData;
private var relf: String; private var urpf: String;
public function Factory(sidebar: Sidebar, relf: String, bmp:BitmapData) private var filewatcher: FileWatcher;
public function Factory(sidebar: Sidebar, urpf: String, bmp:BitmapData)
{ {
super(sidebar, bmp); super(sidebar, bmp);
this.bmp = bmp; this.bmp = bmp;
this.relf = relf; this.urpf = urpf;
}
override public function added():void
{
super.added();
var stage: WorldStage = WorldStage(world);
filewatcher = FileWatcher.Get(stage.UabFromUrf(stage.UrfFromUrp(urpf)));
filewatcher.Register(function(bmpNew:BitmapData, file:File):void {
bmp = bmpNew;
OnImgReload(bmpNew, file);
}, this);
}
override public function removed():void
{
super.removed();
filewatcher.Unregister(this);
} }
override public function OnClick():void override public function OnClick():void
{ {
var worldStage: WorldStage = WorldStage(world); var worldStage: WorldStage = WorldStage(world);
var posMouseReal: Point = worldStage.PointRealFromScreen(new Point(Input.mouseX, Input.mouseY)); var posMouseReal: Point = worldStage.PointRealFromScreen(new Point(Input.mouseX, Input.mouseY));
var relfBmp: String = worldStage.RelFull(relf); var urffBmp: String = worldStage.UrfFromUrp(urpf);
var tok: Token = new Token(bmp, relfBmp, posMouseReal.x - this.bmp.width / 2, posMouseReal.y - this.bmp.height / 2); var tok: Token = new Token(bmp, urffBmp, posMouseReal.x - this.bmp.width / 2, posMouseReal.y - this.bmp.height / 2);
world.add(tok); world.add(tok);
worldStage.tokSelected = tok; worldStage.tokSelected = tok;
} }

64
src/FileWatcher.as Normal file
View file

@ -0,0 +1,64 @@
package
{
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.filesystem.File;
/**
* ...
* @author jjp
*/
public class FileWatcher
{
private var file: File;
private var dateModified: Date;
private var size: Number;
private var rgobj_dgOnChange: Array;
private static var mpabsf_filewatcher:Object = { };
public function FileWatcher(file: File)
{
this.file = file;
this.dateModified = file.modificationDate;
this.size = file.size;
this.rgobj_dgOnChange = [];
}
public static function Get(absf: String): FileWatcher
{
var filewatcher:FileWatcher = mpabsf_filewatcher[absf];
if (filewatcher === null)
{
filewatcher = new FileWatcher(new File(absf));
mpabsf_filewatcher[absf] = filewatcher;
}
return filewatcher;
}
public static function CheckAll():void
{
for each(var filewatcher:FileWatcher in mpabsf_filewatcher)
filewatcher.Check();
}
public function Register(dgOnChange: Function, obj:*):void {
rgobj_dgOnChange.push([obj, dgOnChange]);
}
public function Unregister(obj:*):void {
rgobj_dgOnChange = rgobj_dgOnChange.filter(function(obj_dgOnChange:Array, _:*, __:*):Boolean { return (obj_dgOnChange[0] !== obj); } );
if (rgobj_dgOnChange.length == 0)
delete mpabsf_filewatcher[file.nativePath];
}
public function Check():void
{
if (this.dateModified !== file.modificationDate || this.size !== file.size)
{
this.dateModified = file.modificationDate;
this.size = file.size;
Imgdir.LoadBmp(file, function(bmp:BitmapData, fileT:File):void {
for each(var obj_dgOnChange:Array in rgobj_dgOnChange)
obj_dgOnChange[1](bmp, fileT);
}, null);
}
}
}
}

View file

@ -17,21 +17,21 @@ package
[Embed(source = '../assets/folder.png')] [Embed(source = '../assets/folder.png')]
private const bmpFolder:Class; private const bmpFolder:Class;
private var reld: String; private var urpd: String;
private var text: Text; private var text: Text;
public function Folder(sidebar: Sidebar, reld: String) public function Folder(sidebar: Sidebar, urpd: String)
{ {
super(sidebar, bmpFolder); super(sidebar, bmpFolder);
text = new Text(reld, 2, (img.scaledHeight / 2) - 6); text = new Text(urpd, 2, (img.scaledHeight / 2) - 6);
text.color = 0x4444FF; text.color = 0x4444FF;
addGraphic(text); addGraphic(text);
this.reld = reld; this.urpd = urpd;
} }
override public function OnClick():void override public function OnClick():void
{ {
WorldStage(world).Chdir(this.reld); WorldStage(world).Chdir(this.urpd);
} }
override public function Fade(pct:Number):void override public function Fade(pct:Number):void
{ {

View file

@ -18,15 +18,15 @@ package
{ {
public static const LOADED: String = "ImgLoaded"; public static const LOADED: String = "ImgLoaded";
private var dir: File; private var dir: File;
private var mprelf_bmp: Object; private var mpurpf_bmp: Object;
private var rgreld: Object; private var rgurpd: Object;
public function Imgdir(url: String) public function Imgdir(url: String)
{ {
trace("imgdir: " + url); trace("imgdir: " + url);
this.dir = new File(url); this.dir = new File(url);
this.dir.addEventListener(FileListEvent.DIRECTORY_LISTING, OnDirUpdate); this.dir.addEventListener(FileListEvent.DIRECTORY_LISTING, OnDirUpdate);
this.mprelf_bmp = { }; this.mpurpf_bmp = { };
this.rgreld = { }; this.rgurpd = { };
} }
public function Update() : void public function Update() : void
@ -38,13 +38,13 @@ package
{ {
for each (var file: File in ev.files) for each (var file: File in ev.files)
{ {
var rel: String = file.name; var urp: String = file.name;
if (file.isDirectory && !rgreld[rel]) if (file.isDirectory && !rgurpd[urp])
{ {
rgreld[rel] = true; rgurpd[urp] = true;
dispatchEvent(new EvNewImg(LOADED, rel, null)); dispatchEvent(new EvNewImg(LOADED, urp, null));
} }
else if (!file.isDirectory && /\.(png|gif|jpg|jpeg)$/i.test(rel) && !mprelf_bmp[rel]) else if (!file.isDirectory && /\.(png|gif|jpg|jpeg)$/i.test(urp) && !mpurpf_bmp[urp])
LoadBmp(file, OnBmpLoaded); LoadBmp(file, OnBmpLoaded);
} }
} }
@ -67,7 +67,7 @@ package
} }
private function OnBmpLoaded(bmp: BitmapData, file: File) : void private function OnBmpLoaded(bmp: BitmapData, file: File) : void
{ {
mprelf_bmp[file.name] = bmp; mpurpf_bmp[file.name] = bmp;
this.dispatchEvent(new EvNewImg(LOADED, file.name, bmp)); this.dispatchEvent(new EvNewImg(LOADED, file.name, bmp));
} }
} }

View file

@ -1,10 +1,13 @@
package package
{ {
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.filesystem.File;
import flash.geom.Point; import flash.geom.Point;
import flash.geom.Rectangle; import flash.geom.Rectangle;
import net.flashpunk.Entity; import net.flashpunk.Entity;
import net.flashpunk.graphics.Image; import net.flashpunk.graphics.Image;
import net.flashpunk.Tween;
import net.flashpunk.tweens.misc.Alarm;
import net.flashpunk.utils.Draw; import net.flashpunk.utils.Draw;
import net.flashpunk.utils.Input; import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key; import net.flashpunk.utils.Key;
@ -17,16 +20,18 @@ package
{ {
private var drag: Drag; private var drag: Drag;
public var posReal: Point; public var posReal: Point;
private var relf: String; private var urff: String;
private var xml: XML; private var xml: XML;
public function Token(source:BitmapData, relf: String, x: int, y: int, xml:XML = null) private var filewatcher: FileWatcher;
public function Token(source:BitmapData, urff: String, x: int, y: int, xml:XML = null)
{ {
this.posReal = new Point(x, y); this.posReal = new Point(x, y);
super(x, y, new Image(source)); super(x, y, new Image(source));
this.type = "Token"; this.type = "Token";
this.layer = WorldStage.LAYER_TOKENS; this.layer = WorldStage.LAYER_TOKENS;
this.drag = null; this.drag = null;
this.relf = relf; this.urff = urff;
if (xml === null) if (xml === null)
this.xml = XML("<token/>"); this.xml = XML("<token/>");
else else
@ -36,6 +41,13 @@ package
{ {
return WorldStage(this.world).tokSelected === this; return WorldStage(this.world).tokSelected === this;
} }
override public function added():void
{
super.added();
FixupZoom();
filewatcher = FileWatcher.Get(WorldStage(world).UabFromUrf(urff));
filewatcher.Register(OnFileChanged, this);
}
override public function removed():void override public function removed():void
{ {
super.removed(); super.removed();
@ -44,11 +56,11 @@ package
drag.Done(); drag.Done();
drag = null; drag = null;
} }
filewatcher.Unregister(this);
} }
override public function added():void public function OnFileChanged(bmp: BitmapData, file: File): void
{ {
super.added(); graphic = new Image(bmp);
FixupZoom();
} }
private function FixupZoom(): Number private function FixupZoom(): Number
{ {
@ -99,9 +111,9 @@ package
{ {
drag = Drag.Claim(); drag = Drag.Claim();
if (drag !== null) if (drag !== null)
trace("drag claimed for " + relf); trace("drag claimed for " + urff);
else else
trace("drag failed for " + relf); trace("drag failed for " + urff);
} }
if (drag !== null) if (drag !== null)
@ -129,7 +141,7 @@ package
var xml: XML = this.xml.copy(); var xml: XML = this.xml.copy();
xml.@x = int(posReal.x); xml.@x = int(posReal.x);
xml.@y = int(posReal.y); xml.@y = int(posReal.y);
xml.@path = relf; xml.@path = urff;
return xml; return xml;
} }
} }

View file

@ -33,9 +33,8 @@ package
private var imgdir: Imgdir; private var imgdir: Imgdir;
private var drag: Drag; private var drag: Drag;
private var absd: String; private var urff: String;
private var relf: String; private var rgurpd: Array;
private var rgreld: Array;
private var alarmImgdir: Tween; private var alarmImgdir: Tween;
private var rgsidebar: Vector.<Sidebar>; private var rgsidebar: Vector.<Sidebar>;
@ -46,14 +45,15 @@ package
public var tokSelected: Token; public var tokSelected: Token;
public var zoom: Number; public var zoom: Number;
public var pointView: Point; public var pointView: Point;
public var uabd: String;
public function WorldStage(absf: String) public function WorldStage(uabf: String)
{ {
super(); super();
var match:* = /(.*\/)([^\/]*)$/.exec(absf); var match:* = /(.*\/)([^\/]*)$/.exec(uabf);
this.absd = match[1]; this.uabd = match[1];
this.relf = match[2]; this.urff = match[2];
this.rgreld = []; this.rgurpd = [];
this.rgsidebar = new Vector.<Sidebar>(); this.rgsidebar = new Vector.<Sidebar>();
var sidebarSave: Sidebar = AddSidebar(new Sidebar(FP.width - 32, FP.width, 0, 0, 32, 32, LAYER_SAVE, false, false)); var sidebarSave: Sidebar = AddSidebar(new Sidebar(FP.width - 32, FP.width, 0, 0, 32, 32, LAYER_SAVE, false, false));
@ -69,6 +69,7 @@ package
Chdir(null); Chdir(null);
ToggleUI(); ToggleUI();
Load(); Load();
addTween(new Alarm(3, FileWatcher.CheckAll, Tween.LOOPING), true);
} }
public function KillToken(tok: Token): void public function KillToken(tok: Token): void
@ -90,18 +91,23 @@ package
{ {
var entity: Entity; var entity: Entity;
if (ev.bmp === null) if (ev.bmp === null)
entity = new Folder(SidebarFind(LAYER_SIDEBAR), ev.rel); entity = new Folder(SidebarFind(LAYER_SIDEBAR), ev.urp);
else else
entity = new Factory(SidebarFind(LAYER_SIDEBAR), ev.rel, ev.bmp); entity = new Factory(SidebarFind(LAYER_SIDEBAR), ev.urp, ev.bmp);
} }
public function RelFull(relf:String = null): String public function UabFromUrf(urf:String): String
{ {
var rel:String = rgreld.join(File.separator); return uabd + urf;
if (relf !== null)
rel = rel + File.separator + relf;
return rel;
} }
public function Chdir(reld: String): void public function UrfFromUrp(urp:String): String
{
return Urfd() + urp;
}
public function Urfd(): String
{
return rgurpd.join("/") + "/";
}
public function Chdir(urpd: String): void
{ {
if (alarmImgdir !== null) if (alarmImgdir !== null)
{ {
@ -115,19 +121,19 @@ package
entity.active = false; entity.active = false;
} }
} }
if (reld === "..") if (urpd === "..")
rgreld = rgreld.slice(0, rgreld.length - 1); rgurpd = rgurpd.slice(0, rgurpd.length - 1);
else if (reld !== null) else if (urpd !== null)
rgreld.push(reld); rgurpd.push(urpd);
imgdir = new Imgdir(absd + RelFull()); imgdir = new Imgdir(UabFromUrf(Urfd()));
imgdir.addEventListener(Imgdir.LOADED, OnNewImg); imgdir.addEventListener(Imgdir.LOADED, OnNewImg);
imgdir.Update(); imgdir.Update();
alarmImgdir = this.addTween(new Alarm(3, imgdir.Update, Tween.LOOPING), true); alarmImgdir = this.addTween(new Alarm(3, imgdir.Update, Tween.LOOPING), true);
AddSidebar(new Sidebar(0, -32, 0, 0, 32, FP.height, LAYER_SIDEBAR, reld !== null /*fStartShown*/, true)); AddSidebar(new Sidebar(0, -32, 0, 0, 32, FP.height, LAYER_SIDEBAR, urpd !== null /*fStartShown*/, true));
if (rgreld.length > 0) if (rgurpd.length > 0)
OnNewImg(new EvNewImg(Imgdir.LOADED, "..", null)); OnNewImg(new EvNewImg(Imgdir.LOADED, "..", null));
} }
private function SidebarFind(layer: int):Sidebar private function SidebarFind(layer: int):Sidebar
@ -242,14 +248,14 @@ package
public function Save(): void public function Save(): void
{ {
var stream: FileStream = new FileStream(); var stream: FileStream = new FileStream();
stream.open(new File(absd + File.separator + relf), FileMode.WRITE); stream.open(new File(UabFromUrf(urff)), FileMode.WRITE);
stream.writeUTFBytes(GenXML().toXMLString()); stream.writeUTFBytes(GenXML().toXMLString());
stream.close(); stream.close();
ShowMsg("Saved."); ShowMsg("Saved.");
} }
public function Load(): void public function Load(): void
{ {
var file: File = new File(absd + File.separator + relf); var file: File = new File(UabFromUrf(urff));
if (file.exists) if (file.exists)
{ {
var stream: FileStream = new FileStream(); var stream: FileStream = new FileStream();
@ -268,7 +274,7 @@ package
private function LoadToken(xml: XML, itoken: int, rgtoken:Object): void private function LoadToken(xml: XML, itoken: int, rgtoken:Object): void
{ {
trace("loading " + xml.@path); trace("loading " + xml.@path);
Imgdir.LoadBmp(new File(absd + File.separator + xml.@path), Imgdir.LoadBmp(new File(UabFromUrf(xml.@path)),
function(bmp: BitmapData, file: File):void { function(bmp: BitmapData, file: File):void {
trace("loadtoken: " + xml.@path); trace("loadtoken: " + xml.@path);
var token: Token = new Token(bmp, xml.@path.toString(), int(xml.@x), int(xml.@y), xml); var token: Token = new Token(bmp, xml.@path.toString(), int(xml.@x), int(xml.@y), xml);

12
todo.txt Normal file
View file

@ -0,0 +1,12 @@
- fix scrollwheel sensitivity
- zoom to 100% (magnifying glass icon?)
- show 0,0, maybe some other griddy options
- finalize "library" notion
- text objects
- tilemap
- layers
DONE:
- auto image reloading