From 616aea619d2cd82d3916e69597d814731c7f6e77 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Fri, 15 Jul 2011 17:27:22 +0400 Subject: [PATCH] New ability picker (though not turned on yet) --- Mage.Client/pom.xml | 5 + .../src/main/java/mage/client/MageFrame.java | 12 +- .../components/ability/AbilityPicker.java | 296 ++++++++++++++++++ .../components/ability/BackgroundPainter.java | 60 ++++ .../components/ability/MageScrollButton.java | 75 +++++ .../components/ability/MageScrollbarUI.java | 165 ++++++++++ .../java/mage/client/game/AbilityPicker.java | 19 +- .../main/java/mage/client/game/GamePane.java | 2 + .../mage/client/util/SettingsManager.java | 68 ++++ .../src/main/resources/buttons/down.png | Bin 0 -> 3098 bytes .../src/main/resources/buttons/left.png | Bin 0 -> 3093 bytes .../src/main/resources/buttons/right.png | Bin 0 -> 3100 bytes Mage.Client/src/main/resources/buttons/up.png | Bin 0 -> 3081 bytes Mage.Client/src/main/resources/game/right.png | Bin 0 -> 1377 bytes .../src/main/resources/game/right_hovered.png | Bin 0 -> 1379 bytes 15 files changed, 685 insertions(+), 17 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java create mode 100644 Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java create mode 100644 Mage.Client/src/main/java/mage/client/components/ability/MageScrollButton.java create mode 100644 Mage.Client/src/main/java/mage/client/components/ability/MageScrollbarUI.java create mode 100644 Mage.Client/src/main/java/mage/client/util/SettingsManager.java create mode 100644 Mage.Client/src/main/resources/buttons/down.png create mode 100644 Mage.Client/src/main/resources/buttons/left.png create mode 100644 Mage.Client/src/main/resources/buttons/right.png create mode 100644 Mage.Client/src/main/resources/buttons/up.png create mode 100644 Mage.Client/src/main/resources/game/right.png create mode 100644 Mage.Client/src/main/resources/game/right_hovered.png diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index fdcb8d17360..1d66bf123db 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -102,6 +102,11 @@ beansbinding 1.2.1 + + org.swinglabs + swing-layout + 1.0.3 + diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 45447490b8c..58f4cc17179 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -47,6 +47,7 @@ import mage.client.deckeditor.collection.viewer.CollectionViewerPane; import mage.client.dialog.*; import mage.client.plugins.impl.Plugins; import mage.client.util.EDTExceptionHandler; +import mage.client.util.SettingsManager; import mage.client.util.gui.ArrowBuilder; import mage.components.ImagePanel; @@ -173,6 +174,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { initComponents(); setSize(1024, 768); + SettingsManager.getInstance().setScreenWidthAndHeight(1024, 768); this.setExtendedState(JFrame.MAXIMIZED_BOTH); session = new Session(this); @@ -199,11 +201,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { addMageLabel(); setAppIcon(); - //PlayerPanelNew n = new PlayerPanelNew(); - //n.setBounds(100,100,100,300); - //n.setVisible(true); - //backgroundPane.add(n); - desktopPane.add(ArrowBuilder.getArrowsPanel(), JLayeredPane.DRAG_LAYER); desktopPane.addComponentListener(new ComponentAdapter() { @@ -211,12 +208,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public void componentResized(ComponentEvent e) { int width = ((JComponent) e.getSource()).getWidth(); int height = ((JComponent) e.getSource()).getHeight(); - if (!liteMode) + SettingsManager.getInstance().setScreenWidthAndHeight(width, height); + if (!liteMode) { backgroundPane.setSize(width, height); + } JPanel arrowsPanel = ArrowBuilder.getArrowsPanelRef(); if (arrowsPanel != null) arrowsPanel.setSize(width, height); if (title != null) { - //title.setBorder(BorderFactory.createLineBorder(Color.red)); title.setBounds((int) (width - titleRectangle.getWidth()) / 2, (int) (height - titleRectangle.getHeight()) / 2, titleRectangle.width, titleRectangle.height); } } diff --git a/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java new file mode 100644 index 00000000000..5166c3088f8 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java @@ -0,0 +1,296 @@ +package mage.client.components.ability; + +import com.sun.deploy.util.ArrayUtil; +import mage.client.MageFrame; +import mage.client.util.ImageHelper; +import mage.client.util.SettingsManager; +import mage.client.util.gui.GuiDisplayUtil; +import mage.remote.Session; +import mage.view.AbilityPickerView; +import org.jdesktop.layout.GroupLayout; +import org.jdesktop.layout.LayoutStyle; +import org.jdesktop.swingx.JXPanel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Dialog for choosing abilities. + * + * @author nantuko + */ +public class AbilityPicker extends JXPanel implements MouseWheelListener { + + private static final String DEFAULT_MESSAGE = "Choose spell or ability to play (double-click)";; + private static final int DIALOG_WIDTH = 320; + private static final int DIALOG_HEIGHT = 240; + + private JList rows; + private List choices; + private String message = DEFAULT_MESSAGE; + + private Session session; + private UUID gameId; + + private BackgroundPainter mwPanelPainter; + private JScrollPane jScrollPane2; + private JTextField title; + + private Image rightImage; + private Image rightImageHovered; + + private static final String IMAGE_RIGHT_PATH = "/game/right.png"; + private static final String IMAGE_RIGHT_HOVERED_PATH = "/game/right_hovered.png"; + + private static Color SELECTED_COLOR = new Color(64,147,208); + private static Color BORDER_COLOR = new Color(0,0,0,50); + + public AbilityPicker() { + initComponents(); + addMouseWheelListener(this); + setSize(320, 240); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + jScrollPane2.setOpaque(false); + jScrollPane2.getViewport().setOpaque(false); + //jScrollPane2.getHorizontalScrollBar().setUI(new MageScrollbarUI()); + //jScrollPane2.getVerticalScrollBar().setUI(new MageScrollbarUI()); + } + }); + } + + public AbilityPicker(List choices, String message) { + this.choices = choices; + if (message!= null) { + this.message = message + " (double-click)"; + } + initComponents(); + jScrollPane2.setOpaque(false); + jScrollPane2.getViewport().setOpaque(false); + jScrollPane2.getHorizontalScrollBar().setUI(new MageScrollbarUI()); + jScrollPane2.getVerticalScrollBar().setUI(new MageScrollbarUI()); + + addMouseWheelListener(this); + } + + public void init(Session session, UUID gameId) { + this.session = session; + this.gameId = gameId; + } + + public void show(AbilityPickerView choices, Point p) { + if (p == null) return; + this.choices = new ArrayList(); + + for (Map.Entry choice: choices.getChoices().entrySet()) { + this.choices.add(new AbilityPickerAction(choice.getKey(), choice.getValue())); + } + this.choices.add(new AbilityPickerAction(null, "Cancel")); + + Point centered = SettingsManager.getInstance().getComponentPosition(320, 240); + this.setLocation(centered.x, centered.y); + GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + } + + public void initComponents() { + JLabel jLabel1; + JLabel jLabel3; + + Color textColor = Color.white; + + mwPanelPainter = new BackgroundPainter(); + jLabel1 = new JLabel(); + jLabel3 = new JLabel(); + + title = new JTextField(); + jScrollPane2 = new JScrollPane(); + + setBackground(textColor); + setBackgroundPainter(mwPanelPainter); + jLabel1.setFont(new Font("Times New Roman", 1, 18)); + jLabel1.setForeground(textColor); + jLabel1.setText(message); + + jLabel3.setForeground(textColor); + jLabel3.setHorizontalAlignment(SwingConstants.TRAILING); + jLabel3.setText("Selected:"); + + title.setFont(new Font("Tahoma", 1, 11)); + title.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); + + jScrollPane2.setBorder(null); + jScrollPane2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jScrollPane2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + + rightImage = ImageHelper.loadImage(IMAGE_RIGHT_PATH); + rightImageHovered = ImageHelper.loadImage(IMAGE_RIGHT_HOVERED_PATH); + + //BufferedImage[] images = new BufferedImage[choices.size()]; + //rows = new JList(images); + rows = new JList(); + rows.setModel ( + new AbstractListModel() { + public int getSize() { + if (AbilityPicker.this.choices == null) { + return 0; + } + return AbilityPicker.this.choices.size(); + } + public Object getElementAt(int i) { return AbilityPicker.this.choices.get(i); } + } + ); + + rows.setBackground(textColor); + rows.setCellRenderer(new ImageRenderer()); + rows.ensureIndexIsVisible(rows.getModel().getSize()); + rows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + rows.setLayoutOrientation(JList.VERTICAL); + rows.setMaximumSize(new Dimension(32767, 32767)); + rows.setMinimumSize(new Dimension(67, 16)); + rows.setOpaque(false); + rows.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1 && evt.getClickCount() > 1) { + objectMouseClicked(evt); + } + } + }); + rows.setSelectedIndex(0); + rows.setFont(new Font("Times New Roman", 1, 17)); + + rows.addMouseWheelListener(this); + + jScrollPane2.setViewportView(rows); + + GroupLayout layout = new GroupLayout(this); + this.setLayout(layout); + + layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( + GroupLayout.TRAILING, + layout.createSequentialGroup().addContainerGap().add( + layout.createParallelGroup(GroupLayout.TRAILING).add(GroupLayout.LEADING, jScrollPane2, GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE).add(GroupLayout.LEADING, + layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( + GroupLayout.LEADING, + layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) + ) + .addPreferredGap(LayoutStyle.RELATED) + .add( + layout.createParallelGroup(GroupLayout.TRAILING) + .add( + GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); + + layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( + layout.createSequentialGroup().add( + layout.createParallelGroup(GroupLayout.LEADING).add( + layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) + .add(5, 5, 5) + .add( + layout.createParallelGroup(GroupLayout.BASELINE) + ) + ).add(layout.createSequentialGroup().add(8, 8, 8))) + .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( + layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( + LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + int notches = e.getWheelRotation(); + int index = rows.getSelectedIndex(); + + if (notches < 0) { + if (index > 0) { + rows.setSelectedIndex(index-1); + rows.repaint(); + } + } else { + if (index < choices.size() - 1) { + rows.setSelectedIndex(index+1); + rows.repaint(); + } + } + } + + private void objectMouseClicked(MouseEvent event) { + AbilityPickerAction action = (AbilityPickerAction)choices.get(rows.getSelectedIndex()); + action.actionPerformed(null); + } + + class ImageRenderer extends DefaultListCellRenderer { + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + JLabel label = ((JLabel) c); + label.setOpaque(false); + label.setForeground(Color.white); + + if (choices.size() <= index) return label; + + Object object = choices.get(index); + String name = object.toString(); + label.setText(name); + + if (isSelected) { + label.setIcon(new ImageIcon(rightImageHovered)); + label.setForeground(SELECTED_COLOR); + label.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); + } else { + label.setIcon(new ImageIcon(rightImage)); + } + + return label; + } + + private static final long serialVersionUID = 7689696087189956997L; + } + + public static void main(String[] argv) { + JFrame jframe = new JFrame("Test"); + + List objectList = new ArrayList(); + objectList.add("T: add {R} to your mana pool"); + objectList.add("T: add {B} to your mana pool"); + objectList.add("Cancel"); + AbilityPicker panel = new AbilityPicker(objectList, "Choose ability"); + jframe.add(panel); + jframe.setSize(640, 480); + jframe.setVisible(true); + } + + public class AbilityPickerAction extends AbstractAction { + + private UUID id; + + public AbilityPickerAction(UUID id, String choice) { + this.id = id; + putValue(Action.NAME, choice); + } + + @Override + public void actionPerformed(ActionEvent e) { + // cancel + if (id == null) { + session.sendPlayerBoolean(gameId, false); + } else { + session.sendPlayerUUID(gameId, id); + } + setVisible(false); + } + + @Override + public String toString() { + return (String)getValue(Action.NAME); + } + + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java b/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java new file mode 100644 index 00000000000..c91d5ab87da --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java @@ -0,0 +1,60 @@ +package mage.client.components.ability; + +import org.jdesktop.swingx.painter.AbstractPainter; +import sun.swing.CachedPainter; + +import javax.swing.*; +import java.awt.*; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; + +/** + * Background painter. + * + * @author nantuko + */ +public class BackgroundPainter extends AbstractPainter { + + private Color bgColor = Color.black; + + float bgalpha = 0.8f; + + public BackgroundPainter() { + super(); + setAntialiasing(true); + } + + @Override + protected void doPaint(Graphics2D g2, Object o, int i, int i1) { + float alpha = bgalpha; + Component c = (Component)o; + Composite composite = g2.getComposite(); + if (composite instanceof AlphaComposite) { + alpha *= ((AlphaComposite) composite).getAlpha(); + } + + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); + g2.setColor(bgColor); + + RoundRectangle2D rect = new RoundRectangle2D.Double(0, 0, c.getWidth() - 1, c.getHeight() - 1, 24, 24); + g2.fill(rect); + + Ellipse2D ellipse = new Ellipse2D.Double(-c.getWidth(), + c.getHeight() / 3.0, c.getWidth() * 3.0, + c.getHeight() * 2.0); + + Area area = new Area(new Rectangle(0, 0, c.getWidth(), c.getHeight())); + area.subtract(new Area(ellipse)); + area.intersect(new Area(rect)); + + alpha = 0.1f; + if (composite instanceof AlphaComposite) { + alpha *= ((AlphaComposite) composite).getAlpha(); + } + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); + g2.setColor(new Color(1.0f, 1.0f, 1.0f)); + g2.fill(area); + g2.setComposite(composite); + } +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/components/ability/MageScrollButton.java b/Mage.Client/src/main/java/mage/client/components/ability/MageScrollButton.java new file mode 100644 index 00000000000..c64c643ab01 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ability/MageScrollButton.java @@ -0,0 +1,75 @@ +package mage.client.components.ability; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.io.File; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.plaf.basic.BasicArrowButton; +import javax.swing.plaf.metal.MetalScrollButton; + + +/** + * Buttons for scroll bar. + * + * @author nantuko + */ +public class MageScrollButton extends MetalScrollButton { + + private static Icon buttonLeft; + private static Icon buttonRight; + private static ImageIcon buttonUp; + private static ImageIcon buttonDown; + + private int width; + + static { + buttonLeft = new ImageIcon(MageScrollButton.class.getResource("/buttons/left.png")); + buttonRight = new ImageIcon(MageScrollButton.class.getResource("/buttons/right.png")); + buttonUp = new ImageIcon(MageScrollButton.class.getResource("/buttons/up.png")); + buttonDown = new ImageIcon(MageScrollButton.class.getResource("/buttons/down.png")); + } + + public MageScrollButton(int direction, int width, boolean freeStanding) { + super(direction, width, freeStanding); + setOpaque(false); + this.width = width; + buttonUp.setImage(buttonUp.getImage().getScaledInstance(width, width, Image.SCALE_SMOOTH)); + buttonDown.setImage(buttonDown.getImage().getScaledInstance(width, width, Image.SCALE_SMOOTH)); + } + + @Override + public Dimension getMaximumSize() { + return this.getPreferredSize(); + } + + @Override + public Dimension getMinimumSize() { + return this.getPreferredSize(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(width, width); + } + + @Override + public void paint(Graphics g) { + switch (getDirection()) { + case BasicArrowButton.WEST: + buttonLeft.paintIcon(null, g, 0, 0); + break; + case BasicArrowButton.EAST: + buttonRight.paintIcon(null, g, 0, 0); + break; + case BasicArrowButton.NORTH: + buttonUp.paintIcon(null, g, 0, 0); + break; + case BasicArrowButton.SOUTH: + buttonDown.paintIcon(null, g, 0, 0); + break; + } + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/ability/MageScrollbarUI.java b/Mage.Client/src/main/java/mage/client/components/ability/MageScrollbarUI.java new file mode 100644 index 00000000000..658017a1720 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ability/MageScrollbarUI.java @@ -0,0 +1,165 @@ +package mage.client.components.ability; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.plaf.metal.MetalScrollBarUI; + +/** + * Custom scroll bar. + * + * @author nantuko + */ +public class MageScrollbarUI extends MetalScrollBarUI { + + private static int ANTI_WIDTH = -3; + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setOpaque(false); + } + + @Override + protected JButton createDecreaseButton(int orientation) { + decreaseButton = new MageScrollButton(orientation, scrollBarWidth + ANTI_WIDTH, isFreeStanding); + return decreaseButton; + } + + @Override + protected JButton createIncreaseButton(int orientation) { + increaseButton = new MageScrollButton(orientation, scrollBarWidth + ANTI_WIDTH, isFreeStanding); + return increaseButton; + } + + @Override + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + if (scrollbar.getOrientation() == JScrollBar.VERTICAL) { + int width = trackBounds.width - 4 + ANTI_WIDTH; + int height = trackBounds.height; + + g2.translate(trackBounds.x + 2, trackBounds.y); + + Rectangle2D casing = new Rectangle2D.Double(0, 0, width, height); + g2.setColor(Color.BLACK); + + float alpha = 0.5f; + Composite composite = g2.getComposite(); + if (composite instanceof AlphaComposite) { + alpha *= ((AlphaComposite) composite).getAlpha(); + } + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); + g2.fill(casing); + g2.setComposite(composite); + + g2.drawLine(-1, 0, -1, height); + g2.drawLine(-2, 0, -2, height); + + g2.drawLine(width, 0, width, height); + g2.drawLine(width + 1, 0, width + 1, height); + + RoundRectangle2D roundCasing = new RoundRectangle2D.Double(0, 2, width, height - 4, width, width); + Area area = new Area(casing); + area.subtract(new Area(roundCasing)); + g2.fill(area); + + g2.translate(-trackBounds.x - 2, -trackBounds.y); + } else { + int width = trackBounds.width; + int height = trackBounds.height - 4; + + g2.translate(trackBounds.x, trackBounds.y + 2); + + Rectangle2D casing = new Rectangle2D.Double(0, 0, width, height); + g2.setColor(Color.BLACK); + + float alpha = 0.5f; + Composite composite = g2.getComposite(); + if (composite instanceof AlphaComposite) { + alpha *= ((AlphaComposite) composite).getAlpha(); + } + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); + g2.fill(casing); + g2.setComposite(composite); + + g2.drawLine(0, -1, width, -1); + g2.drawLine(0, -2, width, -2); + + g2.drawLine(0, height, width, height); + g2.drawLine(0, height + 1, width, height + 1); + + RoundRectangle2D roundCasing = new RoundRectangle2D.Double(2, 0, width - 4, height, height, height); + Area area = new Area(casing); + area.subtract(new Area(roundCasing)); + g2.fill(area); + + g2.translate(-trackBounds.x, -trackBounds.y - 2); + } + + } + + @Override + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + if (scrollbar.getOrientation() == JScrollBar.VERTICAL) { + g2.translate(thumbBounds.x + 1, thumbBounds.y + 2); + + int width = thumbBounds.width - 3 + ANTI_WIDTH; + int height = thumbBounds.height - 4; + + RoundRectangle2D casing = new RoundRectangle2D.Double(0, 0, width, height, width, width); + g2.setColor(Color.BLACK); + Paint paint = g2.getPaint(); + g2.setPaint(new GradientPaint(0, 0, new Color(0x818a9b), 0, height, new Color(0x3a4252))); + g2.fill(casing); + g2.setPaint(paint); + + Stroke stroke = g2.getStroke(); + g2.setStroke(new BasicStroke(2.0f)); + g2.draw(casing); + g2.setStroke(stroke); + + g2.translate(-thumbBounds.x - 1, -thumbBounds.y - 2); + } else { + g2.translate(thumbBounds.x + 2, thumbBounds.y + 1); + + int width = thumbBounds.width - 4; + int height = thumbBounds.height - 3; + + RoundRectangle2D casing = new RoundRectangle2D.Double(0, 0, width, height, height, height); + g2.setColor(Color.BLACK); + + Paint paint = g2.getPaint(); + g2.setPaint(new GradientPaint(0, 0, new Color(0x818a9b), 0, height, new Color(0x3a4252))); + g2.fill(casing); + g2.setPaint(paint); + + Stroke stroke = g2.getStroke(); + g2.setStroke(new BasicStroke(2.0f)); + g2.draw(casing); + g2.setStroke(stroke); + + g2.translate(-thumbBounds.x - 2, -thumbBounds.y - 1); + } + } +} diff --git a/Mage.Client/src/main/java/mage/client/game/AbilityPicker.java b/Mage.Client/src/main/java/mage/client/game/AbilityPicker.java index b521cb0c92d..890e9b8bc90 100644 --- a/Mage.Client/src/main/java/mage/client/game/AbilityPicker.java +++ b/Mage.Client/src/main/java/mage/client/game/AbilityPicker.java @@ -28,19 +28,18 @@ package mage.client.game; -import java.awt.Point; +import mage.client.MageFrame; +import mage.client.util.gui.GuiDisplayUtil; +import mage.remote.Session; +import mage.view.AbilityPickerView; + +import javax.swing.*; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; import java.awt.event.ActionEvent; import java.util.Map.Entry; import java.util.UUID; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JPopupMenu; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; -import mage.client.MageFrame; -import mage.remote.Session; -import mage.client.util.gui.GuiDisplayUtil; -import mage.view.AbilityPickerView; /** * diff --git a/Mage.Client/src/main/java/mage/client/game/GamePane.java b/Mage.Client/src/main/java/mage/client/game/GamePane.java index 37c4344a9be..a6b8b6d3bd4 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePane.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePane.java @@ -35,6 +35,8 @@ package mage.client.game; import mage.client.*; + +import javax.swing.*; import java.util.UUID; /** diff --git a/Mage.Client/src/main/java/mage/client/util/SettingsManager.java b/Mage.Client/src/main/java/mage/client/util/SettingsManager.java new file mode 100644 index 00000000000..a0629bd2cf6 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/SettingsManager.java @@ -0,0 +1,68 @@ +package mage.client.util; + +import com.sun.org.apache.xerces.internal.impl.dv.xs.YearMonthDV; + +import java.awt.*; +import java.util.UUID; + +/** + * Contains dynamic settings for client. + * + * @author nantuko + */ +public class SettingsManager { + private static SettingsManager fInstance = new SettingsManager(); + + public static SettingsManager getInstance() { + return fInstance; + } + + public int getScreenWidth() { + return screenWidth; + } + + public void setScreenWidth(int screenWidth) { + this.screenWidth = screenWidth; + } + + public int getScreenHeight() { + return screenHeight; + } + + public void setScreenHeight(int screenHeight) { + this.screenHeight = screenHeight; + } + + public void setScreenWidthAndHeight(int screenWidth, int screenHeight) { + this.screenWidth = screenWidth; + this.screenHeight = screenHeight; + } + + /** + * Get centered component position. Depends on screen width and height. + * + * @param dialogWidth + * @param dialogHeight + * @return + */ + public Point getComponentPosition(int dialogWidth, int dialogHeight) { + if (dialogWidth == 0) { + throw new IllegalArgumentException("dialogWidth can't be 0"); + } + if (dialogHeight == 0) { + throw new IllegalArgumentException("dialogHeight can't be 0"); + } + + int width = Math.max(screenWidth, dialogWidth); + int height = Math.max(screenHeight, dialogHeight); + + int x = ((width - dialogWidth) / 2); + int y = ((height - dialogHeight) / 2); + + return new Point(x, y); + } + + private int screenWidth; + private int screenHeight; + +} diff --git a/Mage.Client/src/main/resources/buttons/down.png b/Mage.Client/src/main/resources/buttons/down.png new file mode 100644 index 0000000000000000000000000000000000000000..e5f3f8cf216a0cbe7ae2b6c307a6cba5f6b4419f GIT binary patch literal 3098 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 literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/buttons/left.png b/Mage.Client/src/main/resources/buttons/left.png new file mode 100644 index 0000000000000000000000000000000000000000..846b6566992da781d92118192033f5ce54bd04d9 GIT binary patch literal 3093 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 XcK-8Sd0ZKBTQ#EEPJXCJEb?rolPcgNl7rbUq$ z7}%Ez3NnH|_#voIMF>TG$OK8nK))qKkwy4PA&9`F6~YYIe4@wi+njN$WsrL|ilhy#_z-1p(* zmESm6t+zz=upHALGD4oFRCads|gJ>hi&(k{Y4me$iOwLh|@(`0ueEZ2nNzl zNY#Uh$5EWjYyhIcc9xfuR?g6|rjrWcZb&N}pFle3L2*&?kN^M@h=Pagas;WM(u{h= z)?pQehdUztaDsOUWP{h_PP3StL^=o3$$m*=(;hOT$>O~ch9t;9^n{1Z799-@P}b(nzhron9Lx(CcL^;A;yM${#;Ic z@{ql{uCNfMQYmZ7W|h@Aq+Ko-q!`FB7L2fHLz2#=Es}O3E3&2ILmID&O2#fjm+O%S zbPq`yiSi?NIZnwZlC+$8*hZM<6i8bsm{-O`Hx9CyM#ySJmixVb>6zPL?f`9P-R2`7 zrz0=+quxR>7TOu17}i$D+8yT#_*u{{dQcX`*iZr8W?}3R+Qm{7YiDxw0#J_bhK3OZ z#$;SK?zAfo{$rTH=lxO!)c#Cc1RkP(lthxQVbAEDo(Vh~lhq`rd&MLdM^KUCZnz!% zXMNeK@w33s66W9KR_Xax?#X7`_dSu%itc3+$FY!r{~iwlzQ#!X&86G4si>x+<#o;Z zx!HFIzb#JKPQJSSJY_DvZw{L4mih*}L%xd9PghqS9+^H|)HT0$>sP$Qw*em2jJ_FM zsO;s-UjDpL^=w>u`^8&Jtyi`Dm=l~ccfjg+$kg|wv+dg0U|_QNiDP4B@zP9R*JMd( zcHzt@kyx85eP0&ykDKSGzE|H3wx6<0*N&{3X<}@1vmMTS4J?0tv9O2>B?2uSzNbwW GNB#hWq4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$xhYxrBYctQ72>n$?(tJ=cGd^JfrQaW+x-&bkTrAO396adujxx{