[gui] update

This commit is contained in:
2019-03-06 17:07:26 +03:00
parent c2ab82b351
commit b0824773c9
46 changed files with 583 additions and 737 deletions

35
src/main/haxework/App.hx Normal file
View File

@@ -0,0 +1,35 @@
package haxework;
import haxework.gui.Root;
import haxework.gui.IView;
import flash.Lib;
import haxework.animate.Animate;
import haxework.animate.FadeAnimate;
import haxework.animate.UnFadeAnimate;
import haxework.gui.popup.PopupManager;
import haxework.net.manage.ILoaderManager;
import haxework.net.manage.LoaderManager;
import haxework.resources.IResources;
import haxework.resources.Resources;
class App {
@:provide var app:App;
@:provide var resources:IResources;
@:provide var loaderManager:ILoaderManager;
@:provide var popupManager:PopupManager;
public function new() {
resources = new Resources();
loaderManager = new LoaderManager();
popupManager = new PopupManager();
popupManager.showAnimateFactory = UnFadeAnimate;
popupManager.closeAnimateFactory = FadeAnimate;
app = this;
}
public function start(view:IView<Dynamic>) {
Animate.bind(Lib.current.stage);
Root.bind(view);
}
}

View File

@@ -4,50 +4,51 @@ import flash.events.Event;
import flash.display.Stage;
class Animate implements IAnimate {
public static var defaultDuraion = 300;
private static var running:Array<IAnimate> = new Array<IAnimate>();
private static var running:Array<IAnimate> = new Array<IAnimate>();
public static function bind(stage:Stage):Void {
stage.addEventListener(Event.ENTER_FRAME, function(_) {
Animate.updateAll();
});
}
public static function updateAll():Void {
if (running.length > 0) {
var time = Date.now().getTime();
for (animate in running) animate.update(time);
public static function bind(stage:Stage):Void {
stage.addEventListener(Event.ENTER_FRAME, function(_) {
Animate.updateAll();
});
}
}
private var callback:Animate -> Void;
private var duration:Int;
private var startTime:Float;
private var progress:Float;
public function new(duration:Int) {
this.duration = duration;
}
public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void {
startTime = Date.now().getTime();
this.callback = callback;
if (!custom) running.push(this);
update(startTime);
}
private function update(time:Float):Void {
progress = (time - startTime) / duration;
if (progress >= 1) {
running.remove(this);
if (callback != null) {
callback(this);
callback = null;
}
public static function updateAll():Void {
if (running.length > 0) {
var time = Date.now().getTime();
for (animate in running) animate.update(time);
}
}
}
public function cancel():Void {
if (!Math.isNaN(startTime)) update(startTime + duration);
}
private var callback:Animate -> Void;
private var duration:Int;
private var startTime:Float;
private var progress:Float;
public function new(duration:Int) {
this.duration = duration > -1 ? duration : defaultDuraion;
}
public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
startTime = Date.now().getTime();
this.callback = callback;
if (!custom) running.push(this);
update(startTime);
}
private function update(time:Float):Void {
progress = (time - startTime) / duration;
if (progress >= 1) {
running.remove(this);
if (callback != null) {
callback(this);
callback = null;
}
}
}
public function cancel():Void {
if (!Math.isNaN(startTime)) update(startTime + duration);
}
}

View File

@@ -1,63 +1,62 @@
package haxework.animate;
import flash.display.DisplayObjectContainer;
import haxework.animate.IAnimate;
import flash.display.Sprite;
import haxework.gui.IView;
import haxework.animate.Animate;
import haxework.animate.IAnimate;
import haxework.gui.IView;
class CircleMaskAnimate extends Animate {
private var view:IView;
private var mask:Sprite;
private var cyrcle:Sprite;
private var size:Float;
private var view:IView<Dynamic>;
private var mask:Sprite;
private var cyrcle:Sprite;
private var size:Float;
public function new(view:IView, ?duration:Int = 1000) {
super(duration);
this.view = view;
this.mask = new Sprite();
this.cyrcle = new Sprite();
}
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void {
var width = view.parent.width;
var height = view.parent.height;
size = Math.sqrt(width * width + height * height);
//size = Math.max(width, height);
cyrcle.x = mask.x = -(size - width) / 2 - size;
cyrcle.y = mask.y = -(size - height) / 2 - size;
redraw(size, size);
view.parent.container.addChild(mask);
view.content.mask = mask;
view.parent.container.addChild(cyrcle);
super.start(callback, custom);
}
private function redraw(size:Float, r:Float):Void {
mask.graphics.clear();
mask.graphics.beginFill(0xffffff);
mask.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
mask.graphics.endFill();
cyrcle.graphics.clear();
cyrcle.graphics.lineStyle(8, 0xffffff);
cyrcle.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
cyrcle.graphics.lineStyle();
}
override private function update(time:Float):Void {
super.update(time);
redraw(size, size * progress);
if (progress >= 1 && view.content.parent != null) {
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
view.content.mask = null;
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
public function new(view:IView<Dynamic>, duration:Int = -1) {
super(duration);
this.view = view;
this.mask = new Sprite();
this.cyrcle = new Sprite();
}
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
var width = view.parent.width;
var height = view.parent.height;
size = Math.sqrt(width * width + height * height);
//size = Math.max(width, height);
cyrcle.x = mask.x = -(size - width) / 2 - size;
cyrcle.y = mask.y = -(size - height) / 2 - size;
redraw(size, size);
view.parent.container.addChild(mask);
view.content.mask = mask;
view.parent.container.addChild(cyrcle);
super.start(callback, custom);
}
private function redraw(size:Float, r:Float):Void {
mask.graphics.clear();
mask.graphics.beginFill(0xffffff);
mask.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
mask.graphics.endFill();
cyrcle.graphics.clear();
cyrcle.graphics.lineStyle(4, 0xffffff);
cyrcle.graphics.drawCircle(size + size / 2, size + size / 2, r / 2);
cyrcle.graphics.lineStyle();
}
override private function update(time:Float):Void {
super.update(time);
redraw(size, size * progress);
if (progress >= 1 && view.content.parent != null) {
if (view.content.parent.contains(mask)) view.content.parent.removeChild(mask);
view.content.mask = null;
if (view.content.parent.contains(cyrcle)) view.parent.container.removeChild(cyrcle);
}
}
}
}

View File

@@ -1,29 +1,29 @@
package haxework.animate;
import flash.display.DisplayObject;
import haxework.animate.IAnimate;
import flash.display.Sprite;
import haxework.gui.IView;
import haxework.animate.Animate;
class FadeAnimate extends Animate {
private var view:IView;
private var view:IView<DisplayObject>;
public function new(view:IView, ?duration = 500) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void {
view.content.alpha = 1.0;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.alpha = 1 - (progress * 1.0);
if (progress >= 1) {
view.content.alpha = 0.0;
public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.alpha = 1.0;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.alpha = 1 - (progress * 1.0);
if (progress >= 1) {
view.content.alpha = 0.0;
}
}
}
}

View File

@@ -2,8 +2,9 @@ package haxework.animate;
interface IAnimate {
public function start(callback:IAnimate->Void, ?custom:Bool = false):Void;
public function cancel():Void;
public function start(callback:IAnimate -> Void, custom:Bool = false):Void;
private function update(time:Float):Void;
}
public function cancel():Void;
private function update(time:Float):Void;
}

