[view] remove ScrollView, add scrolls to GroupView
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
---
|
||||
overflow.y: scroll
|
||||
views:
|
||||
- $type: haxework.view.ScrollView
|
||||
geometry.stretch: true
|
||||
view:
|
||||
id: data
|
||||
$type: haxework.view.data.DataView
|
||||
layout:
|
||||
$type: haxework.view.layout.VerticalLayout
|
||||
factory: ~factory
|
||||
geometry.width: 100%
|
||||
data: $r:any:data
|
||||
- id: data
|
||||
$type: haxework.view.data.DataView
|
||||
layout:
|
||||
$type: haxework.view.layout.VerticalLayout
|
||||
factory: ~factory
|
||||
geometry.width: 100%
|
||||
data: $r:any:data
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
---
|
||||
overflow.y: scroll
|
||||
views:
|
||||
- $type: haxework.view.ScrollView
|
||||
geometry.stretch: true
|
||||
view:
|
||||
id: data
|
||||
$type: haxework.view.data.DataView
|
||||
geometry.padding: 4
|
||||
layout:
|
||||
$type: haxework.view.layout.TailLayout
|
||||
margin: 6
|
||||
factory: ~factory
|
||||
geometry.width: 100%
|
||||
data: $r:any:data
|
||||
- id: data
|
||||
$type: haxework.view.data.DataView
|
||||
geometry.padding: 4
|
||||
layout:
|
||||
$type: haxework.view.layout.TailLayout
|
||||
margin: 6
|
||||
factory: ~factory
|
||||
geometry.width: 100%
|
||||
data: $r:any:data
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package haxework.view;
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.geometry.Position;
|
||||
import haxework.view.group.HGroupView;
|
||||
import haxework.view.list.ScrollBarView;
|
||||
import haxework.view.list.VScrollBarView;
|
||||
import haxework.view.skin.Skin;
|
||||
|
||||
class ScrollView extends HGroupView {
|
||||
|
||||
public var view(default, set):IView<Dynamic>;
|
||||
public var scroll(default, set):ScrollBarView;
|
||||
|
||||
public var ratio(default, null):Signal<Float> = new Signal();
|
||||
public var position(default, set):Float = 0;
|
||||
|
||||
private var mask:Sprite;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
layout.overflow = true;
|
||||
skin = Skin.transparent();
|
||||
mask = new Sprite();
|
||||
content.addChild(mask);
|
||||
content.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheelEvent);
|
||||
scroll = new VScrollBarView();
|
||||
}
|
||||
|
||||
private function onMouseWheelEvent(event:MouseEvent):Void {
|
||||
#if flash event.preventDefault(); #end
|
||||
position -= event.delta * scroll.ratio / 3;
|
||||
}
|
||||
|
||||
private function set_view(value:IView<Dynamic>):IView<Dynamic> {
|
||||
view = value;
|
||||
views = [view, scroll];
|
||||
cast(view.content, DisplayObject).mask = mask;
|
||||
return view;
|
||||
}
|
||||
|
||||
private function set_scroll(value:ScrollBarView):ScrollBarView {
|
||||
scroll = value;
|
||||
views = [view, scroll];
|
||||
ratio.connect(function(ratio) {
|
||||
if (scroll.ratio == ratio) return;
|
||||
scroll.ratio = ratio;
|
||||
scroll.visible = ratio < 1;
|
||||
scroll.geometry.position = ratio < 1 ? LAYOUT : ABSOLUTE;
|
||||
});
|
||||
scroll.onScroll.connect(function(position) this.position = position);
|
||||
return scroll;
|
||||
}
|
||||
|
||||
override public function set_views(value:Array<IView<Dynamic>>):Array<IView<Dynamic>> {
|
||||
return super.set_views(value.filter(function(view) return view != null));
|
||||
}
|
||||
|
||||
private function set_position(value:Float):Float {
|
||||
position = Math.min(Math.max(0, value), 1 - (height / view.height));
|
||||
if (height / view.height > 1) position = 0;
|
||||
if (scroll != null) {
|
||||
scroll.position = position;
|
||||
}
|
||||
toUpdate();
|
||||
return position;
|
||||
}
|
||||
|
||||
override public function update():Void {
|
||||
super.update();
|
||||
ratio.emit(height / view.height);
|
||||
view.y = - position * view.height;
|
||||
// mask redraw
|
||||
mask.graphics.clear();
|
||||
mask.graphics.beginFill(0xffffff);
|
||||
mask.graphics.drawRect(0, 0, width, height);
|
||||
mask.graphics.endFill();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,137 @@
|
||||
package haxework.view.group;
|
||||
|
||||
import flash.display.DisplayObjectContainer;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.MouseEvent;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.geometry.Position;
|
||||
import haxework.view.layout.DefaultLayout;
|
||||
import haxework.view.layout.ILayout;
|
||||
import haxework.view.list.HScrollBarView;
|
||||
import haxework.view.list.ScrollBarView;
|
||||
import haxework.view.list.VScrollBarView;
|
||||
|
||||
class OverflowControl {
|
||||
public var overflow(default, set):Float = 0;
|
||||
public var offset(default, set):Float = 0;
|
||||
public var size(default, default):Float = 0;
|
||||
public var scroll(null, null):ScrollBarView;
|
||||
public var offsetSignal(default, null):Signal<Float>;
|
||||
|
||||
private var scrollFactory:Void -> ScrollBarView;
|
||||
|
||||
public function new(scrollFactory:Void -> ScrollBarView) {
|
||||
this.scrollFactory = scrollFactory;
|
||||
offsetSignal = new Signal();
|
||||
}
|
||||
|
||||
private function set_offset(value:Float):Float {
|
||||
if (offset != value) {
|
||||
offset = checkOffset(value);
|
||||
if (scroll != null) {
|
||||
scroll.position = -offset / size / overflow;
|
||||
}
|
||||
offsetSignal.emit(offset);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
private function checkOffset(value:Float):Float {
|
||||
if (value > 0) {
|
||||
return 0;
|
||||
} else if (value < -size * (overflow - 1)) {
|
||||
return -size * (overflow - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public function set_overflow(value:Float):Float {
|
||||
if (overflow != value) {
|
||||
overflow = value;
|
||||
if (overflow > 1 && scroll == null) {
|
||||
scroll = scrollFactory();
|
||||
scroll.onScroll.connect(function(value) {
|
||||
offset = value > 0 ? -value * overflow * size : 0;
|
||||
});
|
||||
}
|
||||
if (scroll != null) {
|
||||
scroll.ratio = 1 / overflow;
|
||||
}
|
||||
offset = checkOffset(offset);
|
||||
}
|
||||
return overflow;
|
||||
}
|
||||
}
|
||||
|
||||
@:style(true) class GroupView extends SpriteView implements IGroupView {
|
||||
public var container(get, null):DisplayObjectContainer;
|
||||
public var container(null, null):DisplayObjectContainer;
|
||||
|
||||
public var views(default, set):Array<IView<Dynamic>>;
|
||||
@:style public var layout(default, default):ILayout;
|
||||
@:style public var overflow(default, default):Overflow;
|
||||
|
||||
public function new(?layout:ILayout) {
|
||||
public var overflowX(default, set):Float;
|
||||
public var overflowY(default, set):Float;
|
||||
|
||||
private var _mask:Sprite;
|
||||
private var scrollX(get, null):HScrollBarView;
|
||||
private var scrollY(get, null):VScrollBarView;
|
||||
|
||||
public var overflowControlX(default, null):OverflowControl;
|
||||
public var overflowControlY(default, null):OverflowControl;
|
||||
|
||||
public function new(?layout:ILayout, ?overflow:Overflow) {
|
||||
super();
|
||||
this.layout = layout == null ? new DefaultLayout() : layout;
|
||||
container = new Sprite();
|
||||
content.addChild(container);
|
||||
_mask = new Sprite();
|
||||
content.addChild(_mask);
|
||||
container.mask = _mask;
|
||||
this.layout = layout != null ? layout : new DefaultLayout();
|
||||
this.overflow = overflow != null ? overflow : new Overflow();
|
||||
views = [];
|
||||
overflowControlX = new OverflowControl(function() return scrollX);
|
||||
overflowControlX.offsetSignal.connect(function(value) container.x = value);
|
||||
overflowControlY = new OverflowControl(function() return scrollY);
|
||||
overflowControlY.offsetSignal.connect(function(value) container.y = value);
|
||||
content.addEventListener(MouseEvent.MOUSE_WHEEL, _onMouseWheelEvent);
|
||||
}
|
||||
|
||||
inline private function get_container():DisplayObjectContainer {
|
||||
return content;
|
||||
private function get_scrollX():HScrollBarView {
|
||||
if (scrollX == null) {
|
||||
scrollX = new HScrollBarView();
|
||||
scrollX.geometry.position = Position.ABSOLUTE;
|
||||
addView(scrollX);
|
||||
container.removeChild(scrollX.content);
|
||||
content.addChild(scrollX.content);
|
||||
}
|
||||
return scrollX;
|
||||
}
|
||||
|
||||
private function get_scrollY():VScrollBarView {
|
||||
if (scrollY == null) {
|
||||
scrollY = new VScrollBarView();
|
||||
scrollY.geometry.position = Position.ABSOLUTE;
|
||||
addView(scrollY);
|
||||
container.removeChild(scrollY.content);
|
||||
content.addChild(scrollY.content);
|
||||
}
|
||||
return scrollY;
|
||||
}
|
||||
|
||||
private function _onMouseWheelEvent(event:MouseEvent):Void {
|
||||
if (overflowY > 1) {
|
||||
#if flash event.preventDefault(); #end
|
||||
overflowControlY.offset += event.delta * 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function set_overflowX(value:Float):Float {
|
||||
return overflowX = overflowControlX.overflow = value;
|
||||
}
|
||||
|
||||
public function set_overflowY(value:Float):Float {
|
||||
return overflowY = overflowControlY.overflow = value;
|
||||
}
|
||||
|
||||
override public function update():Void {
|
||||
@@ -26,9 +140,15 @@ import haxework.view.layout.ILayout;
|
||||
for (view in views) {
|
||||
view.update();
|
||||
if (view.index > -1) {
|
||||
content.setChildIndex(view.content, view.index);
|
||||
container.setChildIndex(view.content, Std.int(Math.min(views.length - 1, view.index)));
|
||||
}
|
||||
}
|
||||
overflowControlX.size = width;
|
||||
overflowControlY.size = height;
|
||||
_mask.graphics.clear();
|
||||
_mask.graphics.beginFill(0, 1);
|
||||
_mask.graphics.drawRect(0, 0, width, height);
|
||||
_mask.graphics.endFill();
|
||||
}
|
||||
|
||||
public function set_views(value:Array<IView<Dynamic>>):Array<IView<Dynamic>> {
|
||||
@@ -44,7 +164,7 @@ import haxework.view.layout.ILayout;
|
||||
|
||||
public function addView(view:IView<Dynamic>):IView<Dynamic> {
|
||||
views.push(view);
|
||||
if (view.content != null) content.addChild(view.content);
|
||||
if (view.content != null) container.addChild(view.content);
|
||||
view.parent = this;
|
||||
toUpdate();
|
||||
return view;
|
||||
@@ -53,7 +173,7 @@ import haxework.view.layout.ILayout;
|
||||
public function insertView(view:IView<Dynamic>, index:Int):IView<Dynamic> {
|
||||
if (index < 0) index = views.length + index;
|
||||
views.insert(index, view);
|
||||
if (view.content != null) content.addChild(view.content);
|
||||
if (view.content != null) container.addChild(view.content);
|
||||
view.parent = this;
|
||||
toUpdate();
|
||||
return view;
|
||||
@@ -61,7 +181,7 @@ import haxework.view.layout.ILayout;
|
||||
|
||||
public function addViewFirst(view:IView<Dynamic>):IView<Dynamic> {
|
||||
views.unshift(view);
|
||||
content.addChild(view.content);
|
||||
container.addChild(view.content);
|
||||
view.parent = this;
|
||||
toUpdate();
|
||||
return view;
|
||||
@@ -70,14 +190,22 @@ import haxework.view.layout.ILayout;
|
||||
public function removeView(view:IView<Dynamic>):IView<Dynamic> {
|
||||
view.parent = null;
|
||||
views.remove(view);
|
||||
if (view.content != null) content.removeChild(view.content);
|
||||
if (view.content != null) container.removeChild(view.content);
|
||||
toUpdate();
|
||||
return view;
|
||||
}
|
||||
|
||||
public function removeAllViews():Void {
|
||||
if (views != null) while (views.length > 0) {
|
||||
/*if (views != null) while (views.length > 0) {
|
||||
removeView(views[0]);
|
||||
}*/
|
||||
if (views != null) {
|
||||
for (i in 0...views.length) {
|
||||
var view = views[i];
|
||||
if (view != scrollX && view != scrollY) {
|
||||
removeView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package haxework.view.group;
|
||||
|
||||
import flash.display.DisplayObjectContainer;
|
||||
import haxework.view.group.Overflow.Overflow;
|
||||
import haxework.view.layout.ILayout;
|
||||
|
||||
interface IGroupView extends IView<Dynamic> {
|
||||
public var layout(default, set):ILayout;
|
||||
public var overflow(default, set):Overflow;
|
||||
|
||||
public var container(get, null):DisplayObjectContainer;
|
||||
public var overflowX(default, set):Float;
|
||||
public var overflowY(default, set):Float;
|
||||
|
||||
public var container(null, null):DisplayObjectContainer;
|
||||
public var views(default, set):Array<IView<Dynamic>>;
|
||||
|
||||
public function containsView(view:IView<Dynamic>):Bool;
|
||||
|
||||
17
src/main/haxework/view/group/Overflow.hx
Normal file
17
src/main/haxework/view/group/Overflow.hx
Normal file
@@ -0,0 +1,17 @@
|
||||
package haxework.view.group;
|
||||
|
||||
@:enum abstract OverflowType(String) from String to String {
|
||||
var STRETCH = "stretch";
|
||||
var SCROLL = "scroll";
|
||||
var CROP = "crop";
|
||||
}
|
||||
|
||||
@:style class Overflow {
|
||||
@:style(STRETCH) public var x(default, default):OverflowType;
|
||||
@:style(STRETCH) public var y(default, default):OverflowType;
|
||||
|
||||
public function new(?overflowX:OverflowType, ?overflowY:OverflowType) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import haxework.view.geometry.HAlign;
|
||||
import haxework.view.geometry.Position;
|
||||
import haxework.view.geometry.VAlign;
|
||||
import haxework.view.group.IGroupView;
|
||||
import haxework.view.group.Overflow;
|
||||
|
||||
class DefaultLayout extends Layout {
|
||||
|
||||
@@ -19,7 +20,31 @@ class DefaultLayout extends Layout {
|
||||
width = Math.max(width, size.width + view.geometry.margin.horizontal);
|
||||
height = Math.max(height, size.height + view.geometry.margin.horizontal);
|
||||
}
|
||||
if (!overflow) group.setSize(width, height, "group");
|
||||
setGroupSize(group, width, height);
|
||||
}
|
||||
|
||||
private function setGroupSize(group:IGroupView, width:Float, height:Float):Void {
|
||||
group.setSize(
|
||||
switch group.overflow.x {
|
||||
case STRETCH: width;
|
||||
case _: 0;
|
||||
},
|
||||
switch group.overflow.y {
|
||||
case STRETCH: height;
|
||||
case _: 0;
|
||||
},
|
||||
"group"
|
||||
);
|
||||
switch group.overflow.x {
|
||||
case SCROLL:
|
||||
group.overflowX = width / group.width;
|
||||
case _:
|
||||
}
|
||||
switch group.overflow.y {
|
||||
case SCROLL:
|
||||
group.overflowY = height / group.height;
|
||||
case _:
|
||||
}
|
||||
}
|
||||
|
||||
private function filterViews(group:IGroupView, views:Array<IView<Dynamic>>):Array<IView<Dynamic>> {
|
||||
|
||||
@@ -25,7 +25,7 @@ class HorizontalLayout extends DefaultLayout {
|
||||
maxSize = Math.max(maxSize, view.size.toSize("percent").height + view.geometry.padding.vertical + view.geometry.margin.vertical);
|
||||
}
|
||||
|
||||
if (!overflow) group.setSize(fixedSize, maxSize, "group");
|
||||
setGroupSize(group, fixedSize, maxSize);
|
||||
|
||||
leftSize -= fixedSize;
|
||||
for (view in views) {
|
||||
|
||||
@@ -9,7 +9,6 @@ interface ILayout extends IStylable {
|
||||
public var hAlign(get, set):HAlign;
|
||||
public var vAlign(get, set):VAlign;
|
||||
public var margin(get, set):Null<Float>;
|
||||
public var overflow(get, set):Null<Bool>;
|
||||
|
||||
public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void;
|
||||
|
||||
|
||||
@@ -9,11 +9,8 @@ import haxework.view.group.IGroupView;
|
||||
@:style(HAlign.NONE) public var hAlign(default, default):HAlign;
|
||||
@:style(VAlign.NONE) public var vAlign(default, default):VAlign;
|
||||
@:style(0) public var margin(default, default):Null<Float>;
|
||||
@:style(false) public var overflow(default, default):Null<Bool>;
|
||||
|
||||
public function new() {
|
||||
|
||||
}
|
||||
public function new() {}
|
||||
|
||||
public function place(group:IGroupView, views:Array<IView<Dynamic>>):Void {}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class VerticalLayout extends DefaultLayout {
|
||||
maxSize = Math.max(maxSize, view.size.toSize("percent").width + view.geometry.padding.horizontal + view.geometry.margin.horizontal);
|
||||
}
|
||||
|
||||
if (!overflow) group.setSize(maxSize, fixedSize, "group");
|
||||
setGroupSize(group, maxSize, fixedSize);
|
||||
|
||||
leftSize -= fixedSize;
|
||||
for (view in views) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package haxework.view.list;
|
||||
|
||||
import haxework.view.group.Overflow;
|
||||
import flash.events.MouseEvent;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.utils.NumberUtil;
|
||||
@@ -50,7 +51,7 @@ class ListView<D> extends GroupView {
|
||||
addView(main);
|
||||
box = new GroupView(layout);
|
||||
box.geometry.stretch = true;
|
||||
box.layout.overflow = true;
|
||||
box.overflow.y = CROP;
|
||||
main.addView(box);
|
||||
mask = new SpriteView();
|
||||
mask.geometry.stretch = true;
|
||||
|
||||
@@ -5,8 +5,8 @@ import haxework.color.ColorUtil;
|
||||
import haxework.view.list.ScrollBarView;
|
||||
|
||||
@:style class VScrollBarSkin implements ISkin<ScrollBarView> {
|
||||
@:style(0xff0000) public var foreColor(default, default):Null<Color>;
|
||||
@:style(0xffff00) public var backColor(default, default):Null<Color>;
|
||||
@:style(0) public var foreColor(default, default):Null<Color>;
|
||||
@:style(0) public var backColor(default, default):Null<Color>;
|
||||
|
||||
public function new(?foreColor:Color, ?backColor:Color) {
|
||||
this.foreColor = foreColor;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package haxework.view.theme;
|
||||
|
||||
import haxework.view.geometry.VAlign;
|
||||
import haxework.view.geometry.HAlign;
|
||||
import flash.text.Font;
|
||||
import flash.text.FontType;
|
||||
import haxework.color.Color;
|
||||
@@ -124,12 +126,14 @@ class Theme implements ITheme {
|
||||
"skin.backColor" => colors.dark,
|
||||
"geometry.width" => SizeValue.fromFloat(10),
|
||||
"geometry.height" => SizeValue.fromString("100%"),
|
||||
"geometry.hAlign" => HAlign.RIGHT,
|
||||
]));
|
||||
register(new Style("scroll.horizontal", [
|
||||
"skin.foreColor" => colors.light,
|
||||
"skin.backColor" => colors.dark,
|
||||
"geometry.width" => SizeValue.fromString("100%"),
|
||||
"geometry.height" => SizeValue.fromFloat(10),
|
||||
"geometry.vAlign" => VAlign.BOTTOM,
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user