package com.github.czyzby.lml.vis.parser.impl.tag;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.utils.Array;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.impl.tag.actor.TableLmlTag;
import com.github.czyzby.lml.parser.tag.LmlActorBuilder;
import com.github.czyzby.lml.parser.tag.LmlTag;
import com.github.czyzby.lml.util.LmlUtilities;
import com.github.czyzby.lml.vis.parser.impl.tag.builder.ListViewLmlActorBuilder;
import com.kotcrab.vis.ui.util.adapter.ArrayAdapter;
import com.kotcrab.vis.ui.util.adapter.ListAdapter;
import com.kotcrab.vis.ui.widget.ListView;
import com.kotcrab.vis.ui.widget.ListView.ListViewTable;
import com.kotcrab.vis.ui.widget.ListView.UpdatePolicy;
/** Manages {@link ListView} widget. Note that list view is not actually an {@link Actor} - instead, its main table is
* used as the main widget. When injecting the list view into fields or methods, expect {@link ListViewTable} instance
* and extract {@link ListView} with {@link ListViewTable#getListView()} method. Mapped to "listView".
*
* <p>
* Normally, list views are used to display collections of values. However, they can also be used as regular groups of
* actors. If no {@link ListAdapter} is set with "adapter" attribute, a default implementation is provided. The default
* adapter is prepared to handle regular actors, allowing the tag to have children. If a custom adapter is provided with
* "adapter" attribute, this tag cannot have regular children.
*
* <p>
* To set footer and header, use "footer=true" and "header=true" attributes in list view tag's children.
*
* <p>
* Since list view manages a table and a scroll pane, it can have its attributes in its tag. However, table cell
* attributes CANNOT be used: table is automatically built by the list adapter and should not be modified manually. If
* you want a custom way of building the table, use another adapter implementation.
*
* <p>
* By default, {@link ListView} will be in {@link UpdatePolicy#MANUAL} policy during creation to prevent the table from
* being rebuilt during LML parsing. After the tag is closed, policy will be changed back to
* {@link UpdatePolicy#IMMEDIATELY}. If you want to change this setting, do it manually after full construction of the
* actor (onClose action can be used).
*
* @author MJ */
public class ListViewLmlTag extends TableLmlTag {
private ListView<?> listView;
public ListViewLmlTag(final LmlParser parser, final LmlTag parentTag, final StringBuilder rawTagData) {
super(parser, parentTag, rawTagData);
}
@Override
protected ListViewLmlActorBuilder getNewInstanceOfBuilder() {
return new ListViewLmlActorBuilder();
}
@Override
protected Table getNewInstanceOfActor(final LmlActorBuilder builder) {
final ListAdapter<?> listAdapter = extractListAdapter((ListViewLmlActorBuilder) builder);
listView = createListView(listAdapter, builder.getStyleName());
LmlUtilities.getLmlUserObject(listView.getMainTable()).setData(listView);
listView.setUpdatePolicy(UpdatePolicy.MANUAL); // Prevents the table from being rebuilt during creation.
return listView.getMainTable();
}
/** @return managed {@link ListView}. */
@Override
public Object getManagedObject() {
return listView;
}
/** @param listAdapter converts data to views.
* @param styleName name of list view style applied to the view.
* @return a new instance of ListView.
* @param <Type> type of items stored by the list. */
protected <Type> ListView<Type> createListView(final ListAdapter<Type> listAdapter, String styleName) {
return new ListView<Type>(listAdapter, styleName);
}
/** @param builder may contain a custom adapter.
* @return customized list adapter or the default implementation prepared to handle regular actors. */
protected ListAdapter<?> extractListAdapter(final ListViewLmlActorBuilder builder) {
return builder.getListAdapter() != null ? builder.getListAdapter()
: new ArrayAdapter<Actor, Actor>(new Array<Actor>()) {
@Override
protected Actor createView(final Actor item) {
return item;
}
};
}
@Override
@SuppressWarnings("unchecked")
protected void addChild(final Actor actor) {
if (listView.getFooter() == actor || listView.getHeader() == actor) {
return;
}
((ListAdapter<Actor>) listView.getAdapter()).add(actor);
}
@Override
protected void handlePlainTextLine(final String plainTextLine) {
addChild(toLabel(plainTextLine));
}
@Override
protected boolean hasComponentActors() {
return true;
}
@Override
protected Actor[] getComponentActors(final Actor actor) {
return new Actor[] { listView.getScrollPane() };
}
@Override
protected void doOnTagClose() {
final ListView<?> listView = ((ListViewTable<?>) getActor()).getListView();
listView.rebuildView();
listView.setUpdatePolicy(UpdatePolicy.IMMEDIATELY);
super.doOnTagClose();
}
}