mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Optimize FList rendering
This commit is contained in:
@@ -50,7 +50,6 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
|
||||
private static final FSkinColor ALT_ROW_COLOR = BACK_COLOR.getContrastColor(-20);
|
||||
private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE);
|
||||
private static final float ROW_HEIGHT = Utils.AVG_FINGER_HEIGHT + 12;
|
||||
private static final float ROW_PADDING = 5;
|
||||
|
||||
private final ItemList list = new ItemList();
|
||||
private final ItemListModel listModel;
|
||||
@@ -212,7 +211,7 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
|
||||
|
||||
@Override
|
||||
public void scrollSelectionIntoView() {
|
||||
list.scrollIntoView(list.getItemAt(getSelectedIndex()));
|
||||
list.scrollIntoView(getSelectedIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,10 +290,10 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Entry<T, Integer> value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height) {
|
||||
Vector2 loc = new Vector2(ROW_PADDING, ROW_PADDING);
|
||||
public void drawValue(Graphics g, Entry<T, Integer> value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
Vector2 loc = new Vector2(x, y);
|
||||
for (ItemCell cell : cells) {
|
||||
cell.getCellRenderer().draw(g, cell.getFnDisplay().apply(value), font, foreColor, loc, width, height);
|
||||
cell.getCellRenderer().draw(g, cell.getFnDisplay().apply(value), font, foreColor, loc, w, h);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -315,8 +314,7 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FSkinColor getItemFillColor(ListItem item) {
|
||||
int index = Math.round(item.getTop() / ROW_HEIGHT); //more efficient indexing strategy
|
||||
protected FSkinColor getItemFillColor(int index) {
|
||||
if (selectedIndices.contains(index)) {
|
||||
return SEL_COLOR;
|
||||
}
|
||||
|
||||
@@ -868,7 +868,7 @@ public class ConstructedScreen extends LaunchScreen {
|
||||
}
|
||||
|
||||
public Object getSelectedValue() {
|
||||
return list.getItemValueAt(selectedIndex);
|
||||
return list.getItemAt(selectedIndex);
|
||||
}
|
||||
|
||||
public void setSelectedValue(Object value) {
|
||||
@@ -1077,17 +1077,15 @@ public class ConstructedScreen extends LaunchScreen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Variant value, FSkinFont font, FSkinColor color, boolean pressed, float width, float height) {
|
||||
public void drawValue(Graphics g, Variant value, FSkinFont font, FSkinColor color, boolean pressed, float x, float y, float w, float h) {
|
||||
String text = value.gameType.toString();
|
||||
float x = width * SettingsScreen.INSETS_FACTOR;
|
||||
float y = x;
|
||||
float w = width - 2 * x;
|
||||
float h = font.getFont().getMultiLineBounds(text).height + 5;
|
||||
float totalHeight = h;
|
||||
h = font.getFont().getMultiLineBounds(text).height + 5;
|
||||
|
||||
g.drawText(text, font, color, x, y, w, h, false, HAlignment.LEFT, false);
|
||||
value.draw(g, font, color, x, y, w, h);
|
||||
h += 5;
|
||||
g.drawText(value.description, SettingsScreen.DESC_FONT, SettingsScreen.DESC_COLOR, x, y + h, w, height - h - y, true, HAlignment.LEFT, false);
|
||||
g.drawText(value.description, SettingsScreen.DESC_FONT, SettingsScreen.DESC_COLOR, x, y + h, w, totalHeight - h - y, true, HAlignment.LEFT, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class InputSelectCard {
|
||||
private static final float LIST_OPTION_HEIGHT = Utils.AVG_FINGER_HEIGHT;
|
||||
private static final long DOUBLE_TAP_INTERVAL = Utils.secondsToTimeSpan(FGestureAdapter.DOUBLE_TAP_INTERVAL);
|
||||
private static CardOptionsList<?> activeList;
|
||||
private static CardOptionsList<?>.ListItem pressedItem;
|
||||
private static boolean simulatedListPress;
|
||||
private static long lastSelectTime;
|
||||
private static boolean zoomPressed, detailsPressed, ownerPressed, pannedOverOptions;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class InputSelectCard {
|
||||
if (activeList.owner == cardPanel) {
|
||||
if (activeList.getCount() > 0 && now - lastSelectTime <= DOUBLE_TAP_INTERVAL) {
|
||||
//auto-select first option if double tapped
|
||||
activeList.getItemAt(0).tap(0, 0, 1);
|
||||
activeList.tap(0, -activeList.getScrollTop(), 1);
|
||||
}
|
||||
return; //don't select already selected card
|
||||
}
|
||||
@@ -103,9 +103,12 @@ public class InputSelectCard {
|
||||
}
|
||||
|
||||
public static boolean handlePan(CardAreaPanel cardPanel, float x, float y, boolean isPanStop) {
|
||||
if (pressedItem != null) {
|
||||
pressedItem.release(x, y); //prevent pressed item getting stuck
|
||||
pressedItem = null;
|
||||
if (simulatedListPress) {
|
||||
//prevent pressed item getting stuck
|
||||
if (activeList != null) {
|
||||
activeList.release(x, y - activeList.getTop());
|
||||
}
|
||||
simulatedListPress = false;
|
||||
}
|
||||
zoomPressed = false;
|
||||
detailsPressed = false;
|
||||
@@ -119,21 +122,19 @@ public class InputSelectCard {
|
||||
|
||||
if (y < 0) {
|
||||
if (activeList.getCount() > 0) {
|
||||
int index = Math.round(activeList.getCount() + y / LIST_OPTION_HEIGHT);
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
//simulate tap or press on list
|
||||
float listY = activeList.getHeight() + y;
|
||||
if (listY < 0) {
|
||||
listY = 0;
|
||||
}
|
||||
CardOptionsList<?>.ListItem item = activeList.getItemAt(index);
|
||||
if (item != null) {
|
||||
if (isPanStop) {
|
||||
item.tap(0, 0, 1);
|
||||
}
|
||||
else {
|
||||
item.press(0, 0);
|
||||
pressedItem = item;
|
||||
}
|
||||
pannedOverOptions = true;
|
||||
if (isPanStop) {
|
||||
activeList.tap(x, listY, 1);
|
||||
}
|
||||
else {
|
||||
activeList.press(x, listY);
|
||||
simulatedListPress = true;
|
||||
}
|
||||
pannedOverOptions = true;
|
||||
}
|
||||
}
|
||||
else if (y > cardPanel.getHeight()) {
|
||||
@@ -206,13 +207,11 @@ public class InputSelectCard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Object value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height) {
|
||||
float x = width * FList.INSETS_FACTOR;
|
||||
float y = x;
|
||||
public void drawValue(Graphics g, Object value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
if (!pressed) {
|
||||
foreColor = foreColor.alphaColor(ALPHA_COMPOSITE);
|
||||
}
|
||||
g.drawText(value.toString(), font, foreColor, x, y, width - 2 * x, height - 2 * y, true, HAlignment.CENTER, true);
|
||||
g.drawText(value.toString(), font, foreColor, x, y, w, h, true, HAlignment.CENTER, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import forge.game.GameLogEntryType;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.FScreen;
|
||||
import forge.toolbox.FGroupList;
|
||||
import forge.toolbox.FList;
|
||||
import forge.util.Utils;
|
||||
|
||||
@@ -24,7 +25,7 @@ public class SettingsScreen extends FScreen {
|
||||
public static final FSkinFont DESC_FONT = FSkinFont.get(11);
|
||||
public static final FSkinColor DESC_COLOR = FSkinColor.get(Colors.CLR_TEXT).alphaColor(0.5f);
|
||||
|
||||
private final FList<Setting> lstSettings = add(new FList<Setting>());
|
||||
private final FGroupList<Setting> lstSettings = add(new FGroupList<Setting>());
|
||||
|
||||
public SettingsScreen() {
|
||||
super(true, "Settings", false);
|
||||
@@ -237,16 +238,12 @@ public class SettingsScreen extends FScreen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, String value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height) {
|
||||
float x = width * INSETS_FACTOR;
|
||||
float y = 0;
|
||||
width -= 2 * x;
|
||||
public void drawValue(Graphics g, String value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
g.drawText(value, font, foreColor, x, y, w, h, false, HAlignment.LEFT, true);
|
||||
|
||||
g.drawText(value, font, foreColor, x, y, width, height, false, HAlignment.LEFT, true);
|
||||
|
||||
float radius = height / 5;
|
||||
x += width - radius;
|
||||
y = height / 2;
|
||||
float radius = h / 5;
|
||||
x += w - radius;
|
||||
y = h / 2;
|
||||
g.drawCircle(1, DESC_COLOR, x, y, radius);
|
||||
if (value.equals(currentValue)) {
|
||||
g.fillCircle(foreColor, x, y, radius / 2);
|
||||
@@ -280,16 +277,14 @@ public class SettingsScreen extends FScreen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Setting value, FSkinFont font, FSkinColor color, boolean pressed, float width, float height) {
|
||||
float x = width * INSETS_FACTOR;
|
||||
float y = x;
|
||||
float w = width - 2 * x;
|
||||
float h = font.getFont().getMultiLineBounds(value.label).height + 5;
|
||||
public void drawValue(Graphics g, Setting value, FSkinFont font, FSkinColor color, boolean pressed, float x, float y, float w, float h) {
|
||||
float totalHeight = h;
|
||||
h = font.getFont().getMultiLineBounds(value.label).height + 5;
|
||||
|
||||
g.drawText(value.label, font, color, x, y, w, h, false, HAlignment.LEFT, false);
|
||||
value.drawPrefValue(g, font, color, x, y, w, h);
|
||||
h += 5;
|
||||
g.drawText(value.description, DESC_FONT, DESC_COLOR, x, y + h, w, height - h - y, true, HAlignment.LEFT, false);
|
||||
g.drawText(value.description, DESC_FONT, DESC_COLOR, x, y + h, w, totalHeight - h + w * INSETS_FACTOR, true, HAlignment.LEFT, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,12 +112,8 @@ public class FCardZoom extends FOverlay {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, Object value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height) {
|
||||
float x = width * FList.INSETS_FACTOR;
|
||||
float y = 3;
|
||||
g.startClip(0, 0, width, height);
|
||||
g.drawText(value.toString(), font, foreColor, x, y, width - 2 * x, height - 2 * y, true, HAlignment.CENTER, true);
|
||||
g.endClip();
|
||||
public void drawValue(Graphics g, Object value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
g.drawText(value.toString(), font, foreColor, x, y, w, h, true, HAlignment.CENTER, true);
|
||||
}
|
||||
});
|
||||
prompt = add(new VPrompt("Hide", "More",
|
||||
@@ -152,7 +148,7 @@ public class FCardZoom extends FOverlay {
|
||||
}
|
||||
|
||||
private void selectFirstOption() {
|
||||
selectOption(optionList.getItemValueAt(0));
|
||||
selectOption(optionList.getItemAt(0));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
281
forge-gui-mobile/src/forge/toolbox/FGroupList.java
Normal file
281
forge-gui-mobile/src/forge/toolbox/FGroupList.java
Normal file
@@ -0,0 +1,281 @@
|
||||
package forge.toolbox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Forge.Graphics;
|
||||
import forge.assets.FSkinColor;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinTexture;
|
||||
import forge.screens.FScreen;
|
||||
import forge.toolbox.FEvent.FEventHandler;
|
||||
import forge.toolbox.FList.ListItemRenderer;
|
||||
import forge.toolbox.FList.DefaultListItemRenderer;
|
||||
import forge.util.Utils;
|
||||
|
||||
public class FGroupList<E> extends FScrollPane {
|
||||
private static final float GROUP_HEADER_HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.6f);
|
||||
|
||||
private final List<ListGroup> groups = new ArrayList<ListGroup>();
|
||||
private FSkinFont font;
|
||||
private ListItemRenderer<E> renderer;
|
||||
|
||||
public FGroupList() {
|
||||
initialize();
|
||||
}
|
||||
public FGroupList(E[] itemArray) {
|
||||
for (E item : itemArray) {
|
||||
addItem(item);
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
public FGroupList(Iterable<E> items0) {
|
||||
for (E item : items0) {
|
||||
addItem(item);
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
font = FSkinFont.get(14);
|
||||
renderer = new DefaultListItemRenderer<E>();
|
||||
}
|
||||
|
||||
public void addGroup(String groupName) {
|
||||
groups.add(add(new ListGroup(groupName)));
|
||||
}
|
||||
|
||||
public void addItem(E item) {
|
||||
addItem(item, 0);
|
||||
}
|
||||
public void addItem(E item, int groupIndex) {
|
||||
if (groups.isEmpty()) {
|
||||
addGroup(null);
|
||||
}
|
||||
if (groupIndex > groups.size()) {
|
||||
groupIndex = groups.size() - 1;
|
||||
}
|
||||
groups.get(groupIndex).addItem(new ListItem(item));
|
||||
}
|
||||
|
||||
public void removeItem(E item) {
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem groupItem : group.items) {
|
||||
if (groupItem.value == item) {
|
||||
group.removeItem(groupItem);
|
||||
if (group.items.isEmpty()) {
|
||||
groups.remove(group);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
groups.clear();
|
||||
}
|
||||
|
||||
public void setListData(Iterable<E> items0) {
|
||||
clear();
|
||||
for (E item : items0) {
|
||||
addItem(item);
|
||||
}
|
||||
revalidate();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return groups.isEmpty();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
count += group.items.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public ListItem getItemAt(int index) {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem item : group.items) {
|
||||
if (index == count) {
|
||||
return item;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public E getItemValueAt(int index) {
|
||||
ListItem item = getItemAt(index);
|
||||
if (item == null) { return null; }
|
||||
return item.value;
|
||||
}
|
||||
|
||||
public int getIndexOf(E value) {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem item : group.items) {
|
||||
if (item.value == value) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setListItemRenderer(ListItemRenderer<E> renderer0) {
|
||||
renderer = renderer0;
|
||||
}
|
||||
|
||||
public FSkinFont getFont() {
|
||||
return font;
|
||||
}
|
||||
public int getFontSize() {
|
||||
return font.getSize();
|
||||
}
|
||||
public void setFontSize(int fontSize0) {
|
||||
font = FSkinFont.get(fontSize0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
//support scrolling texture with list
|
||||
g.drawImage(FSkinTexture.BG_TEXTURE, -getScrollLeft(), -getScrollTop(), getScrollWidth(), getScrollHeight());
|
||||
g.fillRect(FScreen.TEXTURE_OVERLAY_COLOR, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
float y = 0;
|
||||
float groupHeight;
|
||||
|
||||
for (ListGroup group : groups) {
|
||||
groupHeight = group.getPreferredHeight();
|
||||
group.setBounds(0, y, visibleWidth, groupHeight);
|
||||
y += groupHeight;
|
||||
}
|
||||
|
||||
return new ScrollBounds(visibleWidth, y);
|
||||
}
|
||||
|
||||
private class ListGroup extends FContainer {
|
||||
private final FLabel header;
|
||||
private final List<ListItem> items = new ArrayList<ListItem>();
|
||||
|
||||
private boolean isCollapsed;
|
||||
|
||||
private ListGroup(String name0) {
|
||||
if (name0 == null) {
|
||||
header = null;
|
||||
}
|
||||
else {
|
||||
header = add(new FLabel.ButtonBuilder().text(name0).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
isCollapsed = !isCollapsed;
|
||||
FGroupList.this.revalidate();
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(ListItem item) {
|
||||
items.add(item);
|
||||
add(item);
|
||||
}
|
||||
|
||||
public boolean removeItem(ListItem item) {
|
||||
if (items.remove(item)) {
|
||||
remove(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public float getPreferredHeight() {
|
||||
float height = 0;
|
||||
if (header != null) {
|
||||
height += GROUP_HEADER_HEIGHT;
|
||||
}
|
||||
if (!isCollapsed) {
|
||||
height += renderer.getItemHeight() * items.size() + 1; //+1 so bottom border not cut off
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float y = 0;
|
||||
if (header != null) {
|
||||
header.setBounds(0, y, width, GROUP_HEADER_HEIGHT);
|
||||
y += GROUP_HEADER_HEIGHT;
|
||||
}
|
||||
|
||||
float itemHeight = renderer.getItemHeight();
|
||||
|
||||
for (ListItem item : items) {
|
||||
item.setBounds(0, y, width, itemHeight);
|
||||
y += itemHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ListItem extends FDisplayObject {
|
||||
private final E value;
|
||||
private boolean pressed;
|
||||
|
||||
private ListItem(E value0) {
|
||||
value = value0;
|
||||
}
|
||||
|
||||
public boolean press(float x, float y) {
|
||||
pressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean release(float x, float y) {
|
||||
pressed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean tap(float x, float y, int count) {
|
||||
return renderer.tap(value, x, y, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void draw(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = renderer.getItemHeight();
|
||||
|
||||
FSkinColor fillColor = getItemFillColor(this);
|
||||
if (fillColor != null) {
|
||||
g.fillRect(fillColor, 0, 0, w, h);
|
||||
}
|
||||
|
||||
float padding = w * FList.INSETS_FACTOR;
|
||||
renderer.drawValue(g, value, font, FList.FORE_COLOR, pressed, padding, padding, w - 2 * padding, h - 2 * padding);
|
||||
|
||||
if (drawLineSeparators()) {
|
||||
g.drawLine(1, FList.LINE_COLOR, 0, h, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected FSkinColor getItemFillColor(ListItem item) {
|
||||
if (item.pressed) {
|
||||
return FList.PRESSED_COLOR;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean drawLineSeparators() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -11,19 +11,18 @@ import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinTexture;
|
||||
import forge.assets.FSkinColor.Colors;
|
||||
import forge.screens.FScreen;
|
||||
import forge.toolbox.FEvent.FEventHandler;
|
||||
import forge.util.Utils;
|
||||
|
||||
public class FList<E> extends FScrollPane {
|
||||
public static final float INSETS_FACTOR = 0.025f;
|
||||
private static final float GROUP_HEADER_HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.6f);
|
||||
public static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
|
||||
public static final FSkinColor PRESSED_COLOR = FSkinColor.get(Colors.CLR_ACTIVE).alphaColor(0.9f);
|
||||
public static final FSkinColor LINE_COLOR = FORE_COLOR.alphaColor(0.5f);
|
||||
|
||||
private final List<ListGroup> groups = new ArrayList<ListGroup>();
|
||||
private final List<E> items = new ArrayList<E>();
|
||||
private FSkinFont font;
|
||||
private ListItemRenderer<E> renderer;
|
||||
private int pressedIndex = -1;
|
||||
|
||||
public FList() {
|
||||
initialize();
|
||||
@@ -46,41 +45,18 @@ public class FList<E> extends FScrollPane {
|
||||
renderer = new DefaultListItemRenderer<E>();
|
||||
}
|
||||
|
||||
public void addGroup(String groupName) {
|
||||
groups.add(add(new ListGroup(groupName)));
|
||||
}
|
||||
|
||||
public void addItem(E item) {
|
||||
addItem(item, 0);
|
||||
}
|
||||
public void addItem(E item, int groupIndex) {
|
||||
if (groups.isEmpty()) {
|
||||
addGroup(null);
|
||||
}
|
||||
if (groupIndex > groups.size()) {
|
||||
groupIndex = groups.size() - 1;
|
||||
}
|
||||
groups.get(groupIndex).addItem(new ListItem(item));
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
public void removeItem(E item) {
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem groupItem : group.items) {
|
||||
if (groupItem.value == item) {
|
||||
group.removeItem(groupItem);
|
||||
if (group.items.isEmpty()) {
|
||||
groups.remove(group);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
items.remove(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
groups.clear();
|
||||
items.clear();
|
||||
}
|
||||
|
||||
public void setListData(Iterable<E> items0) {
|
||||
@@ -92,49 +68,35 @@ public class FList<E> extends FScrollPane {
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return groups.isEmpty();
|
||||
return items.isEmpty();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
count += group.items.size();
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public E getItemAt(int index) {
|
||||
if (index < 0 || index >= items.size()) {
|
||||
return null;
|
||||
}
|
||||
return count;
|
||||
return items.get(index);
|
||||
}
|
||||
|
||||
public ListItem getItemAt(int index) {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem item : group.items) {
|
||||
if (index == count) {
|
||||
return item;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public int getIndexOf(E item) {
|
||||
return items.indexOf(item);
|
||||
}
|
||||
|
||||
public E getItemValueAt(int index) {
|
||||
ListItem item = getItemAt(index);
|
||||
if (item == null) { return null; }
|
||||
return item.value;
|
||||
public E getItemAtPoint(float x, float y) {
|
||||
return getItemAt(getIndexAtPoint(x, y));
|
||||
}
|
||||
|
||||
public int getIndexOf(E value) {
|
||||
int count = 0;
|
||||
for (ListGroup group : groups) {
|
||||
for (ListItem item : group.items) {
|
||||
if (item.value == value) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
public int getIndexAtPoint(float x, float y) {
|
||||
return (int)((getScrollTop() + y) / renderer.getItemHeight());
|
||||
}
|
||||
|
||||
public ListItemRenderer<E> getListItemRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
public void setListItemRenderer(ListItemRenderer<E> renderer0) {
|
||||
renderer = renderer0;
|
||||
}
|
||||
@@ -149,6 +111,49 @@ public class FList<E> extends FScrollPane {
|
||||
font = FSkinFont.get(fontSize0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
return new ScrollBounds(visibleWidth, items.size() * renderer.getItemHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(float x, float y) {
|
||||
pressedIndex = getIndexAtPoint(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(float x, float y) {
|
||||
pressedIndex = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
int index = getIndexAtPoint(x, y);
|
||||
E item = getItemAt(index);
|
||||
if (item == null) { return false; }
|
||||
|
||||
return renderer.tap(item, x, y - getItemTop(index), count);
|
||||
}
|
||||
|
||||
private float getItemTop(int index) {
|
||||
return index * renderer.getItemHeight() - getScrollTop();
|
||||
}
|
||||
|
||||
public void scrollIntoView(int index) {
|
||||
float itemTop = getItemTop(index);
|
||||
if (itemTop < 0) {
|
||||
setScrollTop(itemTop);
|
||||
}
|
||||
else {
|
||||
float itemBottom = itemTop + renderer.getItemHeight();
|
||||
if (itemBottom > getHeight()) {
|
||||
setScrollTop(itemBottom - getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(Graphics g) {
|
||||
//support scrolling texture with list
|
||||
@@ -157,124 +162,48 @@ public class FList<E> extends FScrollPane {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
|
||||
float y = 0;
|
||||
float groupHeight;
|
||||
|
||||
for (ListGroup group : groups) {
|
||||
groupHeight = group.getPreferredHeight();
|
||||
group.setBounds(0, y, visibleWidth, groupHeight);
|
||||
y += groupHeight;
|
||||
}
|
||||
|
||||
return new ScrollBounds(visibleWidth, y);
|
||||
}
|
||||
|
||||
private class ListGroup extends FContainer {
|
||||
private final FLabel header;
|
||||
private final List<ListItem> items = new ArrayList<ListItem>();
|
||||
|
||||
private boolean isCollapsed;
|
||||
|
||||
private ListGroup(String name0) {
|
||||
if (name0 == null) {
|
||||
header = null;
|
||||
}
|
||||
else {
|
||||
header = add(new FLabel.ButtonBuilder().text(name0).command(new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
isCollapsed = !isCollapsed;
|
||||
FList.this.revalidate();
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(ListItem item) {
|
||||
items.add(item);
|
||||
add(item);
|
||||
}
|
||||
|
||||
public boolean removeItem(ListItem item) {
|
||||
if (items.remove(item)) {
|
||||
remove(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public float getPreferredHeight() {
|
||||
float height = 0;
|
||||
if (header != null) {
|
||||
height += GROUP_HEADER_HEIGHT;
|
||||
}
|
||||
if (!isCollapsed) {
|
||||
height += renderer.getItemHeight() * items.size();
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLayout(float width, float height) {
|
||||
float y = 0;
|
||||
if (header != null) {
|
||||
header.setBounds(0, y, width, GROUP_HEADER_HEIGHT);
|
||||
y += GROUP_HEADER_HEIGHT;
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
g.startClip(0, 0, w, h);
|
||||
drawBackground(g);
|
||||
|
||||
//draw only items that are visible
|
||||
if (!items.isEmpty()) {
|
||||
int startIndex = getIndexAtPoint(0, 0);
|
||||
float itemHeight = renderer.getItemHeight();
|
||||
boolean drawSeparators = drawLineSeparators();
|
||||
|
||||
float padding = w * INSETS_FACTOR;
|
||||
float y = getItemTop(startIndex);
|
||||
float valueWidth = w - 2 * padding;
|
||||
float valueHeight = itemHeight - 2 * padding;
|
||||
|
||||
for (int i = startIndex; i < items.size(); i++) {
|
||||
if (y > h) { break; }
|
||||
|
||||
FSkinColor fillColor = getItemFillColor(i);
|
||||
if (fillColor != null) {
|
||||
g.fillRect(fillColor, 0, y, w, itemHeight);
|
||||
}
|
||||
|
||||
renderer.drawValue(g, items.get(i), font, FORE_COLOR, pressedIndex == i, padding, y + padding, valueWidth, valueHeight);
|
||||
|
||||
for (ListItem item : items) {
|
||||
item.setBounds(0, y, width, itemHeight);
|
||||
y += itemHeight;
|
||||
|
||||
if (drawSeparators) {
|
||||
g.drawLine(1, LINE_COLOR, 0, y, w, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawOverlay(g);
|
||||
g.endClip();
|
||||
}
|
||||
|
||||
public class ListItem extends FDisplayObject {
|
||||
private final E value;
|
||||
private boolean pressed;
|
||||
|
||||
private ListItem(E value0) {
|
||||
value = value0;
|
||||
}
|
||||
|
||||
public boolean press(float x, float y) {
|
||||
pressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean release(float x, float y) {
|
||||
pressed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean tap(float x, float y, int count) {
|
||||
return renderer.tap(value, x, y, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void draw(Graphics g) {
|
||||
float w = getWidth();
|
||||
float h = renderer.getItemHeight();
|
||||
|
||||
FSkinColor fillColor = getItemFillColor(this);
|
||||
if (fillColor != null) {
|
||||
g.fillRect(fillColor, 0, 0, w, h);
|
||||
}
|
||||
|
||||
renderer.drawValue(g, value, font, FORE_COLOR, pressed, w, h);
|
||||
|
||||
if (drawLineSeparators()) {
|
||||
g.drawLine(1, LINE_COLOR, 0, h, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected FSkinColor getItemFillColor(ListItem item) {
|
||||
if (item.pressed) {
|
||||
return PRESSED_COLOR;
|
||||
protected FSkinColor getItemFillColor(int index) {
|
||||
if (index == pressedIndex) {
|
||||
return FList.PRESSED_COLOR;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -286,7 +215,7 @@ public class FList<E> extends FScrollPane {
|
||||
public static abstract class ListItemRenderer<V> {
|
||||
public abstract float getItemHeight();
|
||||
public abstract boolean tap(V value, float x, float y, int count);
|
||||
public abstract void drawValue(Graphics g, V value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height);
|
||||
public abstract void drawValue(Graphics g, V value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h);
|
||||
}
|
||||
|
||||
public static class DefaultListItemRenderer<V> extends ListItemRenderer<V> {
|
||||
@@ -301,10 +230,8 @@ public class FList<E> extends FScrollPane {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, V value, FSkinFont font, FSkinColor color, boolean pressed, float width, float height) {
|
||||
float x = width * INSETS_FACTOR;
|
||||
float y = x;
|
||||
g.drawText(value.toString(), font, color, x, y, width - 2 * x, height - 2 * y, false, HAlignment.LEFT, true);
|
||||
public void drawValue(Graphics g, V value, FSkinFont font, FSkinColor color, boolean pressed, float x, float y, float w, float h) {
|
||||
g.drawText(value.toString(), font, color, x, y, w, h, false, HAlignment.LEFT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +256,8 @@ public abstract class FScrollPane extends FContainer {
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void draw(Graphics g) {
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
g.startClip(0, 0, getWidth(), getHeight());
|
||||
super.draw(g);
|
||||
g.endClip();
|
||||
|
||||
@@ -107,7 +107,7 @@ public class ListChooser<T> {
|
||||
if (result == 0) {
|
||||
List<T> choices = new ArrayList<T>();
|
||||
for (int i : lstChoices.selectedIndices) {
|
||||
choices.add(lstChoices.getItemValueAt(i));
|
||||
choices.add(lstChoices.getItemAt(i));
|
||||
}
|
||||
callback.run(choices);
|
||||
}
|
||||
@@ -190,9 +190,8 @@ public class ListChooser<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float width, float height) {
|
||||
float x = width * INSETS_FACTOR;
|
||||
g.drawText(value.toString(), font, foreColor, x, 0, width - 2 * x, height, false, HAlignment.LEFT, true);
|
||||
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
g.drawText(value.toString(), font, foreColor, x, y, w, h, false, HAlignment.LEFT, true);
|
||||
}
|
||||
});
|
||||
setFontSize(12);
|
||||
@@ -209,8 +208,7 @@ public class ListChooser<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FSkinColor getItemFillColor(ListItem item) {
|
||||
int index = Math.round(item.getTop() / ITEM_HEIGHT); //more efficient indexing strategy
|
||||
protected FSkinColor getItemFillColor(int index) {
|
||||
if (selectedIndices.contains(index)) {
|
||||
return SEL_COLOR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user