From ec42687d1bfc0e763571c1c0639c7034edc3d426 Mon Sep 17 00:00:00 2001 From: shmyga Date: Thu, 18 Jul 2019 17:55:55 +0300 Subject: [PATCH] [view] remove ScrollView, add scrolls to GroupView --- demo/src/demo/form/DataForm.yaml | 18 +-- demo/src/demo/form/TailForm.yaml | 22 ++- src/main/haxework/view/ScrollView.hx | 82 ---------- src/main/haxework/view/group/GroupView.hx | 150 ++++++++++++++++-- src/main/haxework/view/group/IGroupView.hx | 7 +- src/main/haxework/view/group/Overflow.hx | 17 ++ .../haxework/view/layout/DefaultLayout.hx | 27 +++- .../haxework/view/layout/HorizontalLayout.hx | 2 +- src/main/haxework/view/layout/ILayout.hx | 1 - src/main/haxework/view/layout/Layout.hx | 5 +- .../haxework/view/layout/VerticalLayout.hx | 2 +- src/main/haxework/view/list/ListView.hx | 3 +- src/main/haxework/view/skin/VScrollBarSkin.hx | 4 +- src/main/haxework/view/theme/Theme.hx | 4 + 14 files changed, 217 insertions(+), 127 deletions(-) delete mode 100644 src/main/haxework/view/ScrollView.hx create mode 100644 src/main/haxework/view/group/Overflow.hx diff --git a/demo/src/demo/form/DataForm.yaml b/demo/src/demo/form/DataForm.yaml index e63fc37..39b63f5 100644 --- a/demo/src/demo/form/DataForm.yaml +++ b/demo/src/demo/form/DataForm.yaml @@ -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 diff --git a/demo/src/demo/form/TailForm.yaml b/demo/src/demo/form/TailForm.yaml index 7e24bb7..2d0b32d 100644 --- a/demo/src/demo/form/TailForm.yaml +++ b/demo/src/demo/form/TailForm.yaml @@ -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 diff --git a/src/main/haxework/view/ScrollView.hx b/src/main/haxework/view/ScrollView.hx deleted file mode 100644 index 9c5b50b..0000000 --- a/src/main/haxework/view/ScrollView.hx +++ /dev/null @@ -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; - public var scroll(default, set):ScrollBarView; - - public var ratio(default, null):Signal = 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):IView { - 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>):Array> { - 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(); - } -} diff --git a/src/main/haxework/view/group/GroupView.hx b/src/main/haxework/view/group/GroupView.hx index 0b3a1f9..83d473c 100755 --- a/src/main/haxework/view/group/GroupView.hx +++ b/src/main/haxework/view/group/GroupView.hx @@ -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; + + 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>; @: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>):Array> { @@ -44,7 +164,7 @@ import haxework.view.layout.ILayout; public function addView(view:IView):IView { 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, index:Int):IView { 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):IView { 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):IView { 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); + } + } } } } diff --git a/src/main/haxework/view/group/IGroupView.hx b/src/main/haxework/view/group/IGroupView.hx index 64b76fb..b0cf0c9 100755 --- a/src/main/haxework/view/group/IGroupView.hx +++ b/src/main/haxework/view/group/IGroupView.hx @@ -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 { 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>; public function containsView(view:IView):Bool; diff --git a/src/main/haxework/view/group/Overflow.hx b/src/main/haxework/view/group/Overflow.hx new file mode 100644 index 0000000..e556b2f --- /dev/null +++ b/src/main/haxework/view/group/Overflow.hx @@ -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; + } +} diff --git a/src/main/haxework/view/layout/DefaultLayout.hx b/src/main/haxework/view/layout/DefaultLayout.hx index d82fd70..e5fdf14 100755 --- a/src/main/haxework/view/layout/DefaultLayout.hx +++ b/src/main/haxework/view/layout/DefaultLayout.hx @@ -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>):Array> { diff --git a/src/main/haxework/view/layout/HorizontalLayout.hx b/src/main/haxework/view/layout/HorizontalLayout.hx index fa666f0..f1ad84b 100755 --- a/src/main/haxework/view/layout/HorizontalLayout.hx +++ b/src/main/haxework/view/layout/HorizontalLayout.hx @@ -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) { diff --git a/src/main/haxework/view/layout/ILayout.hx b/src/main/haxework/view/layout/ILayout.hx index a46158b..382225f 100755 --- a/src/main/haxework/view/layout/ILayout.hx +++ b/src/main/haxework/view/layout/ILayout.hx @@ -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; - public var overflow(get, set):Null; public function place(group:IGroupView, views:Array>):Void; diff --git a/src/main/haxework/view/layout/Layout.hx b/src/main/haxework/view/layout/Layout.hx index 564d976..190d85d 100644 --- a/src/main/haxework/view/layout/Layout.hx +++ b/src/main/haxework/view/layout/Layout.hx @@ -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; - @:style(false) public var overflow(default, default):Null; - public function new() { - - } + public function new() {} public function place(group:IGroupView, views:Array>):Void {} diff --git a/src/main/haxework/view/layout/VerticalLayout.hx b/src/main/haxework/view/layout/VerticalLayout.hx index 78779a4..1456fac 100755 --- a/src/main/haxework/view/layout/VerticalLayout.hx +++ b/src/main/haxework/view/layout/VerticalLayout.hx @@ -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) { diff --git a/src/main/haxework/view/list/ListView.hx b/src/main/haxework/view/list/ListView.hx index 2115c1f..2671195 100755 --- a/src/main/haxework/view/list/ListView.hx +++ b/src/main/haxework/view/list/ListView.hx @@ -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 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; diff --git a/src/main/haxework/view/skin/VScrollBarSkin.hx b/src/main/haxework/view/skin/VScrollBarSkin.hx index 4f6422f..bbd2ac8 100644 --- a/src/main/haxework/view/skin/VScrollBarSkin.hx +++ b/src/main/haxework/view/skin/VScrollBarSkin.hx @@ -5,8 +5,8 @@ import haxework.color.ColorUtil; import haxework.view.list.ScrollBarView; @:style class VScrollBarSkin implements ISkin { - @:style(0xff0000) public var foreColor(default, default):Null; - @:style(0xffff00) public var backColor(default, default):Null; + @:style(0) public var foreColor(default, default):Null; + @:style(0) public var backColor(default, default):Null; public function new(?foreColor:Color, ?backColor:Color) { this.foreColor = foreColor; diff --git a/src/main/haxework/view/theme/Theme.hx b/src/main/haxework/view/theme/Theme.hx index 0b78a94..0ee6830 100644 --- a/src/main/haxework/view/theme/Theme.hx +++ b/src/main/haxework/view/theme/Theme.hx @@ -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, ])); }