View File

@@ -0,0 +1,24 @@
package haxework.animate;
import flash.display.DisplayObject;
import haxework.gui.IView;
class SlideAnimate extends Animate {
private var view:IView<DisplayObject>;
public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.x = view.x - this.view.width + this.view.width / progress;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.x = view.x - this.view.width + this.view.width / Math.min(1, progress);
}
}

View File

@@ -1,28 +1,28 @@
package haxework.animate;
import flash.display.Sprite;
import flash.display.DisplayObject;
import haxework.gui.IView;
import haxework.animate.Animate;
class UnFadeAnimate extends Animate {
private var view:IView;
private var view:IView<DisplayObject>;
public function new(view:IView, ?duration = 500) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, ?custom:Bool = false):Void {
view.content.alpha = 0.0;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.alpha = progress * 1.0;
if (progress >= 1) {
view.content.alpha = 1.0;
public function new(view:IView<DisplayObject>, duration:Int = -1) {
super(duration);
this.view = view;
}
override public function start(callback:IAnimate -> Void, custom:Bool = false):Void {
view.content.alpha = 0.0;
super.start(callback, custom);
}
override private function update(time:Float):Void {
super.update(time);
view.content.alpha = progress * 1.0;
if (progress >= 1) {
view.content.alpha = 1.0;
}
}
}
}

View File

@@ -1,5 +0,0 @@
package haxework.core;
interface IDisposable {
public function dispose():Void;
}

View File

