Flesh out FList and support nested containers

This commit is contained in:
drdev
2014-03-05 21:58:43 +00:00
parent cd45fd824d
commit d13e4dbdc5
9 changed files with 178 additions and 252 deletions

1
.gitattributes vendored
View File

@@ -16033,7 +16033,6 @@ forge-m-base/src/forge/screens/quest/QuestScreen.java -text
forge-m-base/src/forge/screens/sealed/SealedScreen.java -text
forge-m-base/src/forge/screens/settings/SettingsScreen.java -text
forge-m-base/src/forge/toolbox/FButton.java -text
forge-m-base/src/forge/toolbox/FComboBox.java -text
forge-m-base/src/forge/toolbox/FContainer.java -text
forge-m-base/src/forge/toolbox/FDisplayObject.java -text
forge-m-base/src/forge/toolbox/FLabel.java -text

View File

@@ -29,8 +29,6 @@ import forge.screens.SplashScreen;
import forge.screens.home.HomeScreen;
import forge.toolbox.FContainer;
import forge.toolbox.FDisplayObject;
import forge.toolbox.FProgressBar;
import forge.utils.Constants;
public class Forge implements ApplicationListener {
private static Forge game;
@@ -59,7 +57,7 @@ public class Forge implements ApplicationListener {
FSkin.loadLight("journeyman", splashScreen);
// Loads card database on background thread (using progress bar to report progress)
new Thread(new Runnable() {
/*new Thread(new Runnable() {
@Override
public void run() {
final FProgressBar bar = splashScreen.getProgressBar();
@@ -98,7 +96,8 @@ public class Forge implements ApplicationListener {
}
});
}
}).start();
}).start();*/
afterDbLoaded();
}
private void afterDbLoaded() {
@@ -190,7 +189,7 @@ public class Forge implements ApplicationListener {
@Override
public boolean touchUp(float x, float y, int pointer, int button) {
for (FDisplayObject listener : potentialListeners) {
if (listener.touchUp(x, y)) {
if (listener.touchUp(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
break;
}
}
@@ -206,7 +205,7 @@ public class Forge implements ApplicationListener {
currentScreen.buildTouchListeners(x, y, potentialListeners);
}
for (FDisplayObject listener : potentialListeners) {
if (listener.touchDown(x, y)) {
if (listener.touchDown(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
return true;
}
}
@@ -216,7 +215,7 @@ public class Forge implements ApplicationListener {
@Override
public boolean tap(float x, float y, int count, int button) {
for (FDisplayObject listener : potentialListeners) {
if (listener.tap(x, y, count)) {
if (listener.tap(listener.screenToLocalX(x), listener.screenToLocalY(y), count)) {
return true;
}
}
@@ -226,7 +225,7 @@ public class Forge implements ApplicationListener {
@Override
public boolean longPress(float x, float y) {
for (FDisplayObject listener : potentialListeners) {
if (listener.longPress(x, y)) {
if (listener.longPress(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
return true;
}
}
@@ -246,7 +245,7 @@ public class Forge implements ApplicationListener {
@Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
for (FDisplayObject listener : potentialListeners) {
if (listener.pan(x, y, deltaX, deltaY)) {
if (listener.pan(listener.screenToLocalX(x), listener.screenToLocalY(y), deltaX, deltaY)) {
return true;
}
}
@@ -256,7 +255,7 @@ public class Forge implements ApplicationListener {
@Override
public boolean panStop(float x, float y, int pointer, int button) {
for (FDisplayObject listener : potentialListeners) {
if (listener.panStop(x, y)) {
if (listener.panStop(listener.screenToLocalX(x), listener.screenToLocalY(y))) {
return true;
}
}
@@ -320,6 +319,7 @@ public class Forge implements ApplicationListener {
final Rectangle parentBounds = bounds;
bounds = new Rectangle(parentBounds.x + displayObj.getLeft(), parentBounds.y + displayObj.getTop(), displayObj.getWidth(), displayObj.getHeight());
displayObj.setScreenPosition(bounds.x, bounds.y);
if (bounds.overlaps(parentBounds)) { //avoid drawing object if it's not within visible region
displayObj.draw(this);

View File

@@ -1,82 +1,25 @@
package forge.screens.settings;
import java.util.ArrayList;
import java.util.List;
import forge.assets.FSkin;
import forge.screens.FScreen;
import forge.toolbox.FComboBox;
import forge.toolbox.FContainer;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FList;
public class SettingsScreen extends FScreen {
private static final float INSETS_FACTOR = 0.025f;
private static final float GAP_Y_FACTOR = 0.01f;
private final FScrollPane scroller = add(new FScrollPane());
private final List<SettingPanel> settingPanels = new ArrayList<SettingPanel>();
private final FList<Object> lstSettings = add(new FList<Object>());
public SettingsScreen() {
super(true, "Settings", false);
addPanel(new ComboBoxPanel<String>("Theme:", FSkin.getAllSkins(), FSkin.getName()));
}
private void addPanel(SettingPanel panel) {
scroller.add(panel);
settingPanels.add(panel);
lstSettings.addItem("Theme");
lstSettings.addItem("Theme4");
lstSettings.addItem("Theme8");
//addSetting(new ComboBoxPanel<String>("Theme:", FSkin.getAllSkins(), FSkin.getName()));
}
@Override
protected void doLayout(float startY, float width, float height) {
float dy = height * GAP_Y_FACTOR;
scroller.setBounds(0, startY + dy, width, height - startY - dy);
float x = width * INSETS_FACTOR;
float y = 0;
float panelWidth = width - 2 * x;
float panelHeight;
for (SettingPanel panel : settingPanels) {
panelHeight = panel.getPreferredHeight();
panel.setBounds(x, y, panelWidth, panelHeight);
y += panelHeight + dy;
}
}
private abstract class SettingPanel extends FContainer {
public abstract float getPreferredHeight();
}
public class ComboBoxPanel<E> extends SettingPanel {
private final FLabel label;
private final FComboBox<E> comboBox;
public ComboBoxPanel(String labelText, E[] items, E selectedItem) {
this(labelText, new FComboBox<E>(items), selectedItem);
}
public ComboBoxPanel(String labelText, Iterable<E> items, E selectedItem) {
this(labelText, new FComboBox<E>(items), selectedItem);
}
private ComboBoxPanel(String labelText, FComboBox<E> comboBox0, E selectedItem) {
label = add(new FLabel.Builder().text(labelText).build());
comboBox = add(comboBox0);
label.setHeight(FComboBox.PREFERRED_HEIGHT - 6);
comboBox.setHeight(FComboBox.PREFERRED_HEIGHT);
comboBox.setSelectedItem(selectedItem);
}
@Override
protected void doLayout(float width, float height) {
label.setBounds(0, 0, width, label.getHeight());
comboBox.setBounds(0, label.getHeight(), width, comboBox.getHeight());
}
@Override
public float getPreferredHeight() {
return label.getHeight() + comboBox.getHeight();
}
lstSettings.setBounds(0, startY + dy, width, height - startY - dy);
}
}

View File

@@ -1,112 +0,0 @@
package forge.toolbox;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import forge.Forge.Graphics;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinColor.Colors;
import forge.utils.Utils;
public class FComboBox<E> extends FDisplayObject {
public static final float PREFERRED_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.7f;
private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
private static final FSkinColor BACK_COLOR = FSkinColor.get(Colors.CLR_THEME2);
private static final FSkinColor BORDER_COLOR = FORE_COLOR.getContrastColor(40);
private final List<E> items = new ArrayList<E>();
private int selectedIndex;
private HAlignment alignment;
private FSkinFont font;
public FComboBox() {
initialize();
}
public FComboBox(E[] itemArray) {
for (E item : itemArray) {
items.add(item);
}
initialize();
}
public FComboBox(Iterable<E> items0) {
for (E item : items0) {
items.add(item);
}
initialize();
}
private void initialize() {
selectedIndex = items.isEmpty() ? -1 : 0;
font = FSkinFont.get(12);
alignment = HAlignment.LEFT;
}
public void addItem(E item) {
if (items.isEmpty()) {
selectedIndex = 0; //select item if no items previously
}
items.add(item);
}
public void removeItem(E item) {
if (items.remove(item)) {
if (selectedIndex >= items.size()) {
selectedIndex = items.size() - 1;
}
}
}
public int getItemCount() {
return items.size();
}
public E getSelectedItem() {
if (selectedIndex >= 0) {
return items.get(selectedIndex);
}
return null;
}
public void setSelectedItem(E item) {
int index = items.indexOf(item);
if (index >= 0) {
selectedIndex = index;
}
}
public HAlignment getAlignment() {
return alignment;
}
public void setAlignment(HAlignment alignment0) {
alignment = alignment0;
}
public boolean tap(float x, float y, int count) {
return true;
}
@Override
public void draw(Graphics g) {
float w = getWidth();
float h = getHeight();
g.fillRect(BACK_COLOR, 0, 0, w, h);
g.drawRect(BORDER_COLOR, 0, 0, w, h);
float shapeWidth = PREFERRED_HEIGHT / 3;
float shapeHeight = shapeWidth;
float x = w - 2 * (shapeWidth - 1);
float y = h / 2 - 1;
float insetX = 4;
g.fillTriangle(FORE_COLOR, x, y, x + shapeWidth, y, x + (shapeWidth / 2), y + (shapeHeight / 2));
E selectedItem = getSelectedItem();
if (selectedItem != null) {
g.drawText(selectedItem.toString(), font, FORE_COLOR, insetX, 0, x - 2 * insetX, h, false, alignment, true);
}
}
}

View File

@@ -58,13 +58,17 @@ public abstract class FContainer extends FDisplayObject {
}
}
public void revalidate() {
doLayout(getWidth(), getHeight());
}
protected abstract void doLayout(float width, float height);
@Override
public final void buildTouchListeners(float x, float y, ArrayList<FDisplayObject> listeners) {
if (isEnabled() && contains(x, y)) {
public final void buildTouchListeners(float screenX, float screenY, ArrayList<FDisplayObject> listeners) {
if (isEnabled() && contains(screenToLocalX(screenX), screenToLocalY(screenY))) {
for (FDisplayObject child : children) {
child.buildTouchListeners(x, y, listeners);
child.buildTouchListeners(screenX, screenY, listeners);
}
listeners.add(this);
}

View File

@@ -11,6 +11,7 @@ public abstract class FDisplayObject {
private boolean visible = true;
private boolean enabled = true;
private final Rectangle bounds = new Rectangle();
private final Vector2 screenPosition = new Vector2();
public void setPosition(float x, float y) {
bounds.setPosition(x, y);
@@ -55,6 +56,26 @@ public abstract class FDisplayObject {
return visible && bounds.contains(x, y);
}
public Vector2 getScreenPosition() {
return screenPosition;
}
public void setScreenPosition(float x, float y) { //only call from Graphics when drawn
screenPosition.set(x, y);
}
public float screenToLocalX(float x) {
return x - screenPosition.x + bounds.x;
}
public float screenToLocalY(float y) {
return y - screenPosition.y + bounds.y;
}
public float localToScreenX(float x) {
return x - bounds.x + screenPosition.x;
}
public float localToScreenY(float y) {
return y - bounds.y + screenPosition.y;
}
public boolean isEnabled() {
return enabled;
}
@@ -71,8 +92,8 @@ public abstract class FDisplayObject {
public abstract void draw(Graphics g);
public void buildTouchListeners(float x, float y, ArrayList<FDisplayObject> listeners) {
if (enabled && contains(x, y)) {
public void buildTouchListeners(float screenX, float screenY, ArrayList<FDisplayObject> listeners) {
if (enabled && contains(screenToLocalX(screenX), screenToLocalY(screenY))) {
listeners.add(this);
}
}

View File

@@ -13,7 +13,7 @@ public class FLabel extends FDisplayObject {
public static class Builder {
//========== Default values for FLabel are set here.
private float bldIconScaleFactor = 0.8f;
private int bldFontSize = 12;
private int bldFontSize = 14;
private HAlignment bldAlignment = HAlignment.LEFT;
private Vector2 bldInsets = new Vector2(0, 0);

View File

@@ -2,6 +2,8 @@ package forge.toolbox;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
@@ -12,14 +14,13 @@ import forge.assets.FSkinColor.Colors;
import forge.utils.Utils;
public class FList<E> extends FScrollPane {
public static final float PREFERRED_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.7f;
private static final float INSETS_FACTOR = 0.025f;
private static final float GROUP_HEADER_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.7f;
private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT);
private static final FSkinColor BACK_COLOR = FSkinColor.get(Colors.CLR_THEME2);
private static final FSkinColor BORDER_COLOR = FORE_COLOR.getContrastColor(40);
private static final FSkinColor PRESSED_COLOR = FSkinColor.get(Colors.CLR_THEME2).alphaColor(0.75f);
private static final FSkinColor LINE_COLOR = FORE_COLOR.alphaColor(0.5f);
private final List<ListItem> items = new ArrayList<ListItem>();
private int selectedIndex;
private final Map<String, ListGroup> groups = new TreeMap<String, ListGroup>();
private FSkinFont font;
private ListItemRenderer renderer;
@@ -28,68 +29,48 @@ public class FList<E> extends FScrollPane {
}
public FList(E[] itemArray) {
for (E item : itemArray) {
items.add(add(new ListItem(item)));
addItem(item);
}
initialize();
}
public FList(Iterable<E> items0) {
for (E item : items0) {
items.add(new ListItem(item));
addItem(item);
}
initialize();
}
private void initialize() {
selectedIndex = items.isEmpty() ? -1 : 0;
font = FSkinFont.get(12);
font = FSkinFont.get(14);
renderer = new DefaultListItemRenderer();
}
public void addItem(E item) {
if (items.isEmpty()) {
selectedIndex = 0; //select item if no items previously
}
items.add(add(new ListItem(item)));
addItem(item, "");
}
private int getIndexOfItem(E item) {
for (int i = 0; i < items.size(); i++) {
if (items.get(i).value == item) {
return i;
}
public void addItem(E item, String groupName) {
ListGroup group = groups.get(groupName);
if (group == null) {
group = add(new ListGroup(groupName));
groups.put(groupName, group);
}
return -1;
group.addItem(new ListItem(item));
}
public void removeItem(E item) {
int index = getIndexOfItem(item);
if (index >= 0) {
remove(items.get(index));
items.remove(index);
if (selectedIndex >= items.size()) {
selectedIndex = items.size() - 1;
for (ListGroup group : groups.values()) {
for (ListItem groupItem : group.items) {
if (groupItem.value == item) {
group.removeItem(groupItem);
if (group.items.isEmpty()) {
groups.remove(group.getName());
}
return;
}
}
}
}
public int getItemCount() {
return items.size();
}
public E getSelectedItem() {
if (selectedIndex >= 0) {
return items.get(selectedIndex).value;
}
return null;
}
public void setSelectedItem(E item) {
int index = getIndexOfItem(item);
if (index >= 0) {
selectedIndex = index;
}
}
public void setListItemRenderer(ListItemRenderer renderer0) {
renderer = renderer0;
}
@@ -97,50 +78,140 @@ public class FList<E> extends FScrollPane {
@Override
protected void doLayout(float width, float height) {
float y = 0;
float itemHeight = renderer.getItemHeight();
float groupHeight;
for (ListItem item : items) {
item.setBounds(0, y, width, itemHeight);
y += itemHeight;
for (ListGroup group : groups.values()) {
groupHeight = group.getPreferredHeight();
group.setBounds(0, y, width, groupHeight);
y += groupHeight;
}
}
@Override
protected void drawBackground(Graphics g) {
float w = getWidth();
float h = getHeight();
private class ListGroup extends FContainer {
private final FLabel header;
private final List<ListItem> items = new ArrayList<ListItem>();
g.fillRect(BACK_COLOR, 0, 0, w, h);
g.drawRect(BORDER_COLOR, 0, 0, w, h);
private boolean isCollapsed;
private ListGroup(String name0) {
if (name0.isEmpty()) {
header = null;
}
else {
header = new FLabel.ButtonBuilder().text(name0).command(new Runnable() {
@Override
public void run() {
isCollapsed = !isCollapsed;
FList.this.revalidate();
}
}).build();
}
}
public String getName() {
return header == null ? null : header.getText();
}
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() + 1) * 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;
}
float itemHeight = renderer.getItemHeight() + 1; //account for bottom border
for (ListItem item : items) {
item.setBounds(0, y, width, itemHeight);
y += itemHeight;
}
}
}
private class ListItem extends FDisplayObject {
private final E value;
private boolean pressed;
private ListItem(E value0) {
value = value0;
}
public boolean touchDown(float x, float y) {
pressed = true;
return true;
}
public boolean touchUp(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) {
renderer.drawValue(g, value, font, FORE_COLOR, getWidth(), getHeight());
float w = getWidth();
float h = renderer.getItemHeight();
if (pressed) {
g.fillRect(PRESSED_COLOR, 0, 0, w, h);
}
renderer.drawValue(g, value, font, FORE_COLOR, w, h);
float y = h + 1;
g.drawLine(LINE_COLOR, 0, y, w, y);
}
}
public abstract class ListItemRenderer {
public abstract float getItemHeight();
public abstract boolean tap(E value, float x, float y, int count);
public abstract void drawValue(Graphics g, E value, FSkinFont font, FSkinColor foreColor, float width, float height);
}
public class DefaultListItemRenderer extends ListItemRenderer {
@Override
public float getItemHeight() {
return 25;
return Utils.AVG_FINGER_HEIGHT;
}
@Override
public boolean tap(E value, float x, float y, int count) {
return false;
}
@Override
public void drawValue(Graphics g, E value, FSkinFont font, FSkinColor color, float width, float height) {
g.drawText(value.toString(), font, color, 0, 0, width, height, false, HAlignment.LEFT, true);
float x = width * INSETS_FACTOR;
g.drawText(value.toString(), font, color, x, 0, width - 2 * x, height, false, HAlignment.LEFT, true);
}
}
}

View File

@@ -7,7 +7,7 @@ import forge.assets.FSkinColor;
import forge.assets.FSkinColor.Colors;
public class FOverlay extends FContainer {
private static final FSkinColor BACKDROP_COLOR = FSkinColor.get(Colors.CLR_OVERLAY).alphaColor(120);
private static final FSkinColor BACKDROP_COLOR = FSkinColor.get(Colors.CLR_OVERLAY).alphaColor(0.5f);
private static final FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_BORDERS);
private static final float CORNER_RADIUS = 10;
private static final Stack<FOverlay> overlays = new Stack<FOverlay>();