Add grouping support for Deck editors

This commit is contained in:
drdev
2014-02-04 01:56:46 +00:00
parent bc851d0b51
commit 35ea4c2a50
12 changed files with 400 additions and 230 deletions

View File

@@ -25,6 +25,7 @@ import forge.gui.toolbox.FButton;
import forge.gui.toolbox.FOptionPane;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.ItemManagerContainer;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
@@ -132,7 +133,7 @@ public class FDeckViewer extends FDialog {
ItemColumn qtyColumn = new ItemColumn(ColumnDef.QUANTITY);
qtyColumn.setIndex(0);
columns.put(ColumnDef.QUANTITY, qtyColumn);
this.cardManager.setup(columns);
this.cardManager.setup(columns, GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
}
private void changeSection() {

View File

@@ -38,6 +38,7 @@ import forge.gui.framework.FScreen;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.item.PaperCard;
@@ -164,7 +165,7 @@ public final class CEditorCommander extends ACEditorBase<PaperCard, Deck> {
lstCatalogCols.remove(ColumnDef.QUANTITY);
this.getCatalogManager().setup(lstCatalogCols);
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns(), GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
SItemManagerUtil.resetUI(this);

View File

@@ -35,6 +35,7 @@ import forge.gui.framework.FScreen;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.item.PaperCard;
@@ -340,7 +341,7 @@ public final class CEditorConstructed extends ACEditorBase<PaperCard, Deck> {
lstCatalogCols.remove(ColumnDef.QUANTITY);
this.getCatalogManager().setup(lstCatalogCols);
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns(), GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
SItemManagerUtil.resetUI(this);

View File

@@ -33,6 +33,8 @@ import forge.gui.framework.FScreen;
import forge.gui.home.sanctioned.CSubmenuDraft;
import forge.gui.toolbox.FOptionPane;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.item.PaperCard;
import forge.limited.BoosterDraft;
@@ -261,7 +263,7 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
@Override
public void update() {
this.getCatalogManager().setup(SColumnUtil.getCatalogDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns(), GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
ccAddLabel = this.getBtnAdd().getText();
this.getBtnAdd().setText("Choose Card");

View File

@@ -34,6 +34,8 @@ import forge.gui.home.sanctioned.CSubmenuDraft;
import forge.gui.home.sanctioned.CSubmenuSealed;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.item.PaperCard;
import forge.util.storage.IStorage;
@@ -161,7 +163,7 @@ public final class CEditorLimited extends ACEditorBase<PaperCard, DeckGroup> {
@Override
public void update() {
this.getCatalogManager().setup(SColumnUtil.getCatalogDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns(), GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
SItemManagerUtil.resetUI(this);

View File

@@ -40,6 +40,7 @@ import forge.gui.home.quest.CSubmenuQuestDecks;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.item.PaperCard;
@@ -255,7 +256,7 @@ public final class CEditorQuest extends ACEditorBase<PaperCard, Deck> {
columnsDeck.put(ColumnDef.DECKS, new ItemColumn(ColumnDef.DECKS, this.fnDeckCompare, this.fnDeckGet));
this.getCatalogManager().setup(columnsCatalog);
this.getDeckManager().setup(columnsDeck);
this.getDeckManager().setup(columnsDeck, GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
SItemManagerUtil.resetUI(this);

View File

@@ -35,6 +35,7 @@ import forge.gui.framework.FScreen;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.SColumnUtil;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.item.PaperCard;
@@ -163,7 +164,7 @@ public final class CEditorVariant extends ACEditorBase<PaperCard, Deck> {
lstCatalogCols.remove(ColumnDef.QUANTITY);
this.getCatalogManager().setup(lstCatalogCols);
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns());
this.getDeckManager().setup(SColumnUtil.getDeckDefaultColumns(), GroupDef.CREATURE_SPELL_LAND, ColumnDef.CMC);
SItemManagerUtil.resetUI(this);

View File

@@ -1240,6 +1240,10 @@ public enum FSkin {
return SkinFont.get(Font.ITALIC, size);
}
public static void setGraphicsFont(Graphics g, SkinFont skinFont) {
g.setFont(skinFont.font);
}
public static class SkinFont {
private static Font baseFont;
private static Map<String, SkinFont> fonts = new HashMap<String, SkinFont>();

View File

@@ -58,6 +58,7 @@ import forge.gui.toolbox.LayoutHelper;
import forge.gui.toolbox.FSkin.Colors;
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
import forge.gui.toolbox.itemmanager.views.ColumnDef;
import forge.gui.toolbox.itemmanager.views.GroupDef;
import forge.gui.toolbox.itemmanager.views.ImageView;
import forge.gui.toolbox.itemmanager.views.ItemColumn;
import forge.gui.toolbox.itemmanager.views.ItemListView;
@@ -120,6 +121,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
private final List<ItemView<T>> views = new ArrayList<ItemView<T>>();
private final ItemListView<T> listView;
private final ImageView<T> imageView;
private ItemView<T> currentView;
private boolean initialized;
protected boolean lockFiltering;
@@ -135,12 +137,13 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
this.genericType = genericType0;
this.wantUnique = wantUnique0;
this.model = new ItemManagerModel<T>(genericType0);
this.listView = new ItemListView<T>(this, this.model);
this.listView.setAllowMultipleSelections(false);
this.currentView = this.listView;
this.imageView = new ImageView<T>(this, this.model);
this.views.add(this.listView);
this.views.add(new ImageView<T>(this, this.model));
this.views.add(this.imageView);
this.currentView = this.listView;
}
/**
@@ -283,7 +286,12 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
}
public void setup(final Map<ColumnDef, ItemColumn> cols) {
this.setup(cols, null, null);
}
public void setup(final Map<ColumnDef, ItemColumn> cols, GroupDef groupBy, ColumnDef pileBy) {
this.listView.setup(cols);
this.imageView.setGroupBy(groupBy);
this.imageView.setPileBy(pileBy);
}
public void setViewIndex(int index) {
@@ -291,15 +299,21 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
ItemView<T> view = this.views.get(index);
if (this.currentView == view) { return; }
final int selectedIndexBefore = this.currentView.getSelectedIndex();
final Iterable<T> selectedItemsBefore = this.currentView.getSelectedItems();
final int backupIndexToSelect = this.currentView.getSelectedIndex();
final Iterable<T> itemsToSelect; //only retain selected items if not single selection of first item
if (backupIndexToSelect > 0 || this.getSelectionCount() > 1) {
itemsToSelect = this.currentView.getSelectedItems();
}
else {
itemsToSelect = null;
}
this.currentView.getButton().setSelected(false);
this.remove(this.currentView.getScroller());
this.currentView = view;
this.currentView.getButton().setSelected(true);
this.currentView.refresh(selectedItemsBefore, selectedIndexBefore);
this.currentView.refresh(itemsToSelect, backupIndexToSelect);
this.add(currentView.getScroller());
this.revalidate();

View File

@@ -2,6 +2,7 @@ package forge.gui.toolbox.itemmanager.views;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
@@ -32,11 +33,12 @@ import forge.gui.toolbox.FSkin.SkinImage;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.ItemManagerModel;
import forge.item.InventoryItem;
import forge.view.arcane.CardArea;
import forge.view.arcane.CardPanel;
public class ImageView<T extends InventoryItem> extends ItemView<T> {
private static final int PADDING = 5;
private static final float GAP_SCALE_FACTOR = 0.04f;
private static final int GROUP_HEADER_HEIGHT = 19;
private final CardViewDisplay display;
private List<Integer> selectedIndices = new ArrayList<Integer>();
@@ -44,19 +46,40 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private boolean allowMultipleSelections;
private ColumnDef pileBy = null;
private GroupDef groupBy = null;
private Point hoverPoint;
private Point hoverScrollPos;
private ItemInfo hoveredItem;
private ArrayList<ItemInfo> orderedItems = new ArrayList<ItemInfo>();
private ArrayList<Group> groups = new ArrayList<Group>();
public ImageView(ItemManager<T> itemManager0, ItemManagerModel<T> model0) {
super(itemManager0, model0);
this.display = new CardViewDisplay();
this.display.addMouseListener(new FMouseAdapter() {
display = new CardViewDisplay();
display.addMouseListener(new FMouseAdapter() {
@Override
public void onLeftMouseDown(MouseEvent e) {
selectItem(e);
if (!selectItem(e)) {
//if didn't click on item, see if clicked on group header
if (groupBy != null) {
Point point = e.getPoint();
for (Group group : groups) {
if (group.getBounds().contains(point)) {
if (point.y < group.getTop() + GROUP_HEADER_HEIGHT) {
group.isCollapsed = !group.isCollapsed;
updateLayout();
}
break;
}
}
}
}
}
@Override
public void onLeftDoubleClick(MouseEvent e) {
itemManager.activateSelectedItems();
if (hoveredItem != null && hoveredItem.selected) {
itemManager.activateSelectedItems();
}
}
@Override
@@ -65,23 +88,23 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
itemManager.showContextMenu(e);
}
private void selectItem(MouseEvent e) {
private boolean selectItem(MouseEvent e) {
focus();
ItemInfo item = display.getItemAtPoint(e.getPoint());
if (item == null) { return; }
ItemInfo item = getItemAtPoint(e.getPoint());
if (item == null) { return false; }
if (item.selected) {
//toggle selection off item if Control down and left mouse down, otherwise do nothing
if (e.getButton() != 1) {
return;
return true;
}
if (e.isControlDown() && allowMultipleSelections) {
item.selected = false;
selectedIndices.remove(item.index);
onSelectionChange();
item.scrollIntoView();
return;
return true;
}
}
if (!allowMultipleSelections || (!e.isControlDown() && !e.isShiftDown())) {
@@ -91,11 +114,12 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
item.selected = true;
onSelectionChange();
item.scrollIntoView();
return true;
}
@Override
public void onMouseExit(MouseEvent e) {
if (display.updateHoveredItem(null, null)) {
if (updateHoveredItem(null, null)) {
display.repaint();
}
}
@@ -103,25 +127,209 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
display.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
FScrollPane scroller = ImageView.this.getScroller();
FScrollPane scroller = getScroller();
Point hoverScrollPos = new Point(scroller.getHorizontalScrollBar().getValue(), scroller.getVerticalScrollBar().getValue());
if (display.updateHoveredItem(e.getPoint(), hoverScrollPos)) {
if (updateHoveredItem(e.getPoint(), hoverScrollPos)) {
display.repaint();
}
}
});
}
@Override
protected void onResize() {
if (this.pileBy == null) {
display.refresh(); //need to refresh to adjust wrapping of items
public GroupDef getGroupBy() {
return groupBy;
}
public void setGroupBy(GroupDef groupBy0) {
groupBy = groupBy0;
}
public ColumnDef getPileBy() {
return pileBy;
}
public void setPileBy(ColumnDef pileBy0) {
pileBy = pileBy0;
if (pileBy == null) {
getScroller().setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
}
else {
getScroller().setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
}
@Override
protected void onResize() {
updateLayout(); //need to update layout to adjust wrapping of items
}
@Override
protected void onRefresh() {
display.refresh();
groups.clear();
Group otherItems;
if (groupBy == null) { //use single group with all items if not grouping
otherItems = new Group("");
groups.add(otherItems);
}
else {
otherItems = null;
for (String groupName : groupBy.getGroups()) {
groups.add(new Group(groupName));
}
}
for (Entry<T, Integer> itemEntry : model.getOrderedList()) {
T item = itemEntry.getKey();
int qty = itemEntry.getValue();
int groupIndex = groupBy == null ? -1 : groupBy.getItemGroupIndex(item);
for (int i = 0; i < qty; i++) {
if (groupIndex >= 0) {
groups.get(groupIndex).add(new ItemInfo(item));
}
else {
if (otherItems == null) {
otherItems = new Group("Other");
groups.add(otherItems);
}
otherItems.add(new ItemInfo(item));
}
}
}
updateLayout();
}
private void updateLayout() {
orderedItems.clear();
int x, groupY;
int y = PADDING;
int groupX = PADDING;
int itemAreaWidth = getVisibleSize().width;
int groupWidth = itemAreaWidth - 2 * groupX;
int pileX = groupBy == null ? groupX : 2 * groupX + 1;
int pileWidth = itemAreaWidth - 2 * pileX;
int itemIndex = 0;
int itemWidth = 50 * imageScaleFactor;
int gap = Math.round(itemWidth * GAP_SCALE_FACTOR);
int dx = itemWidth + gap;
int itemsPerRow = (pileWidth + gap) / dx;
if (itemsPerRow == 0) {
itemsPerRow = 1;
itemWidth = pileWidth;
}
int itemHeight = Math.round(itemWidth * CardPanel.ASPECT_RATIO);
int dy = itemHeight + gap;
for (Group group : groups) {
group.piles.clear();
groupY = y;
if (groupBy != null) {
y += GROUP_HEADER_HEIGHT + PADDING; //leave room for group header
if (group.isCollapsed || group.items.isEmpty()) {
group.setBounds(groupX, groupY, groupWidth, GROUP_HEADER_HEIGHT);
continue;
}
}
else if (group.items.isEmpty()) {
group.setBounds(groupX, groupY, groupWidth, 0);
continue;
}
Pile pile = new Pile(); //use a pile for each row
x = pileX;
for (ItemInfo itemInfo : group.items) {
itemInfo.index = itemIndex++;
orderedItems.add(itemInfo);
if (pile.items.size() == itemsPerRow) {
pile = new Pile();
x = pileX;
y += dy;
}
itemInfo.setBounds(x, y, itemWidth, itemHeight);
if (pile.items.size() == 0) {
pile.setBounds(pileX, y, pileWidth, itemHeight);
group.piles.add(pile);
}
pile.items.add(itemInfo);
x += dx;
}
y += itemHeight;
if (groupBy != null) {
y += PADDING + 1; //leave room for group footer
}
group.setBounds(groupX, groupY, groupWidth, y - groupY);
y += PADDING;
}
display.setPreferredSize(new Dimension(itemAreaWidth, y));
display.revalidate();
display.repaint();
}
private ItemInfo getItemAtPoint(Point p) {
for (int i = groups.size() - 1; i >= 0; i--) {
Group group = groups.get(i);
if (!group.isCollapsed && group.getBounds().contains(p)) {
for (int j = group.piles.size() - 1; j >= 0; j--) {
Pile pile = group.piles.get(j);
if (pile.getBounds().contains(p)) {
for (int k = pile.items.size() - 1; k >= 0; k--) {
ItemInfo item = pile.items.get(k);
if (item.getBounds().contains(p)) {
return item;
}
}
}
}
}
}
return null;
}
private Dimension getVisibleSize() {
FScrollPane scroller = getScroller();
Dimension size = getScroller().getSize();
Insets insets = getScroller().getInsets();
size = new Dimension(size.width - insets.left - insets.right,
size.height - insets.top - insets.bottom);
if (scroller.getVerticalScrollBarPolicy() != ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER) {
size.width -= scroller.getVerticalScrollBar().getPreferredSize().width;
}
if (scroller.getHorizontalScrollBarPolicy() != ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) {
size.height -= scroller.getHorizontalScrollBar().getPreferredSize().height;
}
return size;
}
private boolean updateHoveredItem(Point hoverPoint0, Point hoverScrollPos0) {
hoverPoint = hoverPoint0;
hoverScrollPos = hoverScrollPos0;
ItemInfo item = null;
FScrollPane scroller = getScroller();
if (hoverPoint0 != null) {
Point displayPoint = new Point(hoverPoint0);
//account for change in scroll positions since mouse last moved
displayPoint.x += scroller.getHorizontalScrollBar().getValue() - hoverScrollPos0.x;
displayPoint.y += scroller.getVerticalScrollBar().getValue() - hoverScrollPos0.y;
item = getItemAtPoint(displayPoint);
}
if (hoveredItem == item) { return false; }
hoveredItem = item;
if (item != null) {
CDetail.SINGLETON_INSTANCE.showCard(item.item);
CPicture.SINGLETON_INSTANCE.showImage(item.item);
}
return true;
}
@Override
@@ -131,13 +339,13 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
@Override
public void setAllowMultipleSelections(boolean allowMultipleSelections0) {
this.allowMultipleSelections = allowMultipleSelections0;
allowMultipleSelections = allowMultipleSelections0;
}
@Override
public T getItemAtIndex(int index) {
if (index >= 0 && index < getCount()) {
return display.items.get(index).item;
return orderedItems.get(index).item;
}
return null;
}
@@ -145,12 +353,11 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
@Override
public int getIndexOfItem(T item) {
for (int i = getCount() - 1; i >= 0; i--) {
ItemInfo itemInfo = display.items.get(i);
if (itemInfo.item == item) {
return itemInfo.index;
if (orderedItems.get(i).item == item) {
return i;
}
}
return 0;
return -1;
}
@Override
@@ -165,7 +372,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
@Override
public int getCount() {
return display.items.size();
return orderedItems.size();
}
@Override
@@ -175,7 +382,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
@Override
public int getIndexAtPoint(Point p) {
ItemInfo item = display.getItemAtPoint(p);
ItemInfo item = getItemAtPoint(p);
if (item != null) {
return item.index;
}
@@ -198,7 +405,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
@Override
public void selectAll() {
clearSelection();
for (Integer i = 0; i < display.items.size(); i++) {
for (Integer i = 0; i < getCount(); i++) {
selectedIndices.add(i);
}
updateSelection();
@@ -224,7 +431,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
int count = getCount();
for (Integer i : selectedIndices) {
if (i < count) {
display.items.get(i).selected = false;
orderedItems.get(i).selected = false;
}
}
selectedIndices.clear();
@@ -232,7 +439,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private void updateSelection() {
for (Integer i : selectedIndices) {
display.items.get(i).selected = true;
orderedItems.get(i).selected = true;
}
onSelectionChange();
}
@@ -247,7 +454,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
protected void onScrollSelectionIntoView(JViewport viewport) {
if (selectedIndices.isEmpty()) { return; }
ItemInfo itemInfo = display.items.get(selectedIndices.get(0));
ItemInfo itemInfo = orderedItems.get(selectedIndices.get(0));
itemInfo.scrollIntoView();
}
@@ -255,234 +462,165 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private final Rectangle bounds = new Rectangle();
public Rectangle getBounds() {
return this.bounds;
return bounds;
}
public void setBounds(int x, int y, int width, int height) {
this.bounds.x = x;
this.bounds.y = y;
this.bounds.width = width;
this.bounds.height = height;
bounds.x = x;
bounds.y = y;
bounds.width = width;
bounds.height = height;
}
public int getLeft() {
return bounds.x;
}
public int getTop() {
return bounds.y;
}
public int getRight() {
return bounds.x + bounds.width;
}
public int getBottom() {
return bounds.y + bounds.height;
}
public void scrollIntoView() {
int x = this.bounds.x - CardArea.GUTTER_X;
int y = this.bounds.y - CardArea.GUTTER_Y;
int width = this.bounds.width + 2 * CardArea.GUTTER_Y;
int height = this.bounds.height + 2 * CardArea.GUTTER_Y;
int x = bounds.x - PADDING;
int y = bounds.y - PADDING;
int width = bounds.width + 2 * PADDING;
int height = bounds.height + 2 * PADDING;
display.scrollRectToVisible(new Rectangle(x, y, width, height));
}
}
private class Group extends DisplayArea {
private final List<ItemInfo> items = new ArrayList<ItemInfo>();
private final List<Pile> piles = new ArrayList<Pile>();
private final String name;
private boolean isCollapsed;
public Group(String name0) {
name = name0;
}
public void add(ItemInfo item) {
items.add(item);
}
@Override
public String toString() {
return name;
}
}
private class Pile extends DisplayArea {
private final List<ItemInfo> items = new ArrayList<ItemInfo>();
}
private class ItemInfo extends DisplayArea {
private final T item;
private Integer index;
private int index;
private boolean selected;
private ItemInfo(T item0, int index0) {
this.item = item0;
this.index = index0;
private ItemInfo(T item0) {
item = item0;
}
@Override
public String toString() {
return this.item.toString();
return item.toString();
}
}
@SuppressWarnings("serial")
private class CardViewDisplay extends JPanel {
private Point hoverPoint;
private Point hoverScrollPos;
private ItemInfo hoveredItem;
private List<ItemInfo> items = new ArrayList<ItemInfo>();
private List<Group> sections = new ArrayList<Group>();
private CardViewDisplay() {
this.setOpaque(false);
this.setFocusable(true);
}
private void refresh() {
int index = 0;
this.items.clear();
for (Entry<T, Integer> itemEntry : model.getOrderedList()) {
for (int i = 0; i < itemEntry.getValue(); i++) {
this.items.add(new ItemInfo(itemEntry.getKey(), index++));
}
}
this.refreshSections();
}
private void refreshSections() {
this.sections.clear();
if (!this.items.isEmpty()) {
if (ImageView.this.pileBy == null) {
buildSpreadsheet();
}
else {
buildPiles();
}
}
this.revalidate();
this.repaint();
}
private ItemInfo getItemAtPoint(Point p) {
for (int i = this.sections.size() - 1; i >= 0; i--) {
Group group = this.sections.get(i);
if (!group.isCollapsed && group.getBounds().contains(p)) {
for (int j = group.piles.size() - 1; j >= 0; j--) {
Pile pile = group.piles.get(j);
if (pile.getBounds().contains(p)) {
for (int k = pile.items.size() - 1; k >= 0; k--) {
ItemInfo item = pile.items.get(k);
if (item.getBounds().contains(p)) {
return item;
}
}
}
}
}
}
return null;
}
private Dimension getVisibleSize() {
FScrollPane scroller = ImageView.this.getScroller();
Dimension size = ImageView.this.getScroller().getSize();
Insets insets = ImageView.this.getScroller().getInsets();
size = new Dimension(size.width - insets.left - insets.right,
size.height - insets.top - insets.bottom);
if (scroller.getVerticalScrollBarPolicy() != ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER) {
size.width -= scroller.getVerticalScrollBar().getWidth();
}
if (scroller.getHorizontalScrollBarPolicy() != ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) {
size.height -= scroller.getHorizontalScrollBar().getHeight();
}
return size;
}
private void buildSpreadsheet() {
ImageView.this.getScroller().setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
Group group = new Group();
final int itemAreaWidth = getVisibleSize().width;
int itemWidth = 50 * imageScaleFactor;
int gap = Math.round(itemWidth * GAP_SCALE_FACTOR);
int dx = itemWidth + gap;
int itemsPerRow = (itemAreaWidth - 2 * CardArea.GUTTER_X + gap) / dx;
if (itemsPerRow == 0) {
itemsPerRow = 1;
itemWidth = itemAreaWidth - 2 * CardArea.GUTTER_X;
}
int itemHeight = Math.round(itemWidth * CardPanel.ASPECT_RATIO);
int dy = itemHeight + gap;
Pile pile = new Pile(); //use a pile for each row
int x = CardArea.GUTTER_X;
int y = CardArea.GUTTER_Y;
for (ItemInfo itemInfo : this.items) {
if (pile.items.size() == itemsPerRow) {
pile = new Pile();
x = CardArea.GUTTER_X;
y += dy;
}
itemInfo.setBounds(x, y, itemWidth, itemHeight);
if (pile.items.size() == 0) {
pile.setBounds(0, y, itemAreaWidth, dy);
group.piles.add(pile);
}
pile.items.add(itemInfo);
x += dx;
}
group.setBounds(0, 0, itemAreaWidth, y + itemHeight + CardArea.GUTTER_Y);
this.setPreferredSize(group.getBounds().getSize());
this.sections.add(group);
}
private void buildPiles() {
}
private boolean updateHoveredItem(Point hoverPoint0, Point hoverScrollPos0) {
this.hoverPoint = hoverPoint0;
this.hoverScrollPos = hoverScrollPos0;
ItemInfo item = null;
FScrollPane scroller = ImageView.this.getScroller();
if (hoverPoint0 != null) {
Point displayPoint = new Point(hoverPoint0);
//account for change in scroll positions since mouse last moved
displayPoint.x += scroller.getHorizontalScrollBar().getValue() - hoverScrollPos0.x;
displayPoint.y += scroller.getVerticalScrollBar().getValue() - hoverScrollPos0.y;
item = this.getItemAtPoint(displayPoint);
}
if (this.hoveredItem == item) { return false; }
this.hoveredItem = item;
if (item != null) {
CDetail.SINGLETON_INSTANCE.showCard(item.item);
CPicture.SINGLETON_INSTANCE.showImage(item.item);
}
return true;
setOpaque(false);
setFocusable(true);
}
@Override
public final void paintComponent(final Graphics g) {
if (this.items.isEmpty()) { return; }
updateHoveredItem(this.hoverPoint, this.hoverScrollPos); //ensure hovered item up to date
updateHoveredItem(hoverPoint, hoverScrollPos); //ensure hovered item up to date
final Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int sectionIdx = 0, pileIdx = 0;
final int scrollTop = ImageView.this.getScroller().getVerticalScrollBar().getValue();
final int scrollBottom = scrollTop + getVisibleSize().height;
if (ImageView.this.pileBy == null) {
pileIdx = scrollTop / this.sections.get(0).piles.get(0).getBounds().height;
}
else {
}
for (; sectionIdx < this.sections.size(); sectionIdx++, pileIdx = 0) {
Group group = this.sections.get(sectionIdx);
if (group.getBounds().y >= scrollBottom) {
final Dimension visibleSize = getVisibleSize();
final int visibleTop = getScroller().getVerticalScrollBar().getValue();
final int visibleBottom = visibleTop + visibleSize.height;
final int visibleLeft = getScroller().getHorizontalScrollBar().getValue();
final int visibleRight = visibleLeft + visibleSize.width;
FSkin.setGraphicsFont(g2d, ItemListView.ROW_FONT);
FontMetrics fm = g2d.getFontMetrics();
int fontOffsetY = (GROUP_HEADER_HEIGHT - fm.getHeight()) / 2 + fm.getAscent();
for (Group group : groups) {
if (group.getBottom() < visibleTop) {
continue;
}
if (group.getTop() >= visibleBottom) {
break;
}
if (this.sections.size() > 1) {
//TODO: Draw group name/border
if (group.isCollapsed) {
if (groupBy != null) {
Rectangle bounds = group.getBounds();
FSkin.setGraphicsColor(g2d, ItemListView.HEADER_BACK_COLOR);
g2d.fillRect(bounds.x, bounds.y, bounds.width, GROUP_HEADER_HEIGHT - 1);
FSkin.setGraphicsColor(g2d, ItemListView.FORE_COLOR);
g2d.drawString(group.name + " (" + group.items.size() + ")", bounds.x + PADDING, bounds.y + fontOffsetY);
if (!group.items.isEmpty()) { //draw expand/collapse glyph as long as group isn't empty
int offset = GROUP_HEADER_HEIGHT / 4;
int x1 = bounds.x + bounds.width - PADDING;
int x2 = x1 - offset;
int x3 = x2 - offset;
int y2 = bounds.y + GROUP_HEADER_HEIGHT / 2;
if (!group.isCollapsed) {
offset *= -1;
y2++;
}
int y1 = y2 - offset;
g2d.drawLine(x1, y1, x2, y2);
g2d.drawLine(x2, y2, x3, y1);
if (group.isCollapsed) {
offset++;
}
else {
offset--;
}
y1 += offset;
y2 += offset;
g2d.drawLine(x1, y1, x2, y2);
g2d.drawLine(x2, y2, x3, y1);
}
FSkin.setGraphicsColor(g2d, ItemListView.GRID_COLOR);
g2d.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
if (group.isCollapsed || group.items.isEmpty()) {
continue;
}
int y = bounds.y + GROUP_HEADER_HEIGHT - 1; //draw bottom border of header
g2d.drawLine(bounds.x, y, bounds.x + bounds.width - 1, y);
}
for (; pileIdx < group.piles.size(); pileIdx++) {
Pile pile = group.piles.get(pileIdx);
if (pile.getBounds().y >= scrollBottom) {
else if (group.items.isEmpty()) {
continue;
}
for (Pile pile : group.piles) {
if (pile.getBottom() < visibleTop || pile.getRight() < visibleLeft) {
continue;
}
if (pile.getTop() >= visibleBottom || pile.getLeft() >= visibleRight) {
break;
}
for (ItemInfo itemInfo : pile.items) {
if (itemInfo != this.hoveredItem) { //save hovered item for last
if (itemInfo.getBottom() < visibleTop || itemInfo.getRight() < visibleLeft) {
continue;
}
if (itemInfo.getTop() >= visibleBottom || itemInfo.getLeft() >= visibleRight) {
break;
}
if (itemInfo != hoveredItem) { //save hovered item for last
drawItemImage(g2d, itemInfo);
}
}
}
}
if (this.hoveredItem != null) { //draw hovered item on top
drawItemImage(g2d, this.hoveredItem);
if (hoveredItem != null) { //draw hovered item on top
drawItemImage(g2d, hoveredItem);
}
}
@@ -499,7 +637,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
bounds.width + 2 * selBorderSize, bounds.height + 2 * selBorderSize,
cornerSize + selBorderSize, cornerSize + selBorderSize);
}
else if (itemInfo == this.hoveredItem) {
else if (itemInfo == hoveredItem) {
int hoverBorderSize = Math.max(1, selBorderSize / 2);
g.setColor(Color.green);
g.fillRoundRect(bounds.x - hoverBorderSize, bounds.y - hoverBorderSize,
@@ -517,7 +655,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
else {
g.setColor(Color.white);
Shape clip = g.getClip();
g.setClip(bounds.x, bounds.y, bounds.width, bounds.height);
g.setClip(bounds);
g.drawString(itemInfo.item.getName(), bounds.x + 10, bounds.y + 20);
g.setClip(clip);
}

View File

@@ -78,14 +78,14 @@ import forge.item.InventoryItem;
@SuppressWarnings("serial")
public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
static final SkinColor BACK_COLOR = FSkin.getColor(FSkin.Colors.CLR_ZEBRA);
private static final SkinColor FORE_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
static final SkinColor FORE_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
private static final SkinColor SEL_ACTIVE_COLOR = FSkin.getColor(FSkin.Colors.CLR_ACTIVE);
private static final SkinColor SEL_INACTIVE_COLOR = FSkin.getColor(FSkin.Colors.CLR_INACTIVE);
private static final SkinColor HEADER_BACK_COLOR = BACK_COLOR.getContrastColor(-10);
static final SkinColor HEADER_BACK_COLOR = BACK_COLOR.getContrastColor(-10);
static final SkinColor ALT_ROW_COLOR = BACK_COLOR.getContrastColor(-20);
private static final SkinColor GRID_COLOR = BACK_COLOR.getContrastColor(20);
static final SkinColor GRID_COLOR = BACK_COLOR.getContrastColor(20);
private static final SkinBorder HEADER_BORDER = new FSkin.CompoundSkinBorder(new FSkin.MatteSkinBorder(0, 0, 1, 1, GRID_COLOR), new EmptyBorder(0, 1, 0, 0));
private static final SkinFont ROW_FONT = FSkin.getFont(12);
static final SkinFont ROW_FONT = FSkin.getFont(12);
private static final int ROW_HEIGHT = 19;
private final ItemTable table = new ItemTable();
@@ -104,6 +104,7 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
public ItemListView(ItemManager<T> itemManager0, ItemManagerModel<T> model0) {
super(itemManager0, model0);
this.tableModel = new ItemTableModel(model0);
this.setAllowMultipleSelections(false);
// use different selection highlight colors for focused vs. unfocused tables
this.table.addMouseListener(new FMouseAdapter() {

View File

@@ -33,6 +33,7 @@ import org.apache.commons.lang3.StringUtils;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FScrollPane;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FSkin.SkinColor;
import forge.gui.toolbox.FSkin.SkinImage;
import forge.gui.toolbox.ToolTipListener;
import forge.gui.toolbox.itemmanager.ItemManager;
@@ -40,6 +41,8 @@ import forge.gui.toolbox.itemmanager.ItemManagerModel;
import forge.item.InventoryItem;
public abstract class ItemView<T extends InventoryItem> {
private static final SkinColor BORDER_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
protected final ItemManager<T> itemManager;
protected final ItemManagerModel<T> model;
private final FScrollPane scroller;
@@ -51,7 +54,7 @@ public abstract class ItemView<T extends InventoryItem> {
this.itemManager = itemManager0;
this.model = model0;
this.scroller = new FScrollPane(false);
this.scroller.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_TEXT)));
this.scroller.setBorder(new FSkin.LineSkinBorder(BORDER_COLOR));
this.button = new FLabel.Builder().hoverable().selectable(true)
.icon(getIcon()).iconScaleAuto(false)
.tooltip(getCaption()).build();
@@ -114,7 +117,8 @@ public abstract class ItemView<T extends InventoryItem> {
protected abstract void onRefresh();
private void fixSelection(final Iterable<T> itemsToSelect, final int backupIndexToSelect) {
if (itemsToSelect == null) {
setSelectedIndex(0); //select first item if no items to select
setSelectedIndex(0, false); //select first item if no items to select
getScroller().getVerticalScrollBar().setValue(0); //ensure scrolled to top
}
else {
if (!setSelectedItems(itemsToSelect)) {