@@ -1,133 +0,0 @@
package haxework.core;
typedef Tuple2#if!H<T1, T2>#end = {
var first(default, null):T1;
var second(default, null):T2;
}
typedef Tuple3#if!H<T1, T2, T3>#end = {> Tuple2<T1, T2>,
var third(default, null):T3;
}
typedef Tuple4#if!H<T1, T2, T3, T4>#end = {> Tuple3<T1, T2, T3>,
var fourth(default, null):T4;
}
typedef Tuple5#if!H<T1, T2, T3, T4, T5>#end = {> Tuple4<T1, T2, T3, T4>,
var fifth(default, null):T5;
}
class Tuple {
public static function five<T1, T2, T3, T4, T5>(first:T1, second:T2, third:T3, fourth:T4, fifth:T5):Tuple5<T1, T2, T3, T4, T5> {
return new InternalTuple5(first, second, third, fourth, fifth);
}
public static function four<T1, T2, T3, T4>(first:T1, second:T2, third:T3, fourth:T4):Tuple4<T1, T2, T3, T4> {
return new InternalTuple4(first, second, third, fourth);
}
public static function three<T1, T2, T3>(first:T1, second:T2, third:T3):Tuple3<T1, T2, T3> {
return new InternalTuple3(first, second, third);
}
public static function two<T1, T2>(first:T1, second:T2):Tuple2<T1, T2> {
return new InternalTuple2(first, second);
}
public static inline function asTuple2<T1, T2, T3>(tuple:Tuple3<T1, T2, T3>):Tuple2<T1, T2>
return tuple;
public static inline function asTuple3<T1, T2, T3, T4>(tuple:Tuple4<T1, T2, T3, T4>):Tuple3<T1, T2, T3>
return tuple;
public static inline function asTuple4<T1, T2, T3, T4, T5>(tuple:Tuple5<T1, T2, T3, T4, T5>):Tuple4<T1, T2, T3, T4>
return tuple;
}
private class InternalTuple2<T1, T2> {
public var first(default, null):T1;
public var second(default, null):T2;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
*/
public function new(first:T1, second:T2) {
this.first = first;
this.second = second;
}
public function toString():String {
return "(" + first + ", " + second + ")";
}
}
private class InternalTuple3<T1, T2, T3> extends InternalTuple2<T1, T2> {
public var third(default, null):T3;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
*/
public function new(first:T1, second:T2, third:T3) {
super(first, second);
this.third = third;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ")";
}
}
private class InternalTuple4<T1, T2, T3, T4> extends InternalTuple3<T1, T2, T3> {
public var fourth(default, null):T4;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
* @param fourth The fourth value.
*/
public function new(first:T1, second:T2, third:T3, fourth:T4) {
super(first, second, third);
this.fourth = fourth;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ", "
+ fourth + ")";
}
}
private class InternalTuple5<T1, T2, T3, T4, T5> extends InternalTuple4<T1, T2, T3, T4> {
public var fifth(default, null):T5;
/**
* Creates a new tuple.
* @param first The first value.
* @param second The second value.
* @param third The third value.
* @param fourth The fourth value.
* @param fifth The fifth value.
*/
public function new(first:T1, second:T2, third:T3, fourth:T4, fifth:T5) {
super(first, second, third, fourth);
this.fifth = fifth;
}
public override function toString():String {
return "("
+ first + ", "
+ second + ", "
+ third + ", "
+ fourth + ", "
+ fifth + ")";
}
}

View File

@@ -1,57 +0,0 @@
package haxework.gui;
import haxe.Timer;
import flash.display.Bitmap;
import flash.display.BitmapData;
import haxework.gui.SpriteView;
class AnimateView extends SpriteView {
private var bitmap:Bitmap;
public var frames(default, set):Array<BitmapData>;
public var interval(default, set):Int;
private var frame:Int;
public function new() {
super();
bitmap = new Bitmap();
frames = [];
frame = 0;
interval = 200;
content.addChild(bitmap);
changeFrame();
}
private function set_frames(value:Array<BitmapData>):Array<BitmapData> {
if (frames != value) {
frames = value;
frame = 0;
changeFrame(true);
}
return frames;
}
private function set_interval(value:Int):Int {
if (interval != value) {
interval = value;
}
return interval;
}
private function changeFrame(?forse:Bool = false):Void {
frame = ++frame % frames.length;
bitmap.bitmapData = frames[frame];
update();
if (!forse) Timer.delay(function() changeFrame(false), interval);
}
override public function update():Void {
if (contentSize && bitmap.bitmapData != null) {
width = bitmap.bitmapData.width;
height = bitmap.bitmapData.height;
}
super.update();
bitmap.x = (width - bitmap.width) / 2;
bitmap.y = (height - bitmap.height) / 2;
}
}

View File

