From fe0e8713a97a725a8959415f9716d9b0e3b425cd Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Tue, 1 Feb 2011 08:31:41 -0800 Subject: [PATCH] automatically reload images when they change on disk --- src/EntitySidebarImg.as | 10 +++++++ src/EvNewImg.as | 6 ++-- src/Factory.as | 28 ++++++++++++++---- src/FileWatcher.as | 64 +++++++++++++++++++++++++++++++++++++++++ src/Folder.as | 10 +++---- src/Imgdir.as | 20 ++++++------- src/Token.as | 30 +++++++++++++------ src/WorldStage.as | 58 ++++++++++++++++++++----------------- todo.txt | 12 ++++++++ 9 files changed, 180 insertions(+), 58 deletions(-) create mode 100644 src/FileWatcher.as create mode 100644 todo.txt diff --git a/src/EntitySidebarImg.as b/src/EntitySidebarImg.as index 9e747e3..bffec2e 100644 --- a/src/EntitySidebarImg.as +++ b/src/EntitySidebarImg.as @@ -1,5 +1,7 @@ package { + import flash.display.BitmapData; + import flash.filesystem.File; import net.flashpunk.Entity; import net.flashpunk.Graphic; import net.flashpunk.graphics.Image; @@ -19,6 +21,14 @@ package 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 { super.Fade(pct); diff --git a/src/EvNewImg.as b/src/EvNewImg.as index 3e6be1f..1dc14c2 100644 --- a/src/EvNewImg.as +++ b/src/EvNewImg.as @@ -9,11 +9,11 @@ package */ public class EvNewImg extends Event { - public var rel: String; + public var urp: String; 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; super(type); } diff --git a/src/Factory.as b/src/Factory.as index 18ca938..a7add19 100644 --- a/src/Factory.as +++ b/src/Factory.as @@ -1,6 +1,8 @@ package { + import flash.display.Bitmap; import flash.display.BitmapData; + import flash.filesystem.File; import flash.geom.Point; import net.flashpunk.Entity; import net.flashpunk.Graphic; @@ -15,19 +17,35 @@ package public class Factory extends EntitySidebarImg { private var bmp: BitmapData; - private var relf: String; - public function Factory(sidebar: Sidebar, relf: String, bmp:BitmapData) + private var urpf: String; + private var filewatcher: FileWatcher; + public function Factory(sidebar: Sidebar, urpf: String, bmp:BitmapData) { super(sidebar, 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 { var worldStage: WorldStage = WorldStage(world); var posMouseReal: Point = worldStage.PointRealFromScreen(new Point(Input.mouseX, Input.mouseY)); - var relfBmp: String = worldStage.RelFull(relf); - var tok: Token = new Token(bmp, relfBmp, posMouseReal.x - this.bmp.width / 2, posMouseReal.y - this.bmp.height / 2); + var urffBmp: String = worldStage.UrfFromUrp(urpf); + var tok: Token = new Token(bmp, urffBmp, posMouseReal.x - this.bmp.width / 2, posMouseReal.y - this.bmp.height / 2); world.add(tok); worldStage.tokSelected = tok; } diff --git a/src/FileWatcher.as b/src/FileWatcher.as new file mode 100644 index 0000000..de30ded --- /dev/null +++ b/src/FileWatcher.as @@ -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); + } + } + } + +} \ No newline at end of file diff --git a/src/Folder.as b/src/Folder.as index 34401eb..69a33f3 100644 --- a/src/Folder.as +++ b/src/Folder.as @@ -17,21 +17,21 @@ package [Embed(source = '../assets/folder.png')] private const bmpFolder:Class; - private var reld: String; + private var urpd: String; private var text: Text; - public function Folder(sidebar: Sidebar, reld: String) + public function Folder(sidebar: Sidebar, urpd: String) { super(sidebar, bmpFolder); - text = new Text(reld, 2, (img.scaledHeight / 2) - 6); + text = new Text(urpd, 2, (img.scaledHeight / 2) - 6); text.color = 0x4444FF; addGraphic(text); - this.reld = reld; + this.urpd = urpd; } override public function OnClick():void { - WorldStage(world).Chdir(this.reld); + WorldStage(world).Chdir(this.urpd); } override public function Fade(pct:Number):void { diff --git a/src/Imgdir.as b/src/Imgdir.as index 17610ca..c1a811d 100644 --- a/src/Imgdir.as +++ b/src/Imgdir.as @@ -18,15 +18,15 @@ package { public static const LOADED: String = "ImgLoaded"; private var dir: File; - private var mprelf_bmp: Object; - private var rgreld: Object; + private var mpurpf_bmp: Object; + private var rgurpd: Object; public function Imgdir(url: String) { trace("imgdir: " + url); this.dir = new File(url); this.dir.addEventListener(FileListEvent.DIRECTORY_LISTING, OnDirUpdate); - this.mprelf_bmp = { }; - this.rgreld = { }; + this.mpurpf_bmp = { }; + this.rgurpd = { }; } public function Update() : void @@ -38,13 +38,13 @@ package { for each (var file: File in ev.files) { - var rel: String = file.name; - if (file.isDirectory && !rgreld[rel]) + var urp: String = file.name; + if (file.isDirectory && !rgurpd[urp]) { - rgreld[rel] = true; - dispatchEvent(new EvNewImg(LOADED, rel, null)); + rgurpd[urp] = true; + 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); } } @@ -67,7 +67,7 @@ package } 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)); } } diff --git a/src/Token.as b/src/Token.as index e011d6b..77a614b 100644 --- a/src/Token.as +++ b/src/Token.as @@ -1,10 +1,13 @@ package { import flash.display.BitmapData; + import flash.filesystem.File; import flash.geom.Point; import flash.geom.Rectangle; import net.flashpunk.Entity; import net.flashpunk.graphics.Image; + import net.flashpunk.Tween; + import net.flashpunk.tweens.misc.Alarm; import net.flashpunk.utils.Draw; import net.flashpunk.utils.Input; import net.flashpunk.utils.Key; @@ -17,16 +20,18 @@ package { private var drag: Drag; public var posReal: Point; - private var relf: String; + private var urff: String; 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); super(x, y, new Image(source)); this.type = "Token"; this.layer = WorldStage.LAYER_TOKENS; this.drag = null; - this.relf = relf; + this.urff = urff; if (xml === null) this.xml = XML(""); else @@ -36,6 +41,13 @@ package { 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 { super.removed(); @@ -44,11 +56,11 @@ package drag.Done(); drag = null; } + filewatcher.Unregister(this); } - override public function added():void + public function OnFileChanged(bmp: BitmapData, file: File): void { - super.added(); - FixupZoom(); + graphic = new Image(bmp); } private function FixupZoom(): Number { @@ -99,9 +111,9 @@ package { drag = Drag.Claim(); if (drag !== null) - trace("drag claimed for " + relf); + trace("drag claimed for " + urff); else - trace("drag failed for " + relf); + trace("drag failed for " + urff); } if (drag !== null) @@ -129,7 +141,7 @@ package var xml: XML = this.xml.copy(); xml.@x = int(posReal.x); xml.@y = int(posReal.y); - xml.@path = relf; + xml.@path = urff; return xml; } } diff --git a/src/WorldStage.as b/src/WorldStage.as index 7ce7019..0af873f 100644 --- a/src/WorldStage.as +++ b/src/WorldStage.as @@ -33,9 +33,8 @@ package private var imgdir: Imgdir; private var drag: Drag; - private var absd: String; - private var relf: String; - private var rgreld: Array; + private var urff: String; + private var rgurpd: Array; private var alarmImgdir: Tween; private var rgsidebar: Vector.; @@ -46,14 +45,15 @@ package public var tokSelected: Token; public var zoom: Number; public var pointView: Point; + public var uabd: String; - public function WorldStage(absf: String) + public function WorldStage(uabf: String) { super(); - var match:* = /(.*\/)([^\/]*)$/.exec(absf); - this.absd = match[1]; - this.relf = match[2]; - this.rgreld = []; + var match:* = /(.*\/)([^\/]*)$/.exec(uabf); + this.uabd = match[1]; + this.urff = match[2]; + this.rgurpd = []; this.rgsidebar = new Vector.(); 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); ToggleUI(); Load(); + addTween(new Alarm(3, FileWatcher.CheckAll, Tween.LOOPING), true); } public function KillToken(tok: Token): void @@ -90,18 +91,23 @@ package { var entity: Entity; if (ev.bmp === null) - entity = new Folder(SidebarFind(LAYER_SIDEBAR), ev.rel); + entity = new Folder(SidebarFind(LAYER_SIDEBAR), ev.urp); 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); - if (relf !== null) - rel = rel + File.separator + relf; - return rel; + return uabd + urf; } - 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) { @@ -115,19 +121,19 @@ package entity.active = false; } } - if (reld === "..") - rgreld = rgreld.slice(0, rgreld.length - 1); - else if (reld !== null) - rgreld.push(reld); + if (urpd === "..") + rgurpd = rgurpd.slice(0, rgurpd.length - 1); + else if (urpd !== null) + rgurpd.push(urpd); - imgdir = new Imgdir(absd + RelFull()); + imgdir = new Imgdir(UabFromUrf(Urfd())); imgdir.addEventListener(Imgdir.LOADED, OnNewImg); imgdir.Update(); 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)); } private function SidebarFind(layer: int):Sidebar @@ -242,14 +248,14 @@ package public function Save(): void { 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.close(); ShowMsg("Saved."); } public function Load(): void { - var file: File = new File(absd + File.separator + relf); + var file: File = new File(UabFromUrf(urff)); if (file.exists) { var stream: FileStream = new FileStream(); @@ -268,7 +274,7 @@ package private function LoadToken(xml: XML, itoken: int, rgtoken:Object): void { 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 { trace("loadtoken: " + xml.@path); var token: Token = new Token(bmp, xml.@path.toString(), int(xml.@x), int(xml.@y), xml); diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..cadabec --- /dev/null +++ b/todo.txt @@ -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