Screenmarkers plugin redesign (#3139)
- Update the interface to match with the Obsidian redesign - Remove displaying of screen marker names (they are not editable so not important) - Add support for changing screen markers after creation - Add support for toggling fill
@@ -88,7 +88,8 @@ public class ScreenMarkerMouseListener extends MouseListener
|
||||
|
||||
if (SwingUtilities.isLeftMouseButton(event) && plugin.isCreatingScreenMarker())
|
||||
{
|
||||
plugin.finishCreation(false);
|
||||
/* Set the creation panel as "ready" (because the marker area as been drawn) */
|
||||
plugin.completeSelection();
|
||||
}
|
||||
|
||||
event.consume();
|
||||
|
||||
@@ -43,15 +43,10 @@ public class ScreenMarkerOverlay extends Overlay
|
||||
ScreenMarkerOverlay(ScreenMarker marker)
|
||||
{
|
||||
this.marker = marker;
|
||||
this.screenMarkerRenderable = new ScreenMarkerRenderable();
|
||||
setPosition(OverlayPosition.DETACHED);
|
||||
setLayer(OverlayLayer.ALWAYS_ON_TOP);
|
||||
setPriority(OverlayPriority.HIGH);
|
||||
|
||||
screenMarkerRenderable = new ScreenMarkerRenderable();
|
||||
screenMarkerRenderable.setBorderThickness(marker.getBorderThickness());
|
||||
screenMarkerRenderable.setColor(marker.getColor());
|
||||
screenMarkerRenderable.setFill(marker.getFill());
|
||||
screenMarkerRenderable.setStroke(new BasicStroke(marker.getBorderThickness()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,6 +63,10 @@ public class ScreenMarkerOverlay extends Overlay
|
||||
return null;
|
||||
}
|
||||
|
||||
screenMarkerRenderable.setBorderThickness(marker.getBorderThickness());
|
||||
screenMarkerRenderable.setColor(marker.getColor());
|
||||
screenMarkerRenderable.setFill(marker.getFill());
|
||||
screenMarkerRenderable.setStroke(new BasicStroke(marker.getBorderThickness()));
|
||||
screenMarkerRenderable.setPreferredSize(getPreferredSize());
|
||||
return screenMarkerRenderable.render(graphics);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Kamiel, <https://github.com/Kamielvf>
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,7 +27,6 @@
|
||||
package net.runelite.client.plugins.screenmarkers;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@@ -67,8 +67,8 @@ public class ScreenMarkerPlugin extends Plugin
|
||||
private static final String DEFAULT_MARKER_NAME = "Marker";
|
||||
private static final Dimension DEFAULT_SIZE = new Dimension(2, 2);
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
@Getter
|
||||
private final List<ScreenMarkerOverlay> screenMarkers = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private ConfigManager configManager;
|
||||
@@ -89,9 +89,6 @@ public class ScreenMarkerPlugin extends Plugin
|
||||
private ScreenMarkerPluginPanel pluginPanel;
|
||||
private NavigationButton navigationButton;
|
||||
|
||||
@Getter
|
||||
private final List<ScreenMarkerOverlay> screenMarkers = new ArrayList<>();
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private ScreenMarker currentMarker;
|
||||
|
||||
@@ -125,6 +122,7 @@ public class ScreenMarkerPlugin extends Plugin
|
||||
navigationButton = NavigationButton.builder()
|
||||
.tooltip(PLUGIN_NAME)
|
||||
.icon(icon)
|
||||
.priority(5)
|
||||
.panel(pluginPanel)
|
||||
.build();
|
||||
|
||||
@@ -189,9 +187,6 @@ public class ScreenMarkerPlugin extends Plugin
|
||||
{
|
||||
if (!aborted)
|
||||
{
|
||||
setMouseListenerEnabled(false);
|
||||
pluginPanel.setCreationEnabled(false);
|
||||
|
||||
final ScreenMarkerOverlay screenMarkerOverlay = new ScreenMarkerOverlay(currentMarker);
|
||||
screenMarkerOverlay.setPreferredLocation(overlay.getBounds().getLocation());
|
||||
screenMarkerOverlay.setPreferredSize(overlay.getBounds().getSize());
|
||||
@@ -205,6 +200,15 @@ public class ScreenMarkerPlugin extends Plugin
|
||||
|
||||
creatingScreenMarker = false;
|
||||
currentMarker = null;
|
||||
setMouseListenerEnabled(false);
|
||||
|
||||
pluginPanel.setCreation(false);
|
||||
}
|
||||
|
||||
/* The marker area has been drawn, inform the user and unlock the confirm button */
|
||||
public void completeSelection()
|
||||
{
|
||||
pluginPanel.getCreationPanel().unlockConfirm();
|
||||
}
|
||||
|
||||
public void deleteMarker(final ScreenMarkerOverlay marker)
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.screenmarkers.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.client.plugins.screenmarkers.ScreenMarkerPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
public class ScreenMarkerCreationPanel extends JPanel
|
||||
{
|
||||
private static final ImageIcon CONFIRM_ICON;
|
||||
private static final ImageIcon CONFIRM_HOVER_ICON;
|
||||
private static final ImageIcon CONFIRM_LOCKED_ICON;
|
||||
private static final ImageIcon CANCEL_ICON;
|
||||
private static final ImageIcon CANCEL_HOVER_ICON;
|
||||
|
||||
private final JShadowedLabel instructionsLabel = new JShadowedLabel();
|
||||
private final JLabel confirmLabel = new JLabel();
|
||||
private boolean lockedConfirm = true;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
CONFIRM_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_icon.png")));
|
||||
CONFIRM_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_hover_icon.png")));
|
||||
CONFIRM_LOCKED_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("confirm_locked_icon.png")));
|
||||
CANCEL_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("cancel_icon.png")));
|
||||
CANCEL_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("cancel_hover_icon.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
ScreenMarkerCreationPanel(ScreenMarkerPlugin plugin)
|
||||
{
|
||||
setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
setBorder(new EmptyBorder(8, 8, 8, 8));
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
instructionsLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
instructionsLabel.setForeground(Color.WHITE);
|
||||
|
||||
JPanel actionsContainer = new JPanel(new GridLayout(1, 2, 8, 0));
|
||||
actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
confirmLabel.setIcon(CONFIRM_LOCKED_ICON);
|
||||
confirmLabel.setToolTipText("Confirm and save");
|
||||
confirmLabel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
/* If the confirm button is not locked */
|
||||
if (!lockedConfirm)
|
||||
{
|
||||
plugin.finishCreation(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
confirmLabel.setIcon(lockedConfirm ? CONFIRM_LOCKED_ICON : CONFIRM_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
confirmLabel.setIcon(lockedConfirm ? CONFIRM_LOCKED_ICON : CONFIRM_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
JLabel cancelLabel = new JLabel(CANCEL_ICON);
|
||||
cancelLabel.setToolTipText("Cancel");
|
||||
cancelLabel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
plugin.finishCreation(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
cancelLabel.setIcon(CANCEL_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
cancelLabel.setIcon(CANCEL_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
actionsContainer.add(confirmLabel);
|
||||
actionsContainer.add(cancelLabel);
|
||||
|
||||
add(instructionsLabel, BorderLayout.CENTER);
|
||||
add(actionsContainer, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
/* Unlocks the confirm button */
|
||||
public void unlockConfirm()
|
||||
{
|
||||
this.confirmLabel.setIcon(CONFIRM_ICON);
|
||||
this.lockedConfirm = false;
|
||||
instructionsLabel.setText("Confirm or cancel to finish.");
|
||||
}
|
||||
|
||||
/* Locks the confirm button */
|
||||
public void lockConfirm()
|
||||
{
|
||||
this.confirmLabel.setIcon(CONFIRM_LOCKED_ICON);
|
||||
this.lockedConfirm = true;
|
||||
instructionsLabel.setText("Drag in-game to draw");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Kamiel, <https://github.com/Kamielvf>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,55 +25,395 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.screenmarkers.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridLayout;
|
||||
import javax.swing.JButton;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import net.runelite.client.plugins.screenmarkers.ScreenMarkerOverlay;
|
||||
import net.runelite.client.plugins.screenmarkers.ScreenMarkerPlugin;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
class ScreenMarkerPanel extends JPanel
|
||||
{
|
||||
private static final String DELETE_TEXT = "Delete";
|
||||
private static final String HIDE_TEXT = "Hide";
|
||||
private static final String SHOW_TEXT = "Show";
|
||||
private static final int DEFAULT_FILL_OPACITY = 75;
|
||||
|
||||
private static final ImageIcon BORDER_COLOR_ICON;
|
||||
private static final ImageIcon BORDER_COLOR_HOVER_ICON;
|
||||
private static final ImageIcon NO_BORDER_COLOR_ICON;
|
||||
private static final ImageIcon NO_BORDER_COLOR_HOVER_ICON;
|
||||
|
||||
private static final ImageIcon FILL_COLOR_ICON;
|
||||
private static final ImageIcon FILL_COLOR_HOVER_ICON;
|
||||
private static final ImageIcon NO_FILL_COLOR_ICON;
|
||||
private static final ImageIcon NO_FILL_COLOR_HOVER_ICON;
|
||||
|
||||
private static final ImageIcon FULL_OPACITY_ICON;
|
||||
private static final ImageIcon OPACITY_HOVER_ICON;
|
||||
private static final ImageIcon NO_OPACITY_ICON;
|
||||
|
||||
private static final ImageIcon VISIBLE_ICON;
|
||||
private static final ImageIcon VISIBLE_HOVER_ICON;
|
||||
private static final ImageIcon INVISIBLE_ICON;
|
||||
private static final ImageIcon INVISIBLE_HOVER_ICON;
|
||||
|
||||
private static final ImageIcon DELETE_ICON;
|
||||
private static final ImageIcon DELETE_HOVER_ICON;
|
||||
|
||||
private final ScreenMarkerPlugin plugin;
|
||||
private final ScreenMarkerOverlay marker;
|
||||
private JToggleButton visibleToggle;
|
||||
|
||||
private final JLabel borderColorIndicator = new JLabel();
|
||||
private final JLabel fillColorIndicator = new JLabel();
|
||||
private final JLabel opacityIndicator = new JLabel();
|
||||
private final JLabel visibilityLabel = new JLabel();
|
||||
private final JLabel deleteLabel = new JLabel();
|
||||
|
||||
private final SpinnerModel spinnerModel = new SpinnerNumberModel(5, 0, Integer.MAX_VALUE, 1);
|
||||
private final JSpinner thicknessSpinner = new JSpinner(spinnerModel);
|
||||
|
||||
private boolean visible;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
BufferedImage borderImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("border_color_icon.png"));
|
||||
BORDER_COLOR_ICON = new ImageIcon(borderImg);
|
||||
BORDER_COLOR_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(borderImg, -100));
|
||||
|
||||
BufferedImage noBorderImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("no_border_color_icon.png"));
|
||||
NO_BORDER_COLOR_ICON = new ImageIcon(noBorderImg);
|
||||
NO_BORDER_COLOR_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(noBorderImg, -100));
|
||||
|
||||
BufferedImage fillImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("fill_color_icon.png"));
|
||||
FILL_COLOR_ICON = new ImageIcon(fillImg);
|
||||
FILL_COLOR_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(fillImg, -100));
|
||||
|
||||
BufferedImage noFillImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("no_fill_color_icon.png"));
|
||||
NO_FILL_COLOR_ICON = new ImageIcon(noFillImg);
|
||||
NO_FILL_COLOR_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(noFillImg, -100));
|
||||
|
||||
BufferedImage opacityImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("opacity_icon.png"));
|
||||
FULL_OPACITY_ICON = new ImageIcon(opacityImg);
|
||||
OPACITY_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(opacityImg, -100));
|
||||
NO_OPACITY_ICON = new ImageIcon(SwingUtil.grayscaleOffset(opacityImg, -150));
|
||||
|
||||
BufferedImage visibleImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("visible_icon.png"));
|
||||
VISIBLE_ICON = new ImageIcon(visibleImg);
|
||||
VISIBLE_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(visibleImg, -100));
|
||||
|
||||
BufferedImage invisibleImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("invisible_icon.png"));
|
||||
INVISIBLE_ICON = new ImageIcon(invisibleImg);
|
||||
INVISIBLE_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(invisibleImg, -100));
|
||||
|
||||
BufferedImage deleteImg = ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("delete_icon.png"));
|
||||
DELETE_ICON = new ImageIcon(deleteImg);
|
||||
DELETE_HOVER_ICON = new ImageIcon(SwingUtil.grayscaleOffset(deleteImg, -100));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
ScreenMarkerPanel(ScreenMarkerPlugin plugin, ScreenMarkerOverlay marker)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.marker = marker;
|
||||
construct();
|
||||
}
|
||||
this.visible = marker.getMarker().isVisible();
|
||||
|
||||
private void construct()
|
||||
{
|
||||
setLayout(new GridLayout(0, 1, 0, 3));
|
||||
JPanel container = new JPanel(new FlowLayout());
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
JButton deleteButton = new JButton(DELETE_TEXT);
|
||||
deleteButton.addActionListener(l -> plugin.deleteMarker(marker));
|
||||
JPanel bottomContainer = new JPanel(new BorderLayout());
|
||||
bottomContainer.setBorder(new EmptyBorder(8, 0, 8, 0));
|
||||
bottomContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
boolean selected = !marker.getMarker().isVisible();
|
||||
visibleToggle = new JToggleButton(selected ? SHOW_TEXT : HIDE_TEXT, selected);
|
||||
visibleToggle.setFocusable(false);
|
||||
visibleToggle.addActionListener(l ->
|
||||
JPanel leftActions = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0));
|
||||
leftActions.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
borderColorIndicator.setToolTipText("Edit border color");
|
||||
borderColorIndicator.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
boolean visible = !visibleToggle.isSelected();
|
||||
marker.getMarker().setVisible(visible);
|
||||
visibleToggle.setText(visible ? HIDE_TEXT : SHOW_TEXT);
|
||||
plugin.updateConfig();
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
openBorderColorPicker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
borderColorIndicator.setIcon(marker.getMarker().getBorderThickness() == 0 ? NO_BORDER_COLOR_HOVER_ICON : BORDER_COLOR_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
borderColorIndicator.setIcon(marker.getMarker().getBorderThickness() == 0 ? NO_BORDER_COLOR_ICON : BORDER_COLOR_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
container.add(new JShadowedLabel(marker.getName()));
|
||||
container.add(visibleToggle);
|
||||
container.add(deleteButton);
|
||||
fillColorIndicator.setToolTipText("Edit fill color");
|
||||
fillColorIndicator.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
openFillColorPicker();
|
||||
}
|
||||
|
||||
add(container);
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
fillColorIndicator.setIcon(marker.getMarker().getFill().getAlpha() == 0 ? NO_FILL_COLOR_HOVER_ICON : FILL_COLOR_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
fillColorIndicator.setIcon(marker.getMarker().getFill().getAlpha() == 0 ? NO_FILL_COLOR_ICON : FILL_COLOR_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
thicknessSpinner.setValue(marker.getMarker().getBorderThickness());
|
||||
thicknessSpinner.setPreferredSize(new Dimension(50, 20));
|
||||
thicknessSpinner.addChangeListener(ce -> updateThickness(true));
|
||||
|
||||
opacityIndicator.setToolTipText("Toggle background transparency");
|
||||
opacityIndicator.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
final Color fill = marker.getMarker().getFill();
|
||||
|
||||
if (fill.getAlpha() == 0)
|
||||
{
|
||||
marker.getMarker().setFill(new Color(fill.getRed(), fill.getGreen(), fill.getBlue(), DEFAULT_FILL_OPACITY));
|
||||
}
|
||||
else
|
||||
{
|
||||
marker.getMarker().setFill(new Color(fill.getRed(), fill.getGreen(), fill.getBlue(), 0));
|
||||
}
|
||||
|
||||
updateFill();
|
||||
plugin.updateConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
opacityIndicator.setIcon(OPACITY_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
opacityIndicator.setIcon(marker.getMarker().getFill().getAlpha() == 0 ? NO_OPACITY_ICON : FULL_OPACITY_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
leftActions.add(borderColorIndicator);
|
||||
leftActions.add(fillColorIndicator);
|
||||
leftActions.add(opacityIndicator);
|
||||
leftActions.add(thicknessSpinner);
|
||||
|
||||
JPanel rightActions = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
|
||||
rightActions.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
visibilityLabel.setToolTipText(visible ? "Hide screen marker" : "Show screen marker");
|
||||
visibilityLabel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
visible = !visible;
|
||||
marker.getMarker().setVisible(visible);
|
||||
plugin.updateConfig();
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
visibilityLabel.setIcon(visible ? VISIBLE_HOVER_ICON : INVISIBLE_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
updateVisibility();
|
||||
}
|
||||
});
|
||||
|
||||
deleteLabel.setIcon(DELETE_ICON);
|
||||
deleteLabel.setToolTipText("Delete screen marker");
|
||||
deleteLabel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
int confirm = JOptionPane.showConfirmDialog(null,
|
||||
"Are you sure you want to permanenely delete this screen marker?",
|
||||
"Warning", JOptionPane.OK_CANCEL_OPTION);
|
||||
|
||||
if (confirm == 0)
|
||||
{
|
||||
plugin.deleteMarker(marker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
deleteLabel.setIcon(DELETE_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
deleteLabel.setIcon(DELETE_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
rightActions.add(visibilityLabel);
|
||||
rightActions.add(deleteLabel);
|
||||
|
||||
bottomContainer.add(leftActions, BorderLayout.WEST);
|
||||
bottomContainer.add(rightActions, BorderLayout.EAST);
|
||||
|
||||
add(bottomContainer, BorderLayout.CENTER);
|
||||
|
||||
updateVisibility();
|
||||
updateFill();
|
||||
updateBorder();
|
||||
updateBorder();
|
||||
|
||||
}
|
||||
|
||||
/* Updates the thickness without saving on config */
|
||||
private void updateThickness(boolean save)
|
||||
{
|
||||
marker.getMarker().setBorderThickness((Integer) thicknessSpinner.getValue());
|
||||
updateBorder();
|
||||
if (save)
|
||||
{
|
||||
plugin.updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateVisibility()
|
||||
{
|
||||
visibilityLabel.setIcon(visible ? VISIBLE_ICON : INVISIBLE_ICON);
|
||||
}
|
||||
|
||||
private void updateFill()
|
||||
{
|
||||
final boolean isFullyTransparent = marker.getMarker().getFill().getAlpha() == 0;
|
||||
|
||||
if (isFullyTransparent)
|
||||
{
|
||||
fillColorIndicator.setBorder(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Color color = marker.getMarker().getFill();
|
||||
Color fullColor = new Color(color.getRed(), color.getGreen(), color.getBlue());
|
||||
fillColorIndicator.setBorder(new MatteBorder(0, 0, 3, 0, fullColor));
|
||||
}
|
||||
|
||||
fillColorIndicator.setIcon(isFullyTransparent ? NO_FILL_COLOR_ICON : FILL_COLOR_ICON);
|
||||
opacityIndicator.setIcon(isFullyTransparent ? NO_OPACITY_ICON : FULL_OPACITY_ICON);
|
||||
}
|
||||
|
||||
private void updateBorder()
|
||||
{
|
||||
if (marker.getMarker().getBorderThickness() == 0)
|
||||
{
|
||||
borderColorIndicator.setBorder(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Color color = marker.getMarker().getColor();
|
||||
borderColorIndicator.setBorder(new MatteBorder(0, 0, 3, 0, color));
|
||||
}
|
||||
|
||||
borderColorIndicator.setIcon(marker.getMarker().getBorderThickness() == 0 ? NO_BORDER_COLOR_ICON : BORDER_COLOR_ICON);
|
||||
}
|
||||
|
||||
private void openFillColorPicker()
|
||||
{
|
||||
final JFrame parent = new JFrame();
|
||||
JColorChooser jColorChooser = new JColorChooser(marker.getMarker().getFill());
|
||||
|
||||
jColorChooser.getSelectionModel().addChangeListener(e1 ->
|
||||
{
|
||||
Color chosen = jColorChooser.getColor();
|
||||
marker.getMarker().setFill(new Color(chosen.getRed(), chosen.getGreen(), chosen.getBlue(), DEFAULT_FILL_OPACITY));
|
||||
updateFill();
|
||||
});
|
||||
|
||||
parent.addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
plugin.updateConfig();
|
||||
}
|
||||
});
|
||||
|
||||
parent.add(jColorChooser);
|
||||
parent.pack();
|
||||
parent.setLocationRelativeTo(null);
|
||||
parent.setVisible(true);
|
||||
}
|
||||
|
||||
private void openBorderColorPicker()
|
||||
{
|
||||
final JFrame parent = new JFrame();
|
||||
JColorChooser jColorChooser = new JColorChooser(marker.getMarker().getColor());
|
||||
|
||||
jColorChooser.getSelectionModel().addChangeListener(e1 ->
|
||||
{
|
||||
marker.getMarker().setColor(jColorChooser.getColor());
|
||||
updateBorder();
|
||||
});
|
||||
|
||||
parent.addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
plugin.updateConfig();
|
||||
}
|
||||
});
|
||||
|
||||
parent.add(jColorChooser);
|
||||
parent.pack();
|
||||
parent.setLocationRelativeTo(null);
|
||||
parent.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Kamiel, <https://github.com/Kamielvf>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,84 +29,147 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JFrame;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import net.runelite.client.plugins.screenmarkers.ScreenMarkerOverlay;
|
||||
import net.runelite.client.plugins.screenmarkers.ScreenMarkerPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
|
||||
@Singleton
|
||||
public class ScreenMarkerPluginPanel extends PluginPanel
|
||||
{
|
||||
private static final String TITLE = "Screen Markers";
|
||||
private static final Color DEFAULT_COLOR = Color.BLUE;
|
||||
private static final int DEFAULT_BORDER_THICKNESS = 5;
|
||||
private static final int DEFAULT_FILL_OPACITY = 75;
|
||||
private static final String COLOR_PICKER_TITLE = "Choose a color..";
|
||||
private static final String COLOR_TEXT = "Color";
|
||||
private static final String FILL_TEXT = "Fill";
|
||||
private static final String NEW_TEXT = "New";
|
||||
private static final String CANCEL_TEXT = "Cancel";
|
||||
private static final Color CANCEL_BUTTON_COLOR = Color.RED.darker();
|
||||
private static final ImageIcon ADD_ICON;
|
||||
private static final ImageIcon ADD_HOVER_ICON;
|
||||
|
||||
private static final Color DEFAULT_BORDER_COLOR = Color.GREEN;
|
||||
private static final Color DEFAULT_FILL_COLOR = new Color(0, 255, 0, 0);
|
||||
|
||||
private static final int DEFAULT_BORDER_THICKNESS = 3;
|
||||
|
||||
private final JLabel addMarker = new JLabel(ADD_ICON);
|
||||
private final JLabel title = new JLabel();
|
||||
private final PluginErrorPanel noMarkersPanel = new PluginErrorPanel();
|
||||
|
||||
@Inject
|
||||
private ScreenMarkerPlugin plugin;
|
||||
|
||||
private JButton markerButton;
|
||||
@Getter
|
||||
private Color selectedColor = DEFAULT_BORDER_COLOR;
|
||||
|
||||
@Getter
|
||||
private Color selectedColor = DEFAULT_COLOR;
|
||||
|
||||
@Getter
|
||||
private Color selectedFillColor = new Color(DEFAULT_COLOR.getRed(), DEFAULT_COLOR.getGreen(), DEFAULT_COLOR.getBlue(), DEFAULT_FILL_OPACITY);
|
||||
private Color selectedFillColor = DEFAULT_FILL_COLOR;
|
||||
|
||||
@Getter
|
||||
private int selectedBorderThickness = DEFAULT_BORDER_THICKNESS;
|
||||
|
||||
private boolean creationEnabled = false;
|
||||
@Getter
|
||||
private ScreenMarkerCreationPanel creationPanel;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
ADD_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("add_icon.png")));
|
||||
ADD_HOVER_ICON = new ImageIcon(ImageIO.read(ScreenMarkerPlugin.class.getResourceAsStream("add_hover_icon.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
JPanel northPanel = new JPanel(new GridLayout(0, 2, 0, 3));
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
markerButton = new JButton(NEW_TEXT);
|
||||
markerButton.setFocusable(false);
|
||||
markerButton.addActionListener(l -> startOrCancelCreation());
|
||||
JPanel northPanel = new JPanel(new BorderLayout());
|
||||
northPanel.setBorder(new EmptyBorder(1, 0, 10, 0));
|
||||
|
||||
northPanel.add(new JShadowedLabel(TITLE));
|
||||
northPanel.add(new JLabel());
|
||||
northPanel.add(new JShadowedLabel("Border size:"));
|
||||
northPanel.add(createBorderThicknessSpinner());
|
||||
northPanel.add(new JShadowedLabel("Border color:"));
|
||||
northPanel.add(createBorderColorButton());
|
||||
northPanel.add(new JShadowedLabel("Fill color:"));
|
||||
northPanel.add(createFillColorButton());
|
||||
title.setText("Screen Markers");
|
||||
title.setForeground(Color.WHITE);
|
||||
|
||||
northPanel.add(markerButton);
|
||||
northPanel.add(title, BorderLayout.WEST);
|
||||
northPanel.add(addMarker, BorderLayout.EAST);
|
||||
|
||||
JPanel centerPanel = new JPanel();
|
||||
JPanel markerView = new JPanel(new GridLayout(0, 1, 0, 3));
|
||||
JPanel centerPanel = new JPanel(new BorderLayout());
|
||||
centerPanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
JPanel markerView = new JPanel(new GridBagLayout());
|
||||
markerView.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
constraints.weightx = 1;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
|
||||
for (final ScreenMarkerOverlay marker : plugin.getScreenMarkers())
|
||||
{
|
||||
markerView.add(new ScreenMarkerPanel(plugin, marker));
|
||||
markerView.add(new ScreenMarkerPanel(plugin, marker), constraints);
|
||||
constraints.gridy++;
|
||||
|
||||
markerView.add(Box.createRigidArea(new Dimension(0, 10)), constraints);
|
||||
constraints.gridy++;
|
||||
}
|
||||
|
||||
centerPanel.add(markerView, BorderLayout.NORTH);
|
||||
noMarkersPanel.setContent("Screen Markers", "Highlight a region on your screen.");
|
||||
noMarkersPanel.setVisible(false);
|
||||
|
||||
if (plugin.getScreenMarkers().isEmpty())
|
||||
{
|
||||
noMarkersPanel.setVisible(true);
|
||||
title.setVisible(false);
|
||||
}
|
||||
|
||||
markerView.add(noMarkersPanel, constraints);
|
||||
constraints.gridy++;
|
||||
|
||||
creationPanel = new ScreenMarkerCreationPanel(plugin);
|
||||
creationPanel.setVisible(false);
|
||||
|
||||
markerView.add(creationPanel, constraints);
|
||||
constraints.gridy++;
|
||||
|
||||
addMarker.setToolTipText("Add new screen marker");
|
||||
addMarker.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
setCreation(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
addMarker.setIcon(ADD_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
addMarker.setIcon(ADD_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
centerPanel.add(markerView, BorderLayout.CENTER);
|
||||
|
||||
add(northPanel, BorderLayout.NORTH);
|
||||
add(centerPanel, BorderLayout.CENTER);
|
||||
@@ -119,93 +183,28 @@ public class ScreenMarkerPluginPanel extends PluginPanel
|
||||
init();
|
||||
}
|
||||
|
||||
private void startOrCancelCreation()
|
||||
/* Enables/Disables new marker creation mode */
|
||||
public void setCreation(boolean on)
|
||||
{
|
||||
creationEnabled = !creationEnabled;
|
||||
plugin.setMouseListenerEnabled(creationEnabled);
|
||||
setMarkerButtonState(creationEnabled);
|
||||
}
|
||||
|
||||
public void setCreationEnabled(boolean creationEnabled)
|
||||
{
|
||||
this.creationEnabled = creationEnabled;
|
||||
setMarkerButtonState(creationEnabled);
|
||||
}
|
||||
|
||||
private void setMarkerButtonState(boolean selected)
|
||||
{
|
||||
markerButton.setSelected(selected);
|
||||
markerButton.setText(selected ? CANCEL_TEXT : NEW_TEXT);
|
||||
markerButton.setBackground(selected ? CANCEL_BUTTON_COLOR : null);
|
||||
}
|
||||
|
||||
private JSpinner createBorderThicknessSpinner()
|
||||
{
|
||||
SpinnerModel model = new SpinnerNumberModel(selectedBorderThickness, 0, Integer.MAX_VALUE, 1);
|
||||
JSpinner spinner = new JSpinner(model);
|
||||
Component editor = spinner.getEditor();
|
||||
JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField();
|
||||
spinnerTextField.setColumns(5);
|
||||
spinner.addChangeListener(ce -> selectedBorderThickness = (Integer) spinner.getValue());
|
||||
return spinner;
|
||||
}
|
||||
|
||||
private JButton createBorderColorButton()
|
||||
{
|
||||
JButton colorPicker = new JButton(COLOR_TEXT);
|
||||
colorPicker.setFocusable(false);
|
||||
colorPicker.setBackground(selectedColor);
|
||||
colorPicker.addActionListener(e ->
|
||||
if (on)
|
||||
{
|
||||
final JFrame parent = new JFrame(COLOR_PICKER_TITLE);
|
||||
JColorChooser jColorChooser = new JColorChooser(selectedColor);
|
||||
jColorChooser.getSelectionModel().addChangeListener(e1 -> colorPicker.setBackground(jColorChooser.getColor()));
|
||||
|
||||
parent.addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
selectedColor = jColorChooser.getColor();
|
||||
}
|
||||
});
|
||||
|
||||
parent.add(jColorChooser);
|
||||
parent.pack();
|
||||
parent.setLocationRelativeTo(null);
|
||||
parent.setVisible(true);
|
||||
});
|
||||
|
||||
return colorPicker;
|
||||
}
|
||||
|
||||
private JButton createFillColorButton()
|
||||
{
|
||||
JButton colorPicker = new JButton(FILL_TEXT);
|
||||
colorPicker.setFocusable(false);
|
||||
colorPicker.setBackground(selectedFillColor);
|
||||
colorPicker.addActionListener(e ->
|
||||
noMarkersPanel.setVisible(false);
|
||||
title.setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
final JFrame parent = new JFrame(COLOR_PICKER_TITLE);
|
||||
JColorChooser jColorChooser = new JColorChooser(selectedFillColor);
|
||||
jColorChooser.getSelectionModel().addChangeListener(e1 -> colorPicker.setBackground(jColorChooser.getColor()));
|
||||
boolean empty = plugin.getScreenMarkers().isEmpty();
|
||||
noMarkersPanel.setVisible(empty);
|
||||
title.setVisible(!empty);
|
||||
}
|
||||
|
||||
parent.addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
Color color = jColorChooser.getColor();
|
||||
selectedFillColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), DEFAULT_FILL_OPACITY);
|
||||
}
|
||||
});
|
||||
creationPanel.setVisible(on);
|
||||
addMarker.setVisible(!on);
|
||||
|
||||
parent.add(jColorChooser);
|
||||
parent.pack();
|
||||
parent.setLocationRelativeTo(null);
|
||||
parent.setVisible(true);
|
||||
});
|
||||
|
||||
return colorPicker;
|
||||
if (on)
|
||||
{
|
||||
creationPanel.lockConfirm();
|
||||
plugin.setMouseListenerEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 213 B |
|
After Width: | Height: | Size: 255 B |