Skip to content

Commit

Permalink
allow box's to use datasources and itemrenderers (1st pass)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianharrigan committed Feb 27, 2024
1 parent 5e95236 commit d9c495c
Showing 1 changed file with 113 additions and 3 deletions.
116 changes: 113 additions & 3 deletions haxe/ui/containers/Box.hx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ import haxe.ui.layouts.DefaultLayout;
import haxe.ui.layouts.LayoutFactory;
import haxe.ui.styles.Style;
import haxe.ui.util.Variant;
import haxe.ui.core.CompositeBuilder;
import haxe.ui.core.ItemRenderer;
import haxe.ui.core.IDataComponent;
import haxe.ui.data.ArrayDataSource;
import haxe.ui.data.DataSource;
import haxe.ui.behaviours.DataBehaviour;
import haxe.ui.events.UIEvent;

/**
Base `Layout` that allows a container to specify an `icon`. How that icon resource is used depends on subclasses, like `TabView`
**/
@:dox(icon = "/icons/ui-panel.png")
@:composite(DefaultLayout)
class Box extends Component {
@:composite(Builder, DefaultLayout)
class Box extends Component implements IDataComponent {
//***********************************************************************************************************
// Public API
//***********************************************************************************************************
Expand All @@ -23,6 +30,7 @@ class Box extends Component {
of it should they want to
**/
@:clonable @:behaviour(DefaultBehaviour) public var icon:Variant;
@:clonable @:behaviour(DataSourceBehaviour) public var dataSource:DataSource<Dynamic>;

@:noCompletion private var _layoutName:String;
@:clonable public var layoutName(get, set):String;
Expand All @@ -42,6 +50,20 @@ class Box extends Component {
return value;
}

private var _itemRenderer:ItemRenderer;
@:clonable public var itemRenderer(get, set):ItemRenderer;
private function get_itemRenderer():ItemRenderer {
return _itemRenderer;
}
private function set_itemRenderer(value:ItemRenderer):ItemRenderer {
if (_itemRenderer != value) {
_itemRenderer = value;
invalidateComponentLayout();
}

return value;
}

//***********************************************************************************************************
// Internals
//***********************************************************************************************************
Expand All @@ -64,4 +86,92 @@ class Box extends Component {
layoutName = style.layout;
}
}
}
}

private class Builder extends CompositeBuilder {
private var _box:Box;

public function new(box:Box) {
super(box);
_box = box;
}

@:access(haxe.ui.backend.ComponentImpl)
public override function addComponent(child:Component):Component {
var r = null;
if (child is ItemRenderer && _box.itemRenderer == null) {
_box.itemRenderer = cast(child, ItemRenderer);
_box.itemRenderer.ready();
_box.itemRenderer.handleVisibility(false);
r = child;
} else {
r = super.addComponent(child);
}
return r;
}
}

//***********************************************************************************************************
// Behaviours
//***********************************************************************************************************
@:dox(hide) @:noCompletion
private class DataSourceBehaviour extends DataBehaviour {
private var _box:Box;

public function new(box:Box) {
super(box);
_box = box;
}

public override function set(value:Variant) {
super.set(value);
var dataSource:DataSource<Dynamic> = _value;
if (dataSource != null) {
dataSource.onDataSourceChange = function() {
syncChildren();
}
}
syncChildren();
}

public override function get():Variant {
if (_value == null || _value.isNull) {
_value = new ArrayDataSource<Dynamic>();
var dataSource:DataSource<Dynamic> = _value;
dataSource.onDataSourceChange = function() {
syncChildren();
}
}
return _value;
}

private function syncChildren() { // can probably be more efficient here, but doesnt seem to cause any obvious perf problem
// wouldnt hurt to just reuse item renderers though rather than destroying and creating them
var dataSource:DataSource<Dynamic> = _value;
for (i in 0...dataSource.size) {
var item = dataSource.get(i);
var renderer = findRenderer(item);
if (renderer == null) {
renderer = _box.itemRenderer.cloneComponent();
_box.addComponent(renderer);
}
_box.setComponentIndex(renderer, i);
renderer.data = item;
}
var childrenToRemove = [];
for (child in _component.findComponents(ItemRenderer)) {
if (dataSource.indexOf(child.data) == -1) {
_box.removeComponent(child);
}
}
}

private function findRenderer(data:Dynamic):ItemRenderer {
for (child in _component.findComponents(ItemRenderer)) {
if (child.data == data) {
return child;
}
}
return null;
}
}

0 comments on commit d9c495c

Please sign in to comment.