[view] fixes

This commit is contained in:
2019-07-12 17:08:58 +03:00
parent 2dbfe79371
commit b9908f2d5b
30 changed files with 373 additions and 135 deletions

View File

@@ -1,6 +1,8 @@
package demo; package demo;
import haxework.color.Color; import haxework.color.Color;
import haxework.view.skin.Skin;
import haxework.view.theme.SkinStyle;
import haxework.view.theme.Theme; import haxework.view.theme.Theme;
using haxework.color.ColorUtil; using haxework.color.ColorUtil;
@@ -13,7 +15,7 @@ class AppTheme extends Theme {
override private function reload():Void { override private function reload():Void {
super.reload(); super.reload();
// data.put("view", text().concat(background(colors.light)).concat(border())); styles.put("view", text().concat(background(colors.light, true)));
// data.put("test", [Skin.color(0x00ffff)]); styles.put("test", [new SkinStyle(Skin.color(0x00ffff))]);
} }
} }

View File

@@ -17,7 +17,7 @@ import haxework.view.IView;
@:view var tabs:IGroupView; @:view var tabs:IGroupView;
private function init():Void { private function init():Void {
switcher.change("list"); switcher.change("test_layout");
} }
private function onFrameSwitch(frame:IView<Dynamic>):Void { private function onFrameSwitch(frame:IView<Dynamic>):Void {

View File

@@ -1,6 +1,5 @@
--- ---
style: background style: background
geometry.stretch: true
views: views:
- $type: haxework.view.ImageView - $type: haxework.view.ImageView
geometry.padding: 10 geometry.padding: 10

View File

@@ -9,6 +9,7 @@ import haxework.view.skin.Skin;
private function colorViewFactory(index:Int, color:Int) { private function colorViewFactory(index:Int, color:Int) {
var view = new ButtonView(); var view = new ButtonView();
view.setSize(48, 48, "fixed"); view.setSize(48, 48, "fixed");
view.geometry.padding = 0;
view.skin = Skin.buttonColor(color); view.skin = Skin.buttonColor(color);
return view; return view;
} }

View File

@@ -7,21 +7,24 @@ views:
layout.margin: 10 layout.margin: 10
layout.vAlign: middle layout.vAlign: middle
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xffff00 background.color: 0xffff00
background.alpha: 1
views: views:
- $type: haxework.view.SpriteView - $type: haxework.view.SpriteView
geometry.width: 100 geometry.width: 100
geometry.height: 100 geometry.height: 100
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xff0000 background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.group.VGroupView - $type: haxework.view.group.VGroupView
geometry.padding: 10 geometry.padding: 10
layout.margin: 10 layout.margin: 10
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0x00ffff background.color: 0x00ffff
background.alpha: 1
views: views:
- $type: haxework.view.SpriteView - $type: haxework.view.SpriteView
geometry.width: 100 geometry.width: 100
@@ -29,31 +32,30 @@ views:
size: size:
_test_: [200, 200] _test_: [200, 200]
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xff0000 background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.SpriteView - $type: haxework.view.SpriteView
geometry.width: 100 geometry.width: 100
geometry.height: 100 geometry.height: 100
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xff0000 background.color: 0xff0000
- $type: haxework.view.list.VListView background.alpha: 1
factory: ~haxework.view.list.LabelListItem.factory - $type: haxework.view.text.TextView
geometry.width: 100 geometry.padding: 20
geometry.height: 100 text: "Azazaza"
scroll:
$type: haxework.view.list.VScrollBarView
data:
- "aaa"
- $type: haxework.view.SpriteView - $type: haxework.view.SpriteView
geometry.width: 60% geometry.width: 60%
geometry.height: 100% geometry.height: 100%
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xff0000 background.color: 0xff0000
background.alpha: 1
- $type: haxework.view.SpriteView - $type: haxework.view.SpriteView
geometry.width: 40% geometry.width: 40%
geometry.height: 80% geometry.height: 80%
skin: skin:
$type: haxework.view.skin.ColorSkin $type: haxework.view.skin.SpriteSkin
color: 0xff0000 background.color: 0xff0000
background.alpha: 1

View File

@@ -3,13 +3,14 @@ package haxework.view;
import flash.display.DisplayObject; import flash.display.DisplayObject;
import flash.geom.Rectangle; import flash.geom.Rectangle;
import haxework.view.geometry.Geometry; import haxework.view.geometry.Geometry;
import haxework.view.geometry.Size;
import haxework.view.group.IGroupView; import haxework.view.group.IGroupView;
import haxework.view.skin.ISkin; import haxework.view.skin.ISkin;
import haxework.view.theme.StyleId; import haxework.view.theme.StyleId;
interface IView<C:DisplayObject> { interface IView<C:DisplayObject> {
@:style public var geometry(default, default):Geometry; @:style public var geometry(default, default):Geometry;
@:style public var skin(default, default):ISkin<Dynamic>; @:style public var skin(default, set):ISkin<Dynamic>;
public var id(default, default):String; public var id(default, default):String;
@@ -19,7 +20,9 @@ interface IView<C:DisplayObject> {
public var width(default, null):Float; public var width(default, null):Float;
public var height(default, null):Float; public var height(default, null):Float;
public var style(default, default):StyleId; public var size(default, null):Size;
public var style(default, set):StyleId;
public var content(default, null):C; public var content(default, null):C;

View File

@@ -20,6 +20,7 @@ class ImageView extends SpriteView {
public function new(image:BitmapData = null) { public function new(image:BitmapData = null) {
super(); super();
fillType = FillType.DEFAULT; fillType = FillType.DEFAULT;
skin = bitmapSkin;
if (image != null) { if (image != null) {
this.image = image; this.image = image;
} }

View File

@@ -1,17 +1,17 @@
package haxework.view; package haxework.view;
import haxework.view.skin.ColorSkin;
import flash.display.Sprite; import flash.display.Sprite;
import haxework.view.skin.Skin;
class SpriteView extends View<Sprite> { class SpriteView extends View<Sprite> {
public function new() { public function new() {
super(new Sprite()); super(new Sprite());
skin = new ColorSkin(0, 0); skin = Skin.transparent;
} }
override public function redraw():Void { override public function redraw():Void {
this.content.graphics.clear(); this.content.graphics.clear(); // ToDo: in skin
super.redraw(); super.redraw();
#if dev_layout #if dev_layout
var graphics = content.graphics; var graphics = content.graphics;

View File

@@ -4,6 +4,7 @@ import flash.display.DisplayObject;
import flash.display.InteractiveObject; import flash.display.InteractiveObject;
import flash.geom.Rectangle; import flash.geom.Rectangle;
import haxework.view.geometry.Geometry; import haxework.view.geometry.Geometry;
import haxework.view.geometry.Size;
import haxework.view.geometry.SizeSet; import haxework.view.geometry.SizeSet;
import haxework.view.group.IGroupView; import haxework.view.group.IGroupView;
import haxework.view.skin.ISkin; import haxework.view.skin.ISkin;
@@ -18,8 +19,8 @@ class View<C:DisplayObject> implements IView<C> {
@:provide var theme:ITheme; @:provide var theme:ITheme;
public var geometry(default, default):Geometry; public var geometry(default, default):Geometry;
public var skin(default, default):ISkin<Dynamic>; public var skin(default, set):ISkin<Dynamic>;
public var style(default, default):StyleId; public var style(default, set):StyleId;
public var id(default, default):String; public var id(default, default):String;
@@ -29,6 +30,8 @@ class View<C:DisplayObject> implements IView<C> {
public var width(default, null):Float; public var width(default, null):Float;
public var height(default, null):Float; public var height(default, null):Float;
public var size(default, null):Size;
public var content(default, null):C; public var content(default, null):C;
public var parent(default, null):Null<IGroupView>; public var parent(default, null):Null<IGroupView>;
@@ -39,11 +42,12 @@ class View<C:DisplayObject> implements IView<C> {
public var rect(get, null):Rectangle; public var rect(get, null):Rectangle;
private var size:SizeSet; private var sizeSet:SizeSet;
public function new(content:C) { public function new(content:C) {
id = Type.getClassName(Type.getClass(this)) + counter++; id = Type.getClassName(Type.getClass(this)) + counter++;
size = new SizeSet(); sizeSet = new SizeSet();
size = 0;
this.content = content; this.content = content;
x = 0; x = 0;
y = 0; y = 0;
@@ -80,10 +84,13 @@ class View<C:DisplayObject> implements IView<C> {
} }
public function setSize(width:Float, height:Float, type:String = "default"):Void { public function setSize(width:Float, height:Float, type:String = "default"):Void {
if (size.update([width, height], type)) { if (sizeSet.update([width, height], type)) {
var s = size.toSize(); var s = sizeSet.toSize();
this.width = s.width; this.width = s.width + geometry.padding.horizontal;
this.height = s.height; this.height = s.height + geometry.padding.vertical;
size = sizeSet.toSize(false);
size.width += geometry.padding.horizontal;
size.height += geometry.padding.vertical;
toUpdateParent(); toUpdateParent();
toRedraw(); toRedraw();
} }
@@ -113,6 +120,16 @@ class View<C:DisplayObject> implements IView<C> {
return this.skin; return this.skin;
} }
private function set_style(value:StyleId):StyleId {
if (value != null && style != value) {
style = value;
if (theme != null) {
theme.bind(style, this);
}
}
return style;
}
private function set_visible(value:Bool):Bool { private function set_visible(value:Bool):Bool {
if (visible != value) { if (visible != value) {
visible = value; visible = value;

View File

@@ -65,6 +65,10 @@ abstract Box(Array<Float>) {
} }
} }
public function clone():Box {
return new Box(this);
}
@:from static public inline function fromArray(value:Array<Float>):Box { @:from static public inline function fromArray(value:Array<Float>):Box {
return new Box(value); return new Box(value);
} }

View File

@@ -17,11 +17,14 @@ class SizeSet extends StringMap<Size> {
return false; return false;
} }
public function toSize():Size { public function toSize(percent:Bool = true):Size {
var result:Size = 0; var result:Size = 0;
for (value in iterator()) { for (type in keys()) {
result.width = Math.max(result.width, value.width); if (percent || type.indexOf("percent") == -1) {
result.height = Math.max(result.height, value.height); var value = get(type);
result.width = Math.max(result.width, value.width);
result.height = Math.max(result.height, value.height);
}
} }
return result; return result;
} }

View File

@@ -15,8 +15,8 @@ class DefaultLayout extends Layout {
setViewHeight(group, view); setViewHeight(group, view);
placeViewHorizontal(group, view); placeViewHorizontal(group, view);
placeViewVertical(group, view); placeViewVertical(group, view);
width = Math.max(width, view.width + view.geometry.margin.horizontal); width = Math.max(width, view.size.width + view.geometry.margin.horizontal);
height = Math.max(height, view.height + view.geometry.margin.horizontal); height = Math.max(height, view.size.height + view.geometry.margin.horizontal);
} }
if (!overflow) group.setSize(width, height, "group"); if (!overflow) group.setSize(width, height, "group");
} }
@@ -38,11 +38,11 @@ class DefaultLayout extends Layout {
} }
private function setViewWidth(group:IGroupView, view:IView<Dynamic>):Void { private function setViewWidth(group:IGroupView, view:IView<Dynamic>):Void {
view.setSize(view.geometry.width.percent / 100 * (group.width - view.geometry.margin.horizontal - group.geometry.padding.horizontal), 0, "percent.width"); view.setSize(view.geometry.width.percent / 100 * (group.width - view.geometry.margin.horizontal - group.geometry.padding.horizontal) - view.geometry.padding.horizontal, 0, "percent.width");
} }
private function setViewHeight(group:IGroupView, view:IView<Dynamic>):Void { private function setViewHeight(group:IGroupView, view:IView<Dynamic>):Void {
view.setSize(0, view.geometry.height.percent / 100 * (group.height - view.geometry.margin.vertical - group.geometry.padding.vertical), "percent.height"); view.setSize(0, view.geometry.height.percent / 100 * (group.height - view.geometry.margin.vertical - group.geometry.padding.vertical) - view.geometry.padding.vertical, "percent.height");
} }
private function placeViewHorizontal(group:IGroupView, view:IView<Dynamic>):Void { private function placeViewHorizontal(group:IGroupView, view:IView<Dynamic>):Void {

View File

@@ -10,21 +10,19 @@ class HorizontalLayout extends DefaultLayout {
override public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void { override public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void {
views = filterViews(group, views); views = filterViews(group, views);
var fixedSize:Float = group.geometry.padding.horizontal + margin * (views.length - 1); var fixedSize:Float = margin * (views.length - 1);
var leftSize:Float = group.width; var leftSize:Float = group.width - group.geometry.padding.horizontal;
var maxSize:Float = group.geometry.padding.vertical; var maxSize:Float = 0;
for (view in views) { for (view in views) {
setViewHeight(group, view);
placeViewVertical(group, view);
switch view.geometry.width.type { switch view.geometry.width.type {
case PERCENT: case PERCENT:
leftSize -= (view.geometry.margin.horizontal); leftSize -= (view.geometry.margin.horizontal);
case FIXED: case FIXED:
fixedSize += (view.width + view.geometry.margin.horizontal); fixedSize += (view.width + view.geometry.margin.horizontal);
} }
maxSize = Math.max(maxSize, view.height + view.geometry.margin.vertical + group.geometry.padding.vertical); maxSize = Math.max(maxSize, view.size.height + view.geometry.margin.vertical);
} }
if (!overflow) group.setSize(fixedSize, maxSize, "group"); if (!overflow) group.setSize(fixedSize, maxSize, "group");
@@ -35,7 +33,7 @@ class HorizontalLayout extends DefaultLayout {
case PERCENT: case PERCENT:
var result = view.geometry.width.value / 100 * leftSize; var result = view.geometry.width.value / 100 * leftSize;
fixedSize += result + view.geometry.margin.horizontal; fixedSize += result + view.geometry.margin.horizontal;
view.setSize(result, 0, "percent.width"); view.setSize(result - view.geometry.padding.horizontal, 0, "percent.width");
case _: case _:
}; };
} }
@@ -50,6 +48,8 @@ class HorizontalLayout extends DefaultLayout {
for (view in views) { for (view in views) {
view.x = x + view.geometry.margin.left; view.x = x + view.geometry.margin.left;
x += (view.width + view.geometry.margin.horizontal + margin); x += (view.width + view.geometry.margin.horizontal + margin);
setViewHeight(group, view);
placeViewVertical(group, view);
} }
} }
} }

View File

@@ -10,21 +10,19 @@ class VerticalLayout extends DefaultLayout {
override public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void { override public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void {
views = filterViews(group, views); views = filterViews(group, views);
var fixedSize:Float = group.geometry.padding.vertical + margin * (views.length - 1); var fixedSize:Float = margin * (views.length - 1);
var leftSize:Float = group.height; var leftSize:Float = group.height - group.geometry.padding.vertical;
var maxSize:Float = group.geometry.padding.horizontal; var maxSize:Float = 0;
for (view in views) { for (view in views) {
setViewWidth(group, view);
placeViewHorizontal(group, view);
switch view.geometry.height.type { switch view.geometry.height.type {
case PERCENT: case PERCENT:
leftSize -= (view.geometry.margin.vertical); leftSize -= (view.geometry.margin.vertical);
case FIXED: case FIXED:
fixedSize += (Math.max(view.geometry.height.value, view.height) + view.geometry.margin.vertical); fixedSize += (Math.max(view.geometry.height.value, view.height) + view.geometry.margin.vertical);
} }
maxSize = Math.max(maxSize, view.width + view.geometry.margin.horizontal + group.geometry.padding.horizontal); maxSize = Math.max(maxSize, view.size.width + view.geometry.margin.horizontal);
} }
if (!overflow) group.setSize(maxSize, fixedSize, "group"); if (!overflow) group.setSize(maxSize, fixedSize, "group");
@@ -35,7 +33,7 @@ class VerticalLayout extends DefaultLayout {
case PERCENT: case PERCENT:
var result = view.geometry.height.value / 100 * leftSize; var result = view.geometry.height.value / 100 * leftSize;
fixedSize += result + view.geometry.margin.vertical; fixedSize += result + view.geometry.margin.vertical;
view.setSize(0, result, "percent.height"); view.setSize(0, result - view.geometry.padding.vertical, "percent.height");
case _: case _:
}; };
} }
@@ -50,6 +48,8 @@ class VerticalLayout extends DefaultLayout {
for (view in views) { for (view in views) {
view.y = y + view.geometry.margin.top; view.y = y + view.geometry.margin.top;
y += (view.height + view.geometry.margin.vertical + margin); y += (view.height + view.geometry.margin.vertical + margin);
setViewWidth(group, view);
placeViewHorizontal(group, view);
} }
} }
} }

View File

@@ -1,20 +0,0 @@
package haxework.view.skin;
class BorderSkin implements ISkin<SpriteView> {
public var color(default, default):Int;
public var alpha(default, default):Float;
public var tickness(default, default):Float;
public function new(color:Int = 0xffffff, alpha:Float = 1.0, tickness: Float = 1.0) {
this.color = color;
this.alpha = alpha;
this.tickness = tickness;
}
public function draw(view:SpriteView):Void {
view.content.graphics.lineStyle(tickness, color, alpha, true);
view.content.graphics.drawRect(tickness / 2, tickness / 2, view.width - tickness, view.height - tickness);
view.content.graphics.lineStyle();
}
}

View File

@@ -1,18 +0,0 @@
package haxework.view.skin;
class ColorSkin implements ISkin<SpriteView> {
public var color(default, default):Int;
public var alpha(default, default):Float;
public function new(color:Int = 0xffffff, alpha:Float = 1.0) {
this.color = color;
this.alpha = alpha;
}
public function draw(view:SpriteView):Void {
view.content.graphics.beginFill(color, alpha);
view.content.graphics.drawRect(0, 0, view.width, view.height);
view.content.graphics.endFill();
}
}

View File

@@ -6,18 +6,14 @@ import haxework.view.utils.DrawUtil;
class Skin { class Skin {
public static var transparent(default, never):ISkin<SpriteView> = new ColorSkin(0, 0); public static var transparent(default, never):ISkin<SpriteView> = new SpriteSkin({color: 0, alpha: 0});
public static function bitmap(image:BitmapData, fillType:FillType = null):ISkin<SpriteView> { public static function bitmap(image:BitmapData, fillType:FillType = null):ISkin<SpriteView> {
return new BitmapSkin(image, fillType); return new BitmapSkin(image, fillType);
} }
public static function color(color:Int, alpha:Float = 1.0):ISkin<SpriteView> { public static function color(color:Int, alpha:Float = 1.0):ISkin<SpriteView> {
return new ColorSkin(color, alpha); return new SpriteSkin({color: color, alpha: alpha});
}
public static function border(color:Int, alpha:Float = 1.0, tickness:Float = 1.0):ISkin<SpriteView> {
return new BorderSkin(color, alpha, tickness);
} }
public static function buttonColor(color:Int, borderColor:Int = -1):ISkin<ButtonView> { public static function buttonColor(color:Int, borderColor:Int = -1):ISkin<ButtonView> {

View File

@@ -0,0 +1,55 @@
package haxework.view.skin;
import flash.display.Graphics;
import haxework.color.Color;
typedef Border = {
@:optional var color:Color;
@:optional var thickness:Float;
@:optional var alpha:Float;
}
typedef Background = {
@:optional var color:Color;
@:optional var alpha:Float;
}
class SpriteSkin implements ISkin<SpriteView> {
public var border(default, default):Border;
public var background(default, default):Background;
public function new(?background:Background, ?border:Border) {
this.background = resolveBackground(background);
this.border = resolveBorder(border);
}
private static function resolveBackground(value:Background):Background {
return value != null ? {
color: value.color != null ? value.color : 0x000000,
alpha: value.alpha != null ? value.alpha : 1.0
} : {};
}
private static function resolveBorder(value:Border):Border {
return value != null ? {
color: value.color != null ? value.color : 0x000000,
alpha: value.alpha != null ? value.alpha : 1.0,
thickness: value.thickness != null ? value.thickness : 1
} : {};
}
public function draw(view:SpriteView):Void {
var graphics:Graphics = view.content.graphics;
graphics.clear();
if (border.color != null) {
graphics.lineStyle(border.thickness, border.color, border.alpha, true);
}
if (background.color != null) {
graphics.beginFill(background.color, background.alpha);
}
graphics.drawRect(0, 0, view.width, view.height);
graphics.lineStyle();
graphics.endFill();
}
}

View File

@@ -0,0 +1,23 @@
package haxework.view.text;
import haxework.color.Color;
import flash.text.TextFormatAlign;
class FontPreset {
public var family(default, default):String;
public var embed(default, default):Bool;
public var color(default, default):Color;
public var size(default, default):Int;
public var bold(default, default):Bool;
public var align(default, default):TextFormatAlign;
public function new(family:String = null, embed:Bool = false, color:Color = null, size:Int = 16,
bold:Bool = false, align:TextFormatAlign = null) {
this.family = family;
this.embed = embed;
this.color = color != null ? color : 0xffffff;
this.size = size;
this.bold = bold;
this.align = align;
}
}

View File

@@ -1,21 +0,0 @@
package haxework.view.text;
import flash.text.TextFormatAlign;
class FontStyle {
public var family(default, default):String;
public var embed(default, default):Bool;
public var color(default, default):Int;
public var size(default, default):Int;
public var bold(default, default):Bool;
public var align(default, default):TextFormatAlign;
public function new() {
family = null;
embed = false;
color = 0xffffff;
size = 16;
bold = false;
align = null;
}
}

View File

@@ -5,7 +5,7 @@ import haxework.view.IView;
import haxework.view.layout.ILayout; import haxework.view.layout.ILayout;
interface ITextView extends IView<Dynamic> { interface ITextView extends IView<Dynamic> {
@:style public var font(default, default):FontStyle; @:style public var font(default, default):FontPreset;
@:style public var layout(default, default):ILayout; @:style public var layout(default, default):ILayout;
public var textField(default, null):TextField; public var textField(default, null):TextField;

View File

@@ -12,7 +12,7 @@ import haxework.view.layout.ILayout;
import haxework.view.layout.Layout; import haxework.view.layout.Layout;
class TextView extends SpriteView implements ITextView { class TextView extends SpriteView implements ITextView {
public var font(default, default):FontStyle; public var font(default, default):FontPreset;
public var layout(default, default):ILayout; public var layout(default, default):ILayout;
public var textField(default, null):TextField; public var textField(default, null):TextField;
@@ -27,7 +27,7 @@ class TextView extends SpriteView implements ITextView {
public function new() { public function new() {
super(); super();
font = new FontStyle(); font = new FontPreset();
style = "text"; style = "text";
layout = new Layout(); layout = new Layout();
textField = buildTextField(); textField = buildTextField();

View File

@@ -0,0 +1,18 @@
package haxework.view.theme;
import haxework.view.text.ITextView;
import haxework.view.text.FontPreset;
class FontStyle implements IStyle<ITextView> {
private var font:FontPreset;
public function new(font:FontPreset) {
this.font = font;
}
public function apply(view:ITextView):Void {
view.font = font;
view.toUpdate();
}
}

View File

@@ -0,0 +1,23 @@
package haxework.view.theme;
import haxework.view.geometry.Geometry;
class GeometryStyle implements IStyle<IView<Dynamic>> {
private var geometry:Geometry;
public function new(geometry:Geometry) {
this.geometry = geometry;
}
public function apply(view:IView<Dynamic>):Void {
var update = false;
if (!geometry.padding.empty) {
view.geometry.padding = geometry.padding.clone();
update = true;
}
if (update) {
view.toUpdateParent();
}
}
}

View File

@@ -0,0 +1,5 @@
package haxework.view.theme;
interface IStyle<V:IView<Dynamic>> {
public function apply(view:V):Void;
}

View File

@@ -18,6 +18,5 @@ typedef ThemeColors = {
interface ITheme { interface ITheme {
public var font(default, set):ThemeFont; public var font(default, set):ThemeFont;
public var colors(default, set):ThemeColors; public var colors(default, set):ThemeColors;
public function bind(style:StyleId, view:IView<Dynamic>):Void;
public function bind(styles:Array<String>, view:IView<Dynamic>):Void;
} }

View File

@@ -0,0 +1,18 @@
package haxework.view.theme;
import haxework.view.group.IGroupView;
import haxework.view.layout.ILayout;
class LayoutStyle implements IStyle<IGroupView> {
private var layout:ILayout;
public function new(layout:ILayout) {
this.layout = layout;
}
public function apply(view:IGroupView):Void {
view.layout = layout;
view.toUpdate();
}
}

View File

@@ -0,0 +1,17 @@
package haxework.view.theme;
import haxework.view.skin.ISkin;
class SkinStyle implements IStyle<IView<Dynamic>> {
private var skin:ISkin<Dynamic>;
public function new(skin:ISkin<Dynamic>) {
this.skin = skin;
}
public function apply(view:IView<Dynamic>):Void {
view.skin = skin;
view.toRedraw();
}
}

View File

@@ -3,7 +3,7 @@ package haxework.view.theme;
abstract StyleId(Array<String>) { abstract StyleId(Array<String>) {
public function new(value:Array<String>) { public function new(value:Array<String>) {
this = value; this = value != null ? value : [];
} }
@:to public inline function toArray():Array<String> { @:to public inline function toArray():Array<String> {

View File

@@ -2,11 +2,57 @@ package haxework.view.theme;
import flash.text.Font; import flash.text.Font;
import flash.text.FontType; import flash.text.FontType;
import haxe.ds.StringMap;
import haxework.color.Color; import haxework.color.Color;
import haxework.view.geometry.Geometry;
import haxework.view.skin.Skin;
import haxework.view.skin.SpriteSkin;
import haxework.view.text.FontPreset;
import haxework.view.theme.ITheme; import haxework.view.theme.ITheme;
using haxework.color.ColorUtil; using haxework.color.ColorUtil;
typedef StyleSet = Array<IStyle<Dynamic>>;
class StyleMap extends StringMap<StyleSet> {
private var views:Map<IView<Dynamic>, String> = new Map();
private var viewsByStyle:Map<String, Array<IView<Dynamic>>> = new Map();
private function apply(styles:StyleSet, view:IView<Dynamic>):Void {
for (item in styles) {
item.apply(view);
}
}
public function put(key:String, value:StyleSet):Void {
set(key, value);
if (viewsByStyle.exists(key)) {
for (view in viewsByStyle.get(key)) {
apply(value, view);
}
}
}
public function connect(key:String, view:IView<Dynamic>):Void {
disconnect(view);
if (!viewsByStyle.exists(key)) {
viewsByStyle.set(key, []);
}
viewsByStyle.get(key).push(view);
if (exists(key)) {
apply(get(key), view);
}
}
public function disconnect(view:IView<Dynamic>):Void {
if (views.exists(view)) {
viewsByStyle.get(views.get(view)).remove(view);
views.remove(view);
}
}
}
class Theme implements ITheme { class Theme implements ITheme {
// ToDo: configurable // ToDo: configurable
public var baseFontSize = 18; public var baseFontSize = 18;
@@ -16,7 +62,10 @@ class Theme implements ITheme {
public var font(default, set):ThemeFont; public var font(default, set):ThemeFont;
public var colors(default, set):ThemeColors; public var colors(default, set):ThemeColors;
private var styles:StyleMap;
public function new(?font:ThemeFont, ?colors:ThemeColors) { public function new(?font:ThemeFont, ?colors:ThemeColors) {
styles = new StyleMap();
this.font = font; this.font = font;
this.colors = colors; this.colors = colors;
L.d("Theme", 'font: ${this.font}'); L.d("Theme", 'font: ${this.font}');
@@ -39,12 +88,74 @@ class Theme implements ITheme {
return colors; return colors;
} }
private function reload():Void {
private function reload():Void {
styles.put("background", background());
styles.put("border", background(null, true));
styles.put("frame", background(null, true).concat([new GeometryStyle(new Geometry().setPadding(2))]));
styles.put("text", text());
styles.put("label", text().concat([new GeometryStyle(new Geometry().setPadding([8, 2]))]));
styles.put("button", button());
styles.put("dropdown", background(null, true));
styles.put("tab", text().concat([
new SkinStyle(Skin.tabColor(this.colors.light)),
new GeometryStyle(new Geometry().setPadding([25, 8]))
]));
styles.put("text0", text().concat(background(this.colors.light.diff(-16))));
styles.put("text1", text().concat(background(this.colors.light.diff(16))));
styles.put("scroll.vertical", [
new SkinStyle(Skin.scrollVertical(this.colors.light, this.colors.dark)),
]);
styles.put("scroll.horizontal", [
new SkinStyle(Skin.scrollHorizontal(this.colors.light, this.colors.dark)),
]);
} }
public function bind(styles:Array<String>, view:IView<Dynamic>):Void { public function background(?color:Color, border:Bool = false):StyleSet {
//data.bind(id, view, "skin"); if (color == null) {
color = colors.dark;
}
return [
new SkinStyle(new SpriteSkin(
{color: color},
border ? {color: colors.light, thickness: 2} : null
)),
];
}
public function text(?color:Color):StyleSet {
if (color == null) {
color = colors.text;
}
return [
new FontStyle(new FontPreset(font.name, font.embed, color, baseFontSize)),
];
}
public function button(?color:Color, ?textColor:Color):StyleSet {
if (color == null) {
color = colors.light;
}
return text(textColor).concat([
new SkinStyle(Skin.buttonColor(color)),
new GeometryStyle(new Geometry().setPadding([25, 8])),
]);
}
public function textBox(?color:Color):StyleSet {
return text(color).concat([
new SkinStyle(new SpriteSkin({color: 0, alpha: 0.1}, {color: colors.light, thickness: 2})),
]);
}
public function bind(style:StyleId, view:IView<Dynamic>):Void {
styles.connect(style, view);
}
public function unbind(view:IView<Dynamic>):Void {
styles.disconnect(view);
} }
private static function resolveFont(font:ThemeFont):ThemeFont { private static function resolveFont(font:ThemeFont):ThemeFont {