@@ -4,10 +4,12 @@ import flash.display.DisplayObject;
import flash.events.MouseEvent;
import haxework.signal.Signal;
typedef Factory<D> = Int -> D -> IView<Dynamic>
class DataView<D> extends GroupView {
public var data(default, set):Array<D>;
public var factory(default, default):Int -> D -> IView<Dynamic>;
public var factory(default, set):Factory<D>;
public var onItemSelect(default, null):Signal3<Int, D, IView<Dynamic>> = new Signal3();
public var onDataSelect(default, null):Signal<D> = new Signal();
@@ -15,10 +17,16 @@ class DataView<D> extends GroupView {
private function set_data(value:Array<D>):Array<D> {
data = value;
rebuild();
if (factory != null) rebuild();
return data;
}
private function set_factory(value:Factory<D>):Factory<D> {
factory = value;
if (data != null) rebuild();
return factory;
}
private function rebuild():Void {
for (view in views) {
view.content.removeEventListener(MouseEvent.CLICK, onItemClick);

View File

@@ -17,6 +17,7 @@ interface IView<C:DisplayObject> {
public var content(default, null):C;
public var skin(default, set):SkinSet;
public var skinId(null, set):String;
public var parent(default, null):Null<IGroupView>;

View File

@@ -2,6 +2,7 @@ package haxework.gui;
import flash.display.BitmapData;
import haxework.gui.skin.BitmapSkin;
import haxework.gui.skin.ISkin;
import haxework.gui.utils.DrawUtil.FillType;
import haxework.net.ImageLoader;
@@ -9,22 +10,29 @@ class ImageView extends SpriteView {
public var image(default, set):BitmapData;
public var imageUrl(default, set):String;
public var fillType(default, set):FillType;
public function new(?image:BitmapData) {
private var bitmapSkin:BitmapSkin = new BitmapSkin();
public function new(image:BitmapData = null) {
super();
fillType = FillType.DEFAULT;
if (image != null) {
this.image = image;
}
}
override private function set_skin(value:SkinSet):SkinSet {
value = value.slice(0);
value.unshift(bitmapSkin);
return super.set_skin(value);
}
private function set_image(value:BitmapData):BitmapData {
if (image != value) {
image = value;
skin = [new BitmapSkin(image, FillType.DEFAULT)];
//geometry.size.content.width = value.width;
//geometry.size.content.height = value.height;
//toUpdate();
//toRedraw();
bitmapSkin.image = value;
toRedraw();
}
return image;
}
@@ -34,8 +42,15 @@ class ImageView extends SpriteView {
imageUrl = value;
new ImageLoader().GET(imageUrl).then(function(data) {
image = data;
});
}).catchError(function(e) L.w("ImageView", "load", e));
}
return imageUrl;
}
private function set_fillType(value:FillType):FillType {
if (fillType != value) {
bitmapSkin.fillType = fillType = value;
}
return fillType;
}
}

View File

@@ -7,10 +7,9 @@ import flash.errors.Error;
import flash.events.Event;
import flash.geom.Rectangle;
import flash.Lib;
import haxework.core.IDisposable;
import haxework.signal.Signal;
class Root implements IDisposable {
class Root {
public static function bind(view:IView<Dynamic>, autoSize:Bool = true) {
new Root(view, autoSize);

View File

@@ -144,7 +144,7 @@ class TextView extends SpriteView implements ITextView {
private function updateTextSize():Void {
var size = TextUtil.getSize(textField);
setContentSize(size.x, size.y);
setContentSize(size.x, size.y, "text");
}
override public function update():Void {
@@ -168,7 +168,7 @@ class TextView extends SpriteView implements ITextView {
private function placeTextField(textField:TextField):Void {
textField.width = width;
textField.height = geometry.size.content.height;
textField.height = geometry.size.content.exists("text") ? geometry.size.content.get("text").height : height;
textField.x = switch (layout.hAlign) {
case LEFT | NONE: geometry.padding.left;
@@ -178,8 +178,8 @@ class TextView extends SpriteView implements ITextView {
}
textField.y = switch (layout.vAlign) {
case TOP | NONE: geometry.padding.top;
case MIDDLE: (height - geometry.size.content.height) / 2 + geometry.padding.top - geometry.padding.bottom;
case BOTTOM: height - geometry.size.content.height - geometry.padding.bottom;
case MIDDLE: (height - textField.height) / 2 + geometry.padding.top - geometry.padding.bottom;
case BOTTOM: height - textField.height - geometry.padding.bottom;
default: 0;
}
}

View File

@@ -1,12 +1,14 @@
package haxework.gui;
import haxework.gui.skin.ISkin.ISizeSkin;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import haxework.gui.core.Geometry;
import haxework.gui.skin.ISkin.ISizeSkin;
import haxework.gui.skin.ISkin.SkinSet;
import haxework.resources.IResources;
class View<C:DisplayObject> implements IView<C> {
@:provide private var r:IResources;
private static var counter:Int = 0;
public static var updater(default, null):ViewUpdater = new ViewUpdater();
@@ -23,6 +25,7 @@ class View<C:DisplayObject> implements IView<C> {
public var content(default, null):C;
public var skin(default, set):SkinSet;
public var skinId(null, set):String;
public var parent(default, null):Null<IGroupView>;
@@ -63,22 +66,16 @@ class View<C:DisplayObject> implements IView<C> {
for (skin in this.skin) {
if (Std.is(skin, ISizeSkin)) {
var sizeSkin:ISizeSkin = cast skin;
setSize(sizeSkin.width, sizeSkin.height);
setContentSize(sizeSkin.width, sizeSkin.height, "skin");
}
skin.draw(this);
}
}
private function setSize(width:Float, height:Float):Void {
if (width != geometry.size.fixed.width || height != geometry.size.fixed.height) {
geometry.size.fixed = [width, height];
toUpdateParent();
}
}
private function setContentSize(width:Float, height:Float):Void {
if (width != geometry.size.content.width || height != geometry.size.content.height) {
geometry.size.content = [width, height];
private function setContentSize(width:Float, height:Float, type:String="default"):Void {
var contentSize = geometry.size.content.get(type);
if (contentSize == null || width != contentSize.width || height != contentSize.height) {
geometry.size.content.set(type, [width, height]);
toUpdateParent();
}
}
@@ -123,6 +120,11 @@ class View<C:DisplayObject> implements IView<C> {
return this.skin;
}
private function set_skinId(value:String):String {
r.skin.bind(value, this, "skin");
return value;
}
private function set_visible(value:Bool):Bool {
if (visible != value) {
visible = value;

View File

@@ -29,7 +29,7 @@ abstract ASizeValue(SizeValue) {
}
class SizeSet {
public var content(default, default):Size;
public var content(default, default):Map<String, Size>;
public var fixed(default, default):Size;
public var percent(default, default):Size;
public var stretch(null, set):Bool;
@@ -38,7 +38,7 @@ class SizeSet {
public var height(null, set):ASizeValue;
public function new() {
this.content = [];
this.content = new Map();
this.fixed = [];
this.percent = [];
}
@@ -96,7 +96,9 @@ class Geometry {
}
var result = size.fixed.width;
if (result < 0) {
result = size.content.width;
for (s in size.content.iterator()) {
result = Math.max(result, s.width);
}
}
result += padding.horizontal;
return FIXED(result);
@@ -108,7 +110,9 @@ class Geometry {
}
var result = size.fixed.height;
if (result < 0) {
result = size.content.height;
for (s in size.content.iterator()) {
result = Math.max(result, s.height);
}
}
result += padding.vertical;
return FIXED(result);

View File

@@ -5,7 +5,7 @@ import haxework.animate.IAnimate;
import haxework.gui.IView;
import haxework.gui.GroupView;
class FrameSwitcher extends GroupView implements IFrameSwitcher {
class FrameSwitcher extends GroupView {
public var current(default, null):Null<IView<Dynamic>>;
public var onSwitch:Signal<IView<Dynamic>> = new Signal();
@@ -39,6 +39,7 @@ class FrameSwitcher extends GroupView implements IFrameSwitcher {
throw 'frame "$id" not found';
}
addView(current);
update();
//ToDo:
if (content.stage != null) content.stage.focus = cast(current, SpriteView).content;
var onShowMethod:Dynamic = Reflect.field(current, "onShow");

View File

@@ -1,8 +0,0 @@
package haxework.gui.frame;
import haxework.gui.IView;
interface IFrameSwitcher extends IView<Dynamic> {
public var current(default, null):Null<IView<Dynamic>>;
public function change(id:String):IView<Dynamic>;
}

View File

@@ -29,8 +29,7 @@ class HorizontalLayout extends DefaultLayout {
maxSize = Math.max(maxSize, view.height);
}
group.geometry.size.content.height = maxSize;
group.geometry.size.content.width = fixedSize;
group.geometry.size.content.set("group", [fixedSize, maxSize]);
leftSize -= fixedSize;
for (view in views) {

View File

@@ -1,5 +1,6 @@
package haxework.gui.layout;
import haxework.gui.core.VAlign;
typedef Row = {
var width:Float;
var height:Float;
@@ -50,10 +51,18 @@ class TailLayout extends DefaultLayout {
var y:Float = Math.max(group.geometry.padding.top, (group.height - h) / 2);
y = group.geometry.padding.top;
if (h < group.height) {
y = switch vAlign {
case TOP | NONE: group.geometry.padding.top;
case MIDDLE: (group.height - h) / 2;
case BOTTOM: group.height - h - group.geometry.padding.bottom;
}
}
for (row in rows) {
placeRow(group, y, row);
y += row.height + margin;
}
group.geometry.size.content.height = h;
group.geometry.size.content.set("group", [-1, h]);
}
}

View File

@@ -25,8 +25,7 @@ class VerticalLayout extends DefaultLayout {
maxSize = Math.max(maxSize, view.width);
}
group.geometry.size.content.width = maxSize;
group.geometry.size.content.height = fixedSize;
group.geometry.size.content.set("group", [maxSize, fixedSize]);
leftSize -= fixedSize;
for (view in views) {

View File

@@ -2,24 +2,32 @@ package haxework.gui.list;
import haxework.gui.core.HAlign;
import haxework.gui.list.ListView.IListItemView;
import haxework.gui.skin.ColorSkin;
private typedef Formatter<T> = Int -> T -> String;
class LabelListItem<T> extends LabelView implements IListItemView<T> {
public var item_index(default, default):Int;
public var data(default, set):T;
public var formatter(default, default):Formatter<T>;
public function new() {
private static function defaultFormatter<T>(index:Int, value:T):String {
return Std.string(value);
}
public function new(formatter:Formatter<T> = null) {
super();
this.formatter = formatter == null ? defaultFormatter : formatter;
geometry.size.percent.width = 100;
geometry.size.fixed.height = 20;
geometry.padding = 8;
layout.hAlign = HAlign.LEFT;
layout.hAlign = LEFT;
}
private function set_data(value:T):T {
data = value;
text = Std.string(value);
skin = item_index % 2 == 1 ? [new ColorSkin(0xdddddd)] : [new ColorSkin(0xcccccc)];
text = formatter(item_index, value);
skinId = 'text${item_index % 2}';
return value;
}
}

View File

@@ -12,7 +12,7 @@ import haxework.utils.NumberUtil;
class ListView<D> extends GroupView {
public var data(default, set):Array<D>;
public var factory(null, default):Class<IListItemView<D>>;
public var factory(null, default):Void->IListItemView<D>;
public var offset(default, set):Int;
private var offsetDiff(default, set):Float;
@@ -183,7 +183,7 @@ class ListView<D> extends GroupView {
override public function update():Void {
super.update();
recalcSize(Type.createInstance(factory, []));
recalcSize(factory());
render();
}
@@ -195,7 +195,7 @@ class ListView<D> extends GroupView {
var diff:Int = size - items.length;
if (diff > 0) {
for (i in 0...diff) {
var item:IListItemView<D> = Type.createInstance(factory, []);
var item:IListItemView<D> = factory();
items.push(item);
setClickListener(item);
box.addView(item);

View File

@@ -4,44 +4,43 @@ import haxework.animate.IAnimate;
import haxework.gui.Root;
import haxework.gui.IGroupView;
typedef P = PopupView<Dynamic>;
class PopupManager {
public var showAnimateFactory(default, default):Class<IAnimate>;
public var closeAnimateFactory(default, default):Class<IAnimate>;
public var showAnimateFactory(default, default):Class<IAnimate>;
public var closeAnimateFactory(default, default):Class<IAnimate>;
private var popups:Array<PopupView<Dynamic>>;
private var popups:Array<P>;
public function new() {
popups = new Array<PopupView<Dynamic>>();
}
public function show(popup:PopupView<Dynamic>):Void {
cast(Root.instance.view, IGroupView).addView(popup);
if (showAnimateFactory != null) {
Type.createInstance(showAnimateFactory, [popup]).start(null);
public function new() {
popups = new Array<P>();
}
popups.push(popup);
popup.onShow();
}
public function close(popup:PopupView<Dynamic>):Void {
popups.remove(popup);
if (closeAnimateFactory != null) {
Type.createInstance(closeAnimateFactory, [popup]).start(function(_) {
cast(Root.instance.view, IGroupView).removeView(popup);
popup.onClose();
});
} else {
cast(Root.instance.view, IGroupView).removeView(popup);
popup.onClose();
public function show(popup:P):Void {
cast(Root.instance.view, IGroupView).addView(popup);
if (showAnimateFactory != null) {
Type.createInstance(showAnimateFactory, [popup]).start(null);
}
popups.push(popup);
}
}
public function closeTop():Bool {
if (popups.length > 0) {
close(popups[popups.length - 1]);
return true;
public function close(popup:P):Void {
popups.remove(popup);
if (closeAnimateFactory != null) {
Type.createInstance(closeAnimateFactory, [popup]).start(function(_) {
cast(Root.instance.view, IGroupView).removeView(popup);
});
} else {
cast(Root.instance.view, IGroupView).removeView(popup);
}
}
public function closeTop():Bool {
if (popups.length > 0) {
close(popups[popups.length - 1]);
return true;
}
return false;
}
return false;
}
}

View File

@@ -1,56 +1,49 @@
package haxework.gui.popup;
import promhx.Deferred;
import haxe.Timer;
import haxework.provider.Provider;
import haxework.dispath.Dispatcher;
import haxework.dispath.IDispatcher;
import haxework.gui.IGroupView;
import haxework.gui.ButtonView;
import haxework.gui.skin.ColorSkin;
import haxework.gui.core.Geometry.Position;
import haxework.gui.GroupView;
import haxework.gui.skin.Skin;
import promhx.Deferred;
import promhx.Promise;
class PopupView<V:IView> extends GroupView {
class PopupView<R> extends GroupView {
@:provide var manager:PopupManager;
private var buttonId:String;
private var contentView:V;
private var deferred:Deferred<String>;
public var view(default, set):IView<Dynamic>;
private var deferred:Deferred<R>;
public function new(contentViewFactory:Class<V>) {
super();
pWidth = 100;
pHeight = 100;
inLayout = false;
skin = new ColorSkin(0x000000, 0.6);
this.contentView = Type.createInstance(contentViewFactory, [{listener:this}]);
addView(contentView);
}
public function onPress(button:ButtonView) {
this.buttonId = button.id;
close();
}
public function show():Deferred<String> {
Provider.get(PopupManager).show(this);
deferred = new Deferred<String>();
return deferred;
}
public function close():Void {
Provider.get(PopupManager).close(this);
}
public function onShow():Void {
buttonId = "close";
}
public function onClose():Void {
if (deferred != null) {
deferred.resolve(buttonId);
deferred = null;
public function new() {
super();
geometry.size.stretch = true;
geometry.position = Position.ABSOLUTE;
skin = [Skin.color(0x000000, 0.6)];
}
private function set_view(value:IView<Dynamic>):IView<Dynamic> {
this.view = value;
this.views = [value];
return this.view;
}
public function show():Promise<R> {
manager.show(this);
deferred = new Deferred<R>();
return deferred.promise();
}
public function close(result:R):Void {
manager.close(this);
if (deferred != null) {
deferred.resolve(result);
deferred = null;
}
}
public function reject(reason:Dynamic):Void {
manager.close(this);
if (deferred != null) {
deferred.throwError(reason);
deferred = null;
}
}
}
}

View File

@@ -32,6 +32,6 @@ class BitmapSkin implements ISkin<SpriteView> implements ISizeSkin {
public function draw(view:SpriteView):Void {
if (image == null) return;
DrawUtil.draw(view.content.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color);
DrawUtil.draw(view.content.graphics, image, new Rectangle(0, 0, view.width, view.height), fillType, color, false);
}
}

View File

@@ -14,7 +14,7 @@ class BorderSkin implements ISkin<SpriteView> {
public function draw(view:SpriteView):Void {
view.content.graphics.lineStyle(tickness, color, alpha, true);
view.content.graphics.drawRect(tickness, tickness, view.width - tickness * 2, view.height - tickness * 2);
view.content.graphics.drawRect(tickness / 2, tickness / 2, view.width - tickness, view.height - tickness);
view.content.graphics.lineStyle();
}
}

View File

@@ -7,40 +7,40 @@ import flash.display.BitmapData;
class BitmapUtil {
private static var cache:Map<BitmapData, Map<String, BitmapData>> = new Map<BitmapData, Map<String, BitmapData>>();
private static var cache:Map<BitmapData, Map<String, BitmapData>> = new Map<BitmapData, Map<String, BitmapData>>();
private static function fromCache(image:BitmapData, key:String):Null<BitmapData> {
return cache.exists(image) && cache.get(image).exists(key) ? cache.get(image).get(key) : null;
}
private static function fromCache(image:BitmapData, key:String):Null<BitmapData> {
return cache.exists(image) && cache.get(image).exists(key) ? cache.get(image).get(key) : null;
}
private static function toCache(image:BitmapData, key:String, value:BitmapData):Void {
if (!cache.exists(image)) cache.set(image, new Map<String, BitmapData>());
cache.get(image).set(key, value);
}
private static function toCache(image:BitmapData, key:String, value:BitmapData):Void {
if (!cache.exists(image)) cache.set(image, new Map<String, BitmapData>());
cache.get(image).set(key, value);
}
public static function multiply(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "multiply:" + m);
if (result != null) return result;
var ct:ColorTransform = new ColorTransform(m, m, m, 1.0, 0, 0, 0);
var out:BitmapData = image.clone();
out.colorTransform(out.rect, ct);
toCache(image, "multiply:" + m, out);
return out;
}
public static function multiply(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "multiply:" + m);
if (result != null) return result;
var ct:ColorTransform = new ColorTransform(m, m, m, 1.0, 0, 0, 0);
var out:BitmapData = image.clone();
out.colorTransform(out.rect, ct);
toCache(image, "multiply:" + m, out);
return out;
}
public static function grayscale(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "grayscale:" + m);
if (result != null) return result;
var matrix:Array<Float> = [];
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([0, 0, 0, 1, 0]);
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
var out:BitmapData = image.clone();
out.applyFilter(out, out.rect, new Point(0,0), cmf);
toCache(image, "grayscale:" + m, out);
return out;
}
}
public static function grayscale(image:BitmapData, m:Float):BitmapData {
var result = fromCache(image, "grayscale:" + m);
if (result != null) return result;
var matrix:Array<Float> = [];
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([m, m, m, 0, 0]);
matrix = matrix.concat([0, 0, 0, 1, 0]);
var cmf:ColorMatrixFilter = new ColorMatrixFilter(matrix);
var out:BitmapData = image.clone();
out.applyFilter(out, out.rect, new Point(0, 0), cmf);
toCache(image, "grayscale:" + m, out);
return out;
}
}

View File

@@ -2,30 +2,30 @@ package haxework.gui.utils;
class ColorUtils {
public static function multiply(color:Int, m:Float):Int {
var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.min(255, Math.round(rgb[0] * m));
var green:Int = cast Math.min(255, Math.round(rgb[1] * m));
var blue:Int = cast Math.min(255, Math.round(rgb[2] * m));
return rgb2color(red, green, blue);
}
public static function multiply(color:Int, m:Float):Int {
var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.min(255, Math.round(rgb[0] * m));
var green:Int = cast Math.min(255, Math.round(rgb[1] * m));
var blue:Int = cast Math.min(255, Math.round(rgb[2] * m));
return rgb2color(red, green, blue);
}
public static function diff(color:Int, d:Int):Int {
var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.max(0, Math.min(255, rgb[0] + d));
var green:Int = cast Math.max(0, Math.min(255, rgb[1] + d));
var blue:Int = cast Math.max(0, Math.min(255, rgb[2] + d));
return rgb2color(red, green, blue);
}
public static function diff(color:Int, d:Int):Int {
var rgb:Array<Int> = color2rgb(color);
var red:Int = cast Math.max(0, Math.min(255, rgb[0] + d));
var green:Int = cast Math.max(0, Math.min(255, rgb[1] + d));
var blue:Int = cast Math.max(0, Math.min(255, rgb[2] + d));
return rgb2color(red, green, blue);
}
public static function rgb2color(red:Int, green:Int, blue:Int):Int {
return (red << 16) + (green << 8) + blue;
}
public static function rgb2color(red:Int, green:Int, blue:Int):Int {
return (red << 16) + (green << 8) + blue;
}
public static function color2rgb(color:Int):Array<Int> {
var red:Int = ((color & 0xFF0000) >>> 16);
var green:Int = ((color & 0x00FF00) >> 8);
var blue:Int = (color & 0x0000FF);
return [red, green, blue];
}
}
public static function color2rgb(color:Int):Array<Int> {
var red:Int = ((color & 0xFF0000) >>> 16);
var green:Int = ((color & 0x00FF00) >> 8);
var blue:Int = (color & 0x0000FF);
return [red, green, blue];
}
}

View File

@@ -1,18 +0,0 @@
package haxework.net.order;
import promhx.Promise;
import promhx.Deferred;
typedef Order<T> = {
var id:String;
var data:Null<T>;
var deferred:Deferred<T>;
var clients:Int;
}
interface IOrderSupplier {
public var orders(default, null):Map<String, Order<Dynamic>>;
public function request<T>(url:String, clazz:Class<T>):Promise<T>;
public function release(url:String, force:Bool = false):Void;
}

View File

@@ -1,82 +0,0 @@
package haxework.net.order;
import promhx.Promise;
import promhx.Deferred;
import haxework.net.order.IOrderSupplier.Order;
import flash.display.BitmapData;
class OrderSupplier implements IOrderSupplier {
private static inline var TAG:String = "OrderSupplier";
public var orders(default, null):Map<String, Order<Dynamic>>;
public function new() {
orders = new Map<String, Order<Dynamic>>();
}
public function request<T>(url:String, clazz:Class<T>):Promise<T> {
if (orders.exists(url)) {
var order:Order<T> = orders.get(url);
order.clients++;
//L.d(TAG, "Request(" + order.clients + "): " + url);
return order.deferred.promise();
} else {
var deferred = new Deferred<T>();
var order:Order<T> = {
id:url,
data:null,
deferred:deferred,
clients:1
}
//L.d(TAG, "Request(" + order.clients + "): " + url);
orders.set(url, order);
var loader:ILoader<T> = buildLoader(clazz);
loader.GET(url)
.then(function(data:T):Void {
if (orders.exists(url)) {
var order:Order<T> = orders.get(url);
order.data = data;
order.deferred.resolve(data);
}
})
.catchError(function(error:Dynamic):Void {
if (orders.exists(url)) orders.get(url).deferred.throwError(error);
orders.remove(url);
});
return deferred.promise();
}
}
public function release(url:String, force:Bool = false):Void {
if (orders.exists(url)) {
var order:Order<Dynamic> = orders.get(url);
if (--order.clients <= 0 || force) {
var data:Dynamic = order.data;
if (data != null && Std.is(data, BitmapData)) {
cast(data, BitmapData).dispose();
}
orders.remove(url);
}
L.d(TAG, "Release(" + order.clients + "): " + url);
//log();
}
}
private function buildLoader<T>(clazz:Class<T>):ILoader<T> {
var c:Class<Dynamic> = clazz;
return if (c == BitmapData) {
var loader:ILoader<T> = cast new ImageLoader();
loader.timeout = 7000; //ToDo: hardcode timeout for loading images
loader;
} else {
throw "Unsupported order: " + c;
}
}
private function log():Void {
L.d(TAG, "\n" + Lambda.map(orders, function(order:Order<Dynamic>):String {
return "(" + order.clients + ") " + order.id;
}).join("\n"));
}
}

View File

@@ -1,17 +1,17 @@
package haxework.resources;
import haxework.gui.skin.ISkin.SkinSet;
import flash.display.MovieClip;
import haxework.resources.Resources.ResMap;
import flash.display.BitmapData;
import flash.display.MovieClip;
import haxework.gui.skin.ISkin.SkinSet;
import haxework.resources.Resources.ResMap;
interface IResources {
public var image(default, null):ResMap<BitmapData>;
public var color(default, null):ResMap<Int>;
public var movie(default, null):ResMap<MovieClip>;
public var text(default, null):ResMap<String>;
public var float(default, null):ResMap<Float>;
public var int(default, null):ResMap<Int>;
public var any(default, null):ResMap<Dynamic>;
public var skin(default, null):ResMap<SkinSet>;
public var image(default, null):ResMap<BitmapData>;
public var color(default, null):ResMap<Int>;
public var movie(default, null):ResMap<MovieClip>;
public var text(default, null):ResMap<String>;
public var float(default, null):ResMap<Float>;
public var int(default, null):ResMap<Int>;
public var any(default, null):ResMap<Dynamic>;
public var skin(default, null):ResMap<SkinSet>;
}

View File

@@ -1,20 +1,19 @@
package haxework.resources;
import haxework.gui.skin.ISkin.SkinSet;
import flash.display.BitmapData;
import flash.display.MovieClip;
import haxe.ds.StringMap;
import haxework.core.Tuple;
import haxework.gui.skin.ISkin;
private typedef F = Tuple2<Dynamic, String>
private typedef Listener = {object:Dynamic, field:String};
class ResMap<T> extends StringMap<T> {
private var listeners:Map<String, Array<F>>;
private var listeners:StringMap<Array<Listener>>;
public function new() {
super();
listeners = new Map<String, Array<F>>();
listeners = new StringMap();
}
public function put(key:String, value:T):Void {
@@ -25,17 +24,18 @@ class ResMap<T> extends StringMap<T> {
}
public function bind(key:String, object:Dynamic, field:String):Void {
var f:F = Tuple.two(object, field);
var listener:Listener = {object:object, field:field};
if (listeners.exists(key)) {
listeners.get(key).push(f);
listeners.set(key, listeners.get(key).filter(function(l) return l.object != object || l.field != field));
listeners.get(key).push(listener);
} else {
listeners.set(key, [f]);
listeners.set(key, [listener]);
}
if (exists(key)) call(f, get(key));
if (exists(key)) call(listener, get(key));
}
private function call(field:F, value:T):Void {
Reflect.setProperty(field.first, field.second, value);
private function call(listener:Listener, value:T):Void {
Reflect.setProperty(listener.object, listener.field, value);
}
public function merge(value:Dynamic<T>):Void {