diff --git a/.gitattributes b/.gitattributes index 2c941be1ffb..a807929da24 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15688,6 +15688,7 @@ forge-gui/src/main/java/forge/gui/toolbox/itemmanager/package-info.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ColorSetRenderer.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ColumnDef.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/DeckQuantityRenderer.java -text +forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ImageView.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/IntegerRenderer.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemCellRenderer.java -text forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemColumn.java -text diff --git a/forge-gui/res/skins/default/sprite_icons.png b/forge-gui/res/skins/default/sprite_icons.png index 2d838bf79b0..a40227e5f10 100644 Binary files a/forge-gui/res/skins/default/sprite_icons.png and b/forge-gui/res/skins/default/sprite_icons.png differ diff --git a/forge-gui/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java b/forge-gui/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java index 7487ba364ac..ff55f707c92 100644 --- a/forge-gui/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java +++ b/forge-gui/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java @@ -71,6 +71,9 @@ public class CEditorDraftingProcess extends ACEditorBase { catalogManager.setAlwaysNonUnique(true); deckManager.setAlwaysNonUnique(true); + catalogManager.setViewIndex(1); + deckManager.setViewIndex(1); + this.setCatalogManager(catalogManager); this.setDeckManager(deckManager); } @@ -154,7 +157,7 @@ public class CEditorDraftingProcess extends ACEditorBase { deck.getOrCreate(DeckSection.Sideboard).addAll(this.getDeckManager().getPool()); final String landSet = IBoosterDraft.LAND_SET_CODE[0].getCode(); - + final int landsCount = 10; for(String landName : MagicColor.Constant.BASIC_LANDS) { final int numArt = Singletons.getMagicDb().getCommonCards().getArtCount(landName, landSet); diff --git a/forge-gui/src/main/java/forge/gui/framework/FScreen.java b/forge-gui/src/main/java/forge/gui/framework/FScreen.java index 7f291e41f94..7fb64e677bf 100644 --- a/forge-gui/src/main/java/forge/gui/framework/FScreen.java +++ b/forge-gui/src/main/java/forge/gui/framework/FScreen.java @@ -124,7 +124,7 @@ public enum FScreen { VDeckEditorUI.SINGLETON_INSTANCE, CDeckEditorUI.SINGLETON_INSTANCE, "Draft", - FSkin.getImage(FSkin.ZoneImages.ICO_HAND), + FSkin.getImage(FSkin.ZoneImages.IMG_HAND), true, "Leave Draft", NewConstants.EDITOR_LAYOUT_FILE), diff --git a/forge-gui/src/main/java/forge/gui/toolbox/FLabel.java b/forge-gui/src/main/java/forge/gui/toolbox/FLabel.java index e48887b012a..4fe98b64d35 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/FLabel.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/FLabel.java @@ -439,7 +439,7 @@ public class FLabel extends SkinnedLabel implements ILocalRepaint { if (this.getIcon() != null) { width += this.getIcon().getIconWidth() + this.getIconTextGap(); } - if (opaque) { + if (opaque || selectable) { width += 6; //account for border/padding if opaque } return width; diff --git a/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java b/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java index 7d48c37c4a1..365868164d3 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/FSkin.java @@ -861,12 +861,12 @@ public enum FSkin { /** int[] can hold [xcoord, ycoord, width, height, newwidth, newheight]. */ public enum ZoneImages implements SkinProp { - ICO_HAND (new int[] {280, 40, 40, 40}), - ICO_LIBRARY (new int[] {280, 0, 40, 40}), - ICO_EXILE (new int[] {320, 40, 40, 40}), - ICO_FLASHBACK (new int[] {280, 80, 40, 40}), - ICO_GRAVEYARD (new int[] {320, 0, 40, 40}), - ICO_POISON (new int[] {320, 80, 40, 40}); + IMG_HAND (new int[] {280, 40, 40, 40}), + IMG_LIBRARY (new int[] {280, 0, 40, 40}), + IMG_EXILE (new int[] {320, 40, 40, 40}), + IMG_FLASHBACK (new int[] {280, 80, 40, 40}), + IMG_GRAVEYARD (new int[] {320, 0, 40, 40}), + IMG_POISON (new int[] {320, 80, 40, 40}); private int[] coords; /** @param xy   int[] coordinates */ @@ -1085,6 +1085,8 @@ public enum FSkin { ICO_SAVE (new int[] {660, 560, 20, 20}), ICO_SAVEAS (new int[] {660, 580, 20, 20}), ICO_CLOSE (new int[] {640, 640, 20, 20}), + ICO_LIST (new int[] {640, 660, 20, 20}), + ICO_CARD_IMAGE (new int[] {660, 660, 20, 20}), ICO_UNKNOWN (new int[] {0, 720, 80, 80}), ICO_LOGO (new int[] {480, 0, 200, 200}), ICO_FLIPCARD (new int[] {400, 0, 80, 120}), diff --git a/forge-gui/src/main/java/forge/gui/toolbox/LayoutHelper.java b/forge-gui/src/main/java/forge/gui/toolbox/LayoutHelper.java index df9e74a5099..e7ccf873430 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/LayoutHelper.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/LayoutHelper.java @@ -8,11 +8,16 @@ import javax.swing.JComponent; */ public final class LayoutHelper { private final int parentWidth, parentHeight; - private int x, y, lineBottom; + private int x, y, lineBottom, gapX, gapY; public LayoutHelper(JComponent parent) { + this(parent, 3, 3); + } + public LayoutHelper(JComponent parent, int gapX0, int gapY0) { parentWidth = parent.getWidth(); parentHeight = parent.getHeight(); + gapX = gapX0; + gapY = gapY0; } /** @@ -96,7 +101,7 @@ public final class LayoutHelper { if (y >= parentHeight) { return; } } comp.setBounds(x, y, width, height); - x += width + 3; + x += width + gapX; if (y + height > lineBottom) { lineBottom = y + height; } @@ -118,7 +123,7 @@ public final class LayoutHelper { public void newLine() { if (lineBottom == y) { return; } x = 0; - y = lineBottom + 3; + y = lineBottom + gapY; lineBottom = y; } @@ -127,7 +132,7 @@ public final class LayoutHelper { */ public void newLine(int dy) { x = 0; - y = lineBottom + 3 + dy; + y = lineBottom + gapY + dy; lineBottom = y; } @@ -158,4 +163,18 @@ public final class LayoutHelper { public int getY() { return y; } + + /** + * @return gap X + */ + public int getGapX() { + return gapX; + } + + /** + * @return gap Y + */ + public int getGapY() { + return gapY; + } } diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/CardManager.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/CardManager.java index dcf7d519af1..95c31feb330 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/CardManager.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/CardManager.java @@ -3,6 +3,7 @@ package forge.gui.toolbox.itemmanager; import java.util.List; import javax.swing.JMenu; + import forge.Singletons; import forge.game.GameFormat; import forge.gui.GuiUtils; diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java index b6acb94452b..02839aabef1 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java @@ -49,7 +49,6 @@ import com.google.common.collect.Iterables; import forge.Command; import forge.gui.GuiUtils; import forge.gui.toolbox.ContextMenuBuilder; -import forge.gui.toolbox.FComboBoxWrapper; import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinnedCheckBox; @@ -59,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.ImageView; import forge.gui.toolbox.itemmanager.views.ItemColumn; import forge.gui.toolbox.itemmanager.views.ItemListView; import forge.gui.toolbox.itemmanager.views.ItemView; @@ -118,9 +118,9 @@ public abstract class ItemManager extends JPanel { .fontSize(12) .build(); - private final FComboBoxWrapper> cbViews = new FComboBoxWrapper>(); + private final List> views = new ArrayList>(); + private final ItemListView listView; private ItemView currentView; - private final ItemListView table; private boolean initialized; protected boolean lockFiltering; @@ -135,23 +135,12 @@ public abstract class ItemManager extends JPanel { this.genericType = genericType0; this.wantUnique = wantUnique0; this.model = new ItemManagerModel(genericType0); - this.table = new ItemListView(this, this.model); - this.table.setAllowMultipleSelections(false); - this.currentView = this.table; + this.listView = new ItemListView(this, this.model); + this.listView.setAllowMultipleSelections(false); + this.currentView = this.listView; - this.cbViews.addItem(this.table); - this.cbViews.addItemListener(new ItemListener() { - @SuppressWarnings("unchecked") - @Override - public void itemStateChanged(ItemEvent e) { - ItemView view = (ItemView) e.getItem(); - if (currentView == view) { return; } - ItemManager.this.remove(currentView.getScroller()); - currentView = view; - ItemManager.this.add(currentView.getScroller()); - ItemManager.this.revalidate(); - } - }); + this.views.add(this.listView); + this.views.add(new ImageView(this, this.model)); } /** @@ -160,8 +149,10 @@ public abstract class ItemManager extends JPanel { public void initialize() { if (this.initialized) { return; } //avoid initializing more than once - //build table view - this.table.initialize(); + //initialize views + for (int i = 0; i < this.views.size(); i++) { + this.views.get(i).initialize(i); + } //build enable filters checkbox ItemFilter.layoutCheckbox(this.chkEnableFilters); @@ -196,7 +187,10 @@ public abstract class ItemManager extends JPanel { this.add(this.btnFilters); this.add(this.lblCaption); this.add(this.lblRatio); - this.cbViews.addTo(this); + for (ItemView view : this.views) { + this.add(view.getButton()); + view.getButton().setSelected(view == this.currentView); + } this.add(this.currentView.getScroller()); final Runnable cmdAddCurrentSearch = new Runnable() { @@ -289,7 +283,28 @@ public abstract class ItemManager extends JPanel { } public void setup(final Map cols) { - this.table.setup(cols); + this.listView.setup(cols); + } + + public void setViewIndex(int index) { + if (index < 0 || index >= this.views.size()) { return; } + ItemView view = this.views.get(index); + if (this.currentView == view) { return; } + + final int selectedIndexBefore = this.currentView.getSelectedIndex(); + final Iterable selectedItemsBefore = this.currentView.getSelectedItems(); + + this.currentView.getButton().setSelected(false); + this.remove(this.currentView.getScroller()); + + this.currentView = view; + this.currentView.getButton().setSelected(true); + this.currentView.refresh(selectedItemsBefore, selectedIndexBefore); + + this.add(currentView.getScroller()); + this.revalidate(); + this.repaint(); + this.focus(); } @Override @@ -333,8 +348,8 @@ public abstract class ItemManager extends JPanel { helper.include(this.btnFilters, 61, FTextField.HEIGHT); int captionWidth = this.lblCaption.getAutoSizeWidth(); int ratioWidth = this.lblRatio.getAutoSizeWidth(); - int cbViewsWidth = this.cbViews.getAutoSizeWidth(); - int availableCaptionWidth = helper.getParentWidth() - cbViewsWidth - ratioWidth - helper.getX() - 9; + int viewButtonWidth = FTextField.HEIGHT; + int availableCaptionWidth = helper.getParentWidth() - viewButtonWidth * this.views.size() - ratioWidth - helper.getX() - (this.views.size() + 2) * helper.getGapX(); if (captionWidth > availableCaptionWidth) { //truncate caption if not enough room for it this.lblCaption.setToolTipText(this.lblCaption.getText()); captionWidth = availableCaptionWidth; @@ -343,8 +358,11 @@ public abstract class ItemManager extends JPanel { this.lblCaption.setToolTipText(null); } helper.include(this.lblCaption, captionWidth, FTextField.HEIGHT); - helper.fillLine(this.lblRatio, FTextField.HEIGHT, cbViewsWidth); //leave room for cbViews - helper.fillLine(this.cbViews.getComponent(), FTextField.HEIGHT); + helper.fillLine(this.lblRatio, FTextField.HEIGHT, (viewButtonWidth + helper.getGapX()) * this.views.size() - 1); //leave room for view buttons + for (ItemView view : this.views) { + helper.include(view.getButton(), viewButtonWidth, FTextField.HEIGHT); + helper.offset(-1, 0); + } helper.fill(this.currentView.getScroller()); } diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ImageView.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ImageView.java new file mode 100644 index 00000000000..449bf059079 --- /dev/null +++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ImageView.java @@ -0,0 +1,481 @@ +package forge.gui.toolbox.itemmanager.views; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map.Entry; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JViewport; +import javax.swing.ScrollPaneConstants; + +import forge.ImageCache; +import forge.gui.deckeditor.DeckProxy; +import forge.gui.toolbox.FMouseAdapter; +import forge.gui.toolbox.FScrollPane; +import forge.gui.toolbox.FSkin; +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 extends ItemView { + private static final float GAP_SCALE_FACTOR = 0.04f; + + public enum LayoutType { + Spreadsheet, + Piles + } + + private final CardViewDisplay display; + private final ItemManagerModel model; + private List selectedIndices = new ArrayList(); + private int imageScaleFactor = 3; + private boolean allowMultipleSelections; + private LayoutType layoutType = LayoutType.Spreadsheet; + + public ImageView(ItemManager itemManager0, ItemManagerModel model0) { + super(itemManager0); + this.display = new CardViewDisplay(); + this.model = model0; + this.display.addMouseListener(new FMouseAdapter() { + @Override + public void onLeftMouseDown(MouseEvent e) { + selectItem(e); + } + + @Override + public void onLeftDoubleClick(MouseEvent e) { + getItemManager().activateSelectedItems(); + } + + @Override + public void onRightClick(MouseEvent e) { + selectItem(e); + getItemManager().showContextMenu(e); + } + + private void selectItem(MouseEvent e) { + focus(); + + ItemInfo item = display.getItemAtPoint(e.getPoint()); + if (item == null) { return; } + + if (item.selected) { + //toggle selection off item if Control down and left mouse down, otherwise do nothing + if (e.getButton() != 1) { + return; + } + if (e.isControlDown() && allowMultipleSelections) { + item.selected = false; + selectedIndices.remove(item.index); + onSelectionChange(); + item.scrollIntoView(); + return; + } + } + if (!allowMultipleSelections || (!e.isControlDown() && !e.isShiftDown())) { + clearSelection(); + } + selectedIndices.add(0, item.index); + item.selected = true; + onSelectionChange(); + item.scrollIntoView(); + } + }); + } + + @Override + protected void onResize() { + if (this.layoutType == LayoutType.Spreadsheet) { + display.refresh(); //need to refresh to adjust wrapping of items + } + } + + @Override + protected void onRefresh() { + display.refresh(); + } + + @Override + public JComponent getComponent() { + return display; + } + + @Override + public void setAllowMultipleSelections(boolean allowMultipleSelections0) { + this.allowMultipleSelections = allowMultipleSelections0; + } + + @Override + public T getItemAtIndex(int index) { + if (index >= 0 && index < getCount()) { + return display.items.get(index).item; + } + return null; + } + + @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; + } + } + return 0; + } + + @Override + public int getSelectedIndex() { + return selectedIndices.isEmpty() ? -1 : selectedIndices.get(0); + } + + @Override + public Iterable getSelectedIndices() { + return selectedIndices; + } + + @Override + public int getCount() { + return display.items.size(); + } + + @Override + public int getSelectionCount() { + return selectedIndices.size(); + } + + @Override + public int getIndexAtPoint(Point p) { + ItemInfo item = display.getItemAtPoint(p); + if (item != null) { + return item.index; + } + return -1; + } + + @Override + protected SkinImage getIcon() { + if (getItemManager().getGenericType().equals(DeckProxy.class)) { + return FSkin.getImage(FSkin.EditorImages.IMG_PACK).resize(18, 18); + } + return FSkin.getIcon(FSkin.InterfaceIcons.ICO_CARD_IMAGE); + } + + @Override + protected String getCaption() { + return "Image View"; + } + + @Override + public void selectAll() { + clearSelection(); + for (Integer i = 0; i < display.items.size(); i++) { + selectedIndices.add(i); + } + updateSelection(); + } + + @Override + protected void onSetSelectedIndex(int index) { + clearSelection(); + selectedIndices.add(index); + updateSelection(); + } + + @Override + protected void onSetSelectedIndices(Iterable indices) { + clearSelection(); + for (Integer index : indices) { + selectedIndices.add(index); + } + updateSelection(); + } + + private void clearSelection() { + int count = getCount(); + for (Integer i : selectedIndices) { + if (i < count) { + display.items.get(i).selected = false; + } + } + selectedIndices.clear(); + } + + private void updateSelection() { + for (Integer i : selectedIndices) { + display.items.get(i).selected = true; + } + onSelectionChange(); + } + + @Override + protected void onSelectionChange() { + super.onSelectionChange(); + display.repaint(); + } + + @Override + protected void onScrollSelectionIntoView(JViewport viewport) { + if (selectedIndices.isEmpty()) { return; } + + ItemInfo itemInfo = display.items.get(selectedIndices.get(0)); + itemInfo.scrollIntoView(); + } + + private class DisplayArea { + private final Rectangle bounds = new Rectangle(); + + public Rectangle getBounds() { + return this.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; + } + 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; + display.scrollRectToVisible(new Rectangle(x, y, width, height)); + } + } + private class Section extends DisplayArea { + private final List piles = new ArrayList(); + private boolean isCollapsed; + } + private class Pile extends DisplayArea { + private final List items = new ArrayList(); + } + private class ItemInfo extends DisplayArea { + private final T item; + private Integer index; + private boolean selected; + + private ItemInfo(T item0) { + this.item = item0; + } + + @Override + public String toString() { + return this.item.toString(); + } + } + + @SuppressWarnings("serial") + private class CardViewDisplay extends JPanel { + private List items = new ArrayList(); + private List
sections = new ArrayList
(); + + private CardViewDisplay() { + this.setOpaque(false); + this.setFocusable(true); + } + + private void refresh() { + this.items.clear(); + for (Entry itemEntry : model.getItems()) { + for (int i = 0; i < itemEntry.getValue(); i++) { + this.items.add(new ItemInfo(itemEntry.getKey())); + } + } + Collections.sort(this.items, new Comparator() { + @Override + public int compare(ItemInfo arg0, ItemInfo arg1) { + return arg0.item.getName().compareTo(arg1.item.getName()); + } + }); + for (int i = 0; i < this.items.size(); i++) { + this.items.get(i).index = i; + } + this.refreshSections(); + } + + private void refreshSections() { + this.sections.clear(); + + if (!this.items.isEmpty()) { + switch (ImageView.this.layoutType) { + case Spreadsheet: + buildSpreadsheet(); + break; + case Piles: + buildPiles(); + break; + } + } + + this.revalidate(); + this.repaint(); + } + + private ItemInfo getItemAtPoint(Point p) { + for (int i = this.sections.size() - 1; i >= 0; i--) { + Section section = this.sections.get(i); + if (!section.isCollapsed && section.getBounds().contains(p)) { + for (int j = section.piles.size() - 1; j >= 0; j--) { + Pile pile = section.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); + + Section section = new Section(); + + 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); + section.piles.add(pile); + } + pile.items.add(itemInfo); + x += dx; + } + + section.setBounds(0, 0, itemAreaWidth, y + itemHeight + CardArea.GUTTER_Y); + this.setPreferredSize(section.getBounds().getSize()); + + this.sections.add(section); + } + + private void buildPiles() { + + } + + @Override + public final void paintComponent(final Graphics g) { + if (this.items.isEmpty()) { return; } + + final Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + final int itemWidth = this.items.get(0).getBounds().width; + final int selBorderSize = Math.max(1, Math.round(itemWidth * GAP_SCALE_FACTOR / 2) - 1); + final int borderSize = Math.round(itemWidth * CardPanel.BLACK_BORDER_SIZE); + final int cornerSize = Math.max(4, Math.round(itemWidth * CardPanel.ROUNDED_CORNER_SIZE)); + + int sectionIdx = 0, pileIdx = 0; + final int scrollTop = ImageView.this.getScroller().getVerticalScrollBar().getValue(); + final int scrollBottom = scrollTop + getVisibleSize().height; + switch (ImageView.this.layoutType) { + case Spreadsheet: + pileIdx = scrollTop / this.sections.get(0).piles.get(0).getBounds().height; + break; + case Piles: + break; + } + for (; sectionIdx < this.sections.size(); sectionIdx++, pileIdx = 0) { + Section section = this.sections.get(sectionIdx); + if (section.getBounds().y >= scrollBottom) { + break; + } + if (this.sections.size() > 1) { + //TODO: Draw section name/border + if (section.isCollapsed) { + continue; + } + } + for (; pileIdx < section.piles.size(); pileIdx++) { + Pile pile = section.piles.get(pileIdx); + if (pile.getBounds().y >= scrollBottom) { + break; + } + for (ItemInfo itemInfo : pile.items) { + Rectangle bounds = itemInfo.getBounds(); + + if (itemInfo.selected) { + g2d.setColor(Color.green); + g2d.fillRoundRect(bounds.x - selBorderSize, bounds.y - selBorderSize, + bounds.width + 2 * selBorderSize, bounds.height + 2 * selBorderSize, + cornerSize + selBorderSize, cornerSize + selBorderSize); + } + + g2d.setColor(Color.black); + g2d.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, cornerSize, cornerSize); + + BufferedImage img = ImageCache.getImage(itemInfo.item, bounds.width - 2 * borderSize, bounds.height - 2 * borderSize); + if (img != null) { + g2d.drawImage(img, null, bounds.x + borderSize, bounds.y + borderSize); + } + else { + g2d.setColor(Color.white); + Shape clip = g2d.getClip(); + g2d.setClip(bounds.x, bounds.y, bounds.width, bounds.height); + g2d.drawString(itemInfo.item.getName(), bounds.x + 10, bounds.y + 20); + g2d.setClip(clip); + } + } + } + } + } + } +} diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemListView.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemListView.java index cc2465beb25..d11b2d5ded8 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemListView.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemListView.java @@ -60,6 +60,7 @@ import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinBorder; import forge.gui.toolbox.FSkin.SkinColor; import forge.gui.toolbox.FSkin.SkinFont; +import forge.gui.toolbox.FSkin.SkinImage; import forge.gui.toolbox.FSkin.SkinnedTable; import forge.gui.toolbox.FSkin.SkinnedTableHeader; import forge.gui.toolbox.itemmanager.ItemManager; @@ -174,6 +175,11 @@ public final class ItemListView extends ItemView { return this.table.getTableHeader().getLocationOnScreen(); //use table header's location since that stays in place } + @Override + protected SkinImage getIcon() { + return FSkin.getIcon(FSkin.InterfaceIcons.ICO_LIST); + } + @Override protected String getCaption() { return "List View"; @@ -262,6 +268,10 @@ public final class ItemListView extends ItemView { return this.table.rowAtPoint(p); } + @Override + protected void onResize() { + } + @Override protected void onRefresh() { this.tableModel.refreshSort(); @@ -496,27 +506,17 @@ public final class ItemListView extends ItemView { return -1; } - public void onSelectionChange() { - final int row = getSelectedIndex(); - if (row != -1) { - ListSelectionEvent event = new ListSelectionEvent(getItemManager(), row, row, false); - for (ListSelectionListener listener : getItemManager().getSelectionListeners()) { - listener.valueChanged(event); - } - } - } - private final ListSelectionListener listSelectionListener = new ListSelectionListener() { @Override public void valueChanged(final ListSelectionEvent arg0) { - ItemTableModel.this.onSelectionChange(); + ItemListView.this.onSelectionChange(); } }; private final FocusAdapter focusAdapter = new FocusAdapter() { @Override public void focusGained(final FocusEvent e) { - ItemTableModel.this.onSelectionChange(); + ItemListView.this.onSelectionChange(); } }; diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemView.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemView.java index 3515f9afba9..1e0742a7175 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemView.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/views/ItemView.java @@ -24,6 +24,8 @@ import javax.swing.PopupFactory; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; @@ -31,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.SkinImage; import forge.gui.toolbox.ToolTipListener; import forge.gui.toolbox.itemmanager.ItemManager; import forge.item.InventoryItem; @@ -38,6 +41,7 @@ import forge.item.InventoryItem; public abstract class ItemView { private final ItemManager itemManager; private final FScrollPane scroller; + private final FLabel button; private int heightBackup; private boolean isIncrementalSearchActive = false; @@ -45,11 +49,14 @@ public abstract class ItemView { this.itemManager = itemManager0; this.scroller = new FScrollPane(false); this.scroller.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_TEXT))); + this.button = new FLabel.Builder().hoverable().selectable(true) + .icon(getIcon()).iconScaleAuto(false) + .tooltip(getCaption()).build(); } - public void initialize() { + public void initialize(final int index) { final JComponent comp = this.getComponent(); - + //hook incremental search functionality final IncrementalSearch incrementalSearch = new IncrementalSearch(); comp.addFocusListener(new FocusAdapter() { @@ -60,11 +67,19 @@ public abstract class ItemView { }); comp.addKeyListener(incrementalSearch); + this.button.setCommand(new Runnable() { + @Override + public void run() { + itemManager.setViewIndex(index); + } + }); + this.scroller.setViewportView(comp); this.scroller.getVerticalScrollBar().addAdjustmentListener(new ToolTipListener()); this.scroller.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { + onResize(); //scroll selection into view whenever view height changes int height = e.getComponent().getHeight(); if (height != heightBackup) { @@ -79,6 +94,10 @@ public abstract class ItemView { return this.itemManager; } + public FLabel getButton() { + return this.button; + } + public FScrollPane getScroller() { return this.scroller; } @@ -91,6 +110,7 @@ public abstract class ItemView { onRefresh(); fixSelection(itemsToSelect, backupIndexToSelect); } + protected abstract void onResize(); protected abstract void onRefresh(); private void fixSelection(final Iterable itemsToSelect, final int backupIndexToSelect) { if (itemsToSelect == null) { @@ -115,7 +135,7 @@ public abstract class ItemView { } return items; } - + public final boolean setSelectedItem(T item) { return setSelectedItem(item, true); } @@ -199,6 +219,16 @@ public abstract class ItemView { } } + protected void onSelectionChange() { + final int index = getSelectedIndex(); + if (index != -1) { + ListSelectionEvent event = new ListSelectionEvent(getItemManager(), index, index, false); + for (ListSelectionListener listener : itemManager.getSelectionListeners()) { + listener.valueChanged(event); + } + } + } + public void scrollSelectionIntoView() { Container parent = getComponent().getParent(); if (parent instanceof JViewport) { @@ -233,6 +263,7 @@ public abstract class ItemView { public abstract int getCount(); public abstract int getSelectionCount(); public abstract int getIndexAtPoint(Point p); + protected abstract SkinImage getIcon(); protected abstract String getCaption(); protected abstract void onSetSelectedIndex(int index); protected abstract void onSetSelectedIndices(Iterable indices); diff --git a/forge-gui/src/main/java/forge/gui/toolbox/special/PlayerDetailsPanel.java b/forge-gui/src/main/java/forge/gui/toolbox/special/PlayerDetailsPanel.java index e2cd79e2aa6..74a6d1d74dc 100644 --- a/forge-gui/src/main/java/forge/gui/toolbox/special/PlayerDetailsPanel.java +++ b/forge-gui/src/main/java/forge/gui/toolbox/special/PlayerDetailsPanel.java @@ -38,12 +38,12 @@ public class PlayerDetailsPanel extends JPanel { private Player player; // Info labels - private FLabel lblHand = getBuiltFLabel(FSkin.ZoneImages.ICO_HAND, "99", "Cards in hand"); - private FLabel lblGraveyard = getBuiltFLabel(FSkin.ZoneImages.ICO_GRAVEYARD, "99", "Cards in graveyard"); - private FLabel lblLibrary = getBuiltFLabel(FSkin.ZoneImages.ICO_LIBRARY, "99", "Cards in library"); - private FLabel lblExile = getBuiltFLabel(FSkin.ZoneImages.ICO_EXILE, "99", "Exiled cards"); - private FLabel lblFlashback = getBuiltFLabel(FSkin.ZoneImages.ICO_FLASHBACK, "99", "Flashback cards"); - private FLabel lblPoison = getBuiltFLabel(FSkin.ZoneImages.ICO_POISON, "99", "Poison counters"); + private FLabel lblHand = getBuiltFLabel(FSkin.ZoneImages.IMG_HAND, "99", "Cards in hand"); + private FLabel lblGraveyard = getBuiltFLabel(FSkin.ZoneImages.IMG_GRAVEYARD, "99", "Cards in graveyard"); + private FLabel lblLibrary = getBuiltFLabel(FSkin.ZoneImages.IMG_LIBRARY, "99", "Cards in library"); + private FLabel lblExile = getBuiltFLabel(FSkin.ZoneImages.IMG_EXILE, "99", "Exiled cards"); + private FLabel lblFlashback = getBuiltFLabel(FSkin.ZoneImages.IMG_FLASHBACK, "99", "Flashback cards"); + private FLabel lblPoison = getBuiltFLabel(FSkin.ZoneImages.IMG_POISON, "99", "Poison counters"); private final List> manaLabels = new ArrayList>(); private FLabel getBuiltFLabel(SkinProp p0, String s0, String s1) { diff --git a/forge-gui/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui/src/main/java/forge/view/arcane/CardPanel.java index 4535fb2f013..8c718b51fe8 100644 --- a/forge-gui/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui/src/main/java/forge/view/arcane/CardPanel.java @@ -76,11 +76,11 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl private static CardPanel dragAnimationPanel; /** Constant ROUNDED_CORNER_SIZE=0.1f. */ - private static final float ROUNDED_CORNER_SIZE = 0.1f; + public static final float ROUNDED_CORNER_SIZE = 0.1f; /** Constant SELECTED_BORDER_SIZE=0.01f. */ - private static final float SELECTED_BORDER_SIZE = 0.01f; + public static final float SELECTED_BORDER_SIZE = 0.01f; /** Constant BLACK_BORDER_SIZE=0.03f. */ - private static final float BLACK_BORDER_SIZE = 0.03f; + public static final float BLACK_BORDER_SIZE = 0.03f; /** * Constant