mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 14:30:14 +00:00
Polish map view list
Outline icons, keycaps, row hover.
This commit is contained in:
1 parent
a648ef6622
commit
2cd9167549
5 files changed
+331
-24
No files matched your search
@@ -112,6 +112,7 @@ final class MapCanvas extends JPanel {
|
|||||||
private boolean entitiesVisible;
|
private boolean entitiesVisible;
|
||||||
private boolean follow;
|
private boolean follow;
|
||||||
private boolean help;
|
private boolean help;
|
||||||
|
private int coveredLeftWidth;
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
private boolean detailedHover;
|
private boolean detailedHover;
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
@@ -337,6 +338,17 @@ final class MapCanvas extends JPanel {
|
|||||||
listener.onTogglesChanged();
|
listener.onTogglesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps the help, debug and notification cards clear of a panel floating over the map's left side.
|
||||||
|
*/
|
||||||
|
void setCoveredLeftWidth(int width) {
|
||||||
|
if (width == coveredLeftWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
coveredLeftWidth = width;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
void toggleHelp() {
|
void toggleHelp() {
|
||||||
help = !help;
|
help = !help;
|
||||||
repaint();
|
repaint();
|
||||||
@@ -814,15 +826,16 @@ final class MapCanvas extends JPanel {
|
|||||||
int lineHeight = canvas.getFontMetrics().getHeight() + StudioTheme.scale(4);
|
int lineHeight = canvas.getFontMetrics().getHeight() + StudioTheme.scale(4);
|
||||||
int width = keyWidth + columnGap + descriptionWidth + padding * 2;
|
int width = keyWidth + columnGap + descriptionWidth + padding * 2;
|
||||||
int height = keys.size() * lineHeight + padding * 2;
|
int height = keys.size() * lineHeight + padding * 2;
|
||||||
StudioOverlay.drawCard(canvas, padding, padding, width, height);
|
int left = coveredLeftWidth + padding;
|
||||||
|
StudioOverlay.drawCard(canvas, left, padding, width, height);
|
||||||
for (int index = 0; index < keys.size(); index++) {
|
for (int index = 0; index < keys.size(); index++) {
|
||||||
int y = padding * 2 + canvas.getFontMetrics().getAscent() + index * lineHeight;
|
int y = padding * 2 + canvas.getFontMetrics().getAscent() + index * lineHeight;
|
||||||
canvas.setFont(StudioTheme.boldFont());
|
canvas.setFont(StudioTheme.boldFont());
|
||||||
canvas.setColor(StudioTheme.LINK);
|
canvas.setColor(StudioTheme.LINK);
|
||||||
canvas.drawString(keys.get(index), padding * 2, y);
|
canvas.drawString(keys.get(index), left + padding, y);
|
||||||
canvas.setFont(StudioTheme.font());
|
canvas.setFont(StudioTheme.font());
|
||||||
canvas.setColor(StudioTheme.SECONDARY_TEXT);
|
canvas.setColor(StudioTheme.SECONDARY_TEXT);
|
||||||
canvas.drawString(descriptions.get(index), padding * 2 + keyWidth + columnGap, y);
|
canvas.drawString(descriptions.get(index), left + padding + keyWidth + columnGap, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,7 +848,7 @@ final class MapCanvas extends JPanel {
|
|||||||
lines.add("Tile scale " + (frame == null ? "-" : Form.f(frame.renderBlocksPerPixel(), 0)) + " blocks/px");
|
lines.add("Tile scale " + (frame == null ? "-" : Form.f(frame.renderBlocksPerPixel(), 0)) + " blocks/px");
|
||||||
lines.add(paintCadenceFps + " paints per second");
|
lines.add(paintCadenceFps + " paints per second");
|
||||||
int padding = StudioTheme.scale(CARD_PADDING);
|
int padding = StudioTheme.scale(CARD_PADDING);
|
||||||
drawCard(canvas, padding, getHeight() - padding, 0D, 1D, lines);
|
drawCard(canvas, coveredLeftWidth + padding, getHeight() - padding, 0D, 1D, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderNotifications(Graphics2D canvas) {
|
private void renderNotifications(Graphics2D canvas) {
|
||||||
@@ -848,7 +861,7 @@ final class MapCanvas extends JPanel {
|
|||||||
int padding = StudioTheme.scale(CARD_PADDING);
|
int padding = StudioTheme.scale(CARD_PADDING);
|
||||||
int width = textWidth + padding * 2;
|
int width = textWidth + padding * 2;
|
||||||
int height = canvas.getFontMetrics().getHeight() + padding;
|
int height = canvas.getFontMetrics().getHeight() + padding;
|
||||||
int x = (getWidth() - width) / 2;
|
int x = coveredLeftWidth + (getWidth() - coveredLeftWidth - width) / 2;
|
||||||
int y = getHeight() - height - StudioTheme.scale(16);
|
int y = getHeight() - height - StudioTheme.scale(16);
|
||||||
StudioOverlay.drawCard(canvas, x, y, width, height);
|
StudioOverlay.drawCard(canvas, x, y, width, height);
|
||||||
canvas.setColor(StudioTheme.TEXT);
|
canvas.setColor(StudioTheme.TEXT);
|
||||||
|
|||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.gui;
|
||||||
|
|
||||||
|
import java.awt.BasicStroke;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.Shape;
|
||||||
|
import java.awt.geom.Ellipse2D;
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A small outline picture of what a map view shows, in the style of IntelliJ's new UI icons: thin single-colour
|
||||||
|
* lines on a 16 by 16 grid, laid on half pixels so they stay crisp.
|
||||||
|
*/
|
||||||
|
final class MapViewIcon {
|
||||||
|
private static final double GRID = 16D;
|
||||||
|
private static final float LINE_WIDTH = 1F;
|
||||||
|
private static final Color LINE_COLOR = new Color(0xCED0D6);
|
||||||
|
|
||||||
|
private MapViewIcon() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void paint(Graphics2D graphics, MapView view, int x, int y, int size) {
|
||||||
|
Graphics2D canvas = (Graphics2D) graphics.create();
|
||||||
|
try {
|
||||||
|
canvas.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
canvas.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
|
||||||
|
canvas.translate(x, y);
|
||||||
|
canvas.scale(size / GRID, size / GRID);
|
||||||
|
canvas.setColor(LINE_COLOR);
|
||||||
|
canvas.setStroke(new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
|
||||||
|
for (Shape line : glyphOf(view)) {
|
||||||
|
canvas.draw(line);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
canvas.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> glyphOf(MapView view) {
|
||||||
|
return switch (view) {
|
||||||
|
case BIOMES -> leaf();
|
||||||
|
case REGIONS -> foldedMap();
|
||||||
|
case HEIGHT -> mountains();
|
||||||
|
case CONTINENTS -> globe();
|
||||||
|
case LAND_BIOMES -> tree();
|
||||||
|
case SEA_BIOMES -> waves();
|
||||||
|
case CAVE_BIOMES -> caveMouth();
|
||||||
|
case PALETTES -> layers();
|
||||||
|
case OBJECTS -> cube();
|
||||||
|
case NOISE -> noiseWave();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> leaf() {
|
||||||
|
Path2D blade = new Path2D.Double();
|
||||||
|
blade.moveTo(3.5, 12.5);
|
||||||
|
blade.curveTo(2.5, 6, 6.5, 2.5, 13.5, 2.5);
|
||||||
|
blade.curveTo(13.5, 9.5, 10, 13.5, 3.5, 12.5);
|
||||||
|
return List.of(blade, new Line2D.Double(3.5, 12.5, 9.5, 6.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> foldedMap() {
|
||||||
|
Path2D outline = new Path2D.Double();
|
||||||
|
outline.moveTo(1.5, 3.5);
|
||||||
|
outline.lineTo(5.5, 2.5);
|
||||||
|
outline.lineTo(10.5, 3.5);
|
||||||
|
outline.lineTo(14.5, 2.5);
|
||||||
|
outline.lineTo(14.5, 12.5);
|
||||||
|
outline.lineTo(10.5, 13.5);
|
||||||
|
outline.lineTo(5.5, 12.5);
|
||||||
|
outline.lineTo(1.5, 13.5);
|
||||||
|
outline.closePath();
|
||||||
|
return List.of(outline, new Line2D.Double(5.5, 2.5, 5.5, 12.5), new Line2D.Double(10.5, 3.5, 10.5, 13.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> mountains() {
|
||||||
|
Path2D ridge = new Path2D.Double();
|
||||||
|
ridge.moveTo(1.5, 13.5);
|
||||||
|
ridge.lineTo(6.5, 4.5);
|
||||||
|
ridge.lineTo(9.5, 9.5);
|
||||||
|
ridge.lineTo(11, 7.5);
|
||||||
|
ridge.lineTo(14.5, 13.5);
|
||||||
|
ridge.closePath();
|
||||||
|
return List.of(ridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> globe() {
|
||||||
|
return List.of(
|
||||||
|
new Ellipse2D.Double(1.5, 1.5, 13, 13),
|
||||||
|
new Ellipse2D.Double(5, 1.5, 6, 13),
|
||||||
|
new Line2D.Double(1.5, 8, 14.5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> tree() {
|
||||||
|
Path2D crown = new Path2D.Double();
|
||||||
|
crown.moveTo(8, 1.5);
|
||||||
|
crown.lineTo(13.5, 11.5);
|
||||||
|
crown.lineTo(2.5, 11.5);
|
||||||
|
crown.closePath();
|
||||||
|
return List.of(crown, new Line2D.Double(8, 11.5, 8, 14.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> waves() {
|
||||||
|
return List.of(wave(5.5), wave(10.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Shape wave(double middleY) {
|
||||||
|
Path2D wave = new Path2D.Double();
|
||||||
|
wave.moveTo(1.5, middleY);
|
||||||
|
wave.curveTo(3.7, middleY - 2.5, 5.8, middleY - 2.5, 8, middleY);
|
||||||
|
wave.curveTo(10.2, middleY + 2.5, 12.3, middleY + 2.5, 14.5, middleY);
|
||||||
|
return wave;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> caveMouth() {
|
||||||
|
Path2D arch = new Path2D.Double();
|
||||||
|
arch.moveTo(3.5, 13.5);
|
||||||
|
arch.lineTo(3.5, 8);
|
||||||
|
arch.curveTo(3.5, 2, 12.5, 2, 12.5, 8);
|
||||||
|
arch.lineTo(12.5, 13.5);
|
||||||
|
return List.of(arch, new Line2D.Double(1.5, 13.5, 14.5, 13.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stacked sheets, like IntelliJ's layers icon.
|
||||||
|
private static List<Shape> layers() {
|
||||||
|
Path2D top = new Path2D.Double();
|
||||||
|
top.moveTo(8, 1.5);
|
||||||
|
top.lineTo(14.5, 5);
|
||||||
|
top.lineTo(8, 8.5);
|
||||||
|
top.lineTo(1.5, 5);
|
||||||
|
top.closePath();
|
||||||
|
return List.of(top, chevron(8.5), chevron(11.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Shape chevron(double sideY) {
|
||||||
|
Path2D chevron = new Path2D.Double();
|
||||||
|
chevron.moveTo(1.5, sideY);
|
||||||
|
chevron.lineTo(8, sideY + 3.5);
|
||||||
|
chevron.lineTo(14.5, sideY);
|
||||||
|
return chevron;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> cube() {
|
||||||
|
Path2D outline = new Path2D.Double();
|
||||||
|
outline.moveTo(8, 1.5);
|
||||||
|
outline.lineTo(14, 4.5);
|
||||||
|
outline.lineTo(14, 11.5);
|
||||||
|
outline.lineTo(8, 14.5);
|
||||||
|
outline.lineTo(2, 11.5);
|
||||||
|
outline.lineTo(2, 4.5);
|
||||||
|
outline.closePath();
|
||||||
|
Path2D edges = new Path2D.Double();
|
||||||
|
edges.moveTo(2, 4.5);
|
||||||
|
edges.lineTo(8, 7.5);
|
||||||
|
edges.lineTo(14, 4.5);
|
||||||
|
edges.moveTo(8, 7.5);
|
||||||
|
edges.lineTo(8, 14.5);
|
||||||
|
return List.of(outline, edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Shape> noiseWave() {
|
||||||
|
Path2D wave = new Path2D.Double();
|
||||||
|
wave.moveTo(1.5, 9);
|
||||||
|
wave.curveTo(2.8, 3, 4.6, 3, 5.8, 8);
|
||||||
|
wave.curveTo(7, 13, 8.8, 13.5, 10, 7.5);
|
||||||
|
wave.curveTo(11, 3.5, 13, 4.5, 14.5, 8.5);
|
||||||
|
return List.of(wave);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,27 +18,35 @@
|
|||||||
|
|
||||||
package com.volmit.iris.core.gui;
|
package com.volmit.iris.core.gui;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.DefaultListCellRenderer;
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.DefaultListModel;
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.Icon;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.UIManager;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map window's list of views, grouped under headers, each row showing the key that opens it.
|
* The map window's list of views, grouped under headers, each row with a picture of the view and the key that opens
|
||||||
|
* it.
|
||||||
*/
|
*/
|
||||||
final class MapViewList extends JList<MapViewList.Row> {
|
final class MapViewList extends JList<MapViewList.Row> {
|
||||||
private static final long serialVersionUID = -4130872409914437415L;
|
private static final long serialVersionUID = -4130872409914437415L;
|
||||||
private static final int ROW_HEIGHT = 26;
|
private static final int ROW_HEIGHT = 28;
|
||||||
|
private static final int NO_ROW = -1;
|
||||||
|
|
||||||
private final DefaultListModel<Row> rows = new DefaultListModel<>();
|
private final DefaultListModel<Row> rows = new DefaultListModel<>();
|
||||||
private int lastViewRow;
|
private int lastViewRow;
|
||||||
|
private int hoveredRow = NO_ROW;
|
||||||
|
|
||||||
MapViewList(Consumer<MapView> onViewChosen) {
|
MapViewList(Consumer<MapView> onViewChosen) {
|
||||||
fillRows();
|
fillRows();
|
||||||
@@ -58,6 +66,43 @@ final class MapViewList extends JList<MapViewList.Row> {
|
|||||||
lastViewRow = getSelectedIndex();
|
lastViewRow = getSelectedIndex();
|
||||||
onViewChosen.accept(selected.view());
|
onViewChosen.accept(selected.view());
|
||||||
});
|
});
|
||||||
|
MouseAdapter hover = new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(MouseEvent event) {
|
||||||
|
hover(viewRowAt(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent event) {
|
||||||
|
hover(NO_ROW);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addMouseListener(hover);
|
||||||
|
addMouseMotionListener(hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int viewRowAt(MouseEvent event) {
|
||||||
|
int row = locationToIndex(event.getPoint());
|
||||||
|
if (row < 0 || rows.get(row).isHeader() || !getCellBounds(row, row).contains(event.getPoint())) {
|
||||||
|
return NO_ROW;
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hover(int row) {
|
||||||
|
if (row == hoveredRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repaintRow(hoveredRow);
|
||||||
|
hoveredRow = row;
|
||||||
|
repaintRow(hoveredRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repaintRow(int row) {
|
||||||
|
Rectangle bounds = row == NO_ROW ? null : getCellBounds(row, row);
|
||||||
|
if (bounds != null) {
|
||||||
|
repaint(bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void select(MapView view) {
|
void select(MapView view) {
|
||||||
@@ -123,7 +168,12 @@ final class MapViewList extends JList<MapViewList.Row> {
|
|||||||
|
|
||||||
private static final class RowRenderer extends DefaultListCellRenderer {
|
private static final class RowRenderer extends DefaultListCellRenderer {
|
||||||
private static final long serialVersionUID = 6302156810211578474L;
|
private static final long serialVersionUID = 6302156810211578474L;
|
||||||
|
private static final int ICON_SIZE = 16;
|
||||||
|
private static final int ICON_TEXT_GAP = 8;
|
||||||
|
private static final int KEYCAP_SIZE = 17;
|
||||||
|
private static final int KEYCAP_ARC = 5;
|
||||||
private String shortcut;
|
private String shortcut;
|
||||||
|
private boolean hovered;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean selected, boolean focused) {
|
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean selected, boolean focused) {
|
||||||
@@ -133,35 +183,83 @@ final class MapViewList extends JList<MapViewList.Row> {
|
|||||||
setText(row.group().label().toUpperCase(Locale.ROOT));
|
setText(row.group().label().toUpperCase(Locale.ROOT));
|
||||||
setFont(StudioTheme.sectionFont());
|
setFont(StudioTheme.sectionFont());
|
||||||
setForeground(StudioTheme.MUTED_TEXT);
|
setForeground(StudioTheme.MUTED_TEXT);
|
||||||
setBorder(StudioTheme.emptyBorder(index == 0 ? 0 : 6, 6, 0, 6));
|
setBorder(StudioTheme.emptyBorder(index == 0 ? 2 : 10, 8, 0, 6));
|
||||||
|
setIcon(null);
|
||||||
setToolTipText(null);
|
setToolTipText(null);
|
||||||
shortcut = null;
|
shortcut = null;
|
||||||
|
hovered = false;
|
||||||
|
setOpaque(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
setFont(StudioTheme.font());
|
setFont(StudioTheme.font());
|
||||||
setBorder(StudioTheme.emptyBorder(0, 10, 0, 10));
|
setBorder(StudioTheme.emptyBorder(0, 8, 0, 8));
|
||||||
|
setIcon(new ViewIcon(row.view()));
|
||||||
|
setIconTextGap(StudioTheme.scale(ICON_TEXT_GAP));
|
||||||
setToolTipText(row.view().description());
|
setToolTipText(row.view().description());
|
||||||
shortcut = row.view().shortcutText();
|
shortcut = row.view().shortcutText();
|
||||||
|
hovered = !selected && list instanceof MapViewList viewList && viewList.hoveredRow == index;
|
||||||
|
setOpaque(!hovered);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics graphics) {
|
protected void paintComponent(Graphics graphics) {
|
||||||
super.paintComponent(graphics);
|
|
||||||
if (shortcut == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Graphics2D canvas = (Graphics2D) graphics.create();
|
Graphics2D canvas = (Graphics2D) graphics.create();
|
||||||
try {
|
try {
|
||||||
|
canvas.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
canvas.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
canvas.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
canvas.setFont(StudioTheme.smallFont());
|
if (hovered) {
|
||||||
canvas.setColor(StudioTheme.MUTED_TEXT);
|
paintHoverBackground(canvas);
|
||||||
int textWidth = canvas.getFontMetrics().stringWidth(shortcut);
|
}
|
||||||
int baseline = (getHeight() + canvas.getFontMetrics().getAscent() - canvas.getFontMetrics().getDescent()) / 2;
|
super.paintComponent(graphics);
|
||||||
canvas.drawString(shortcut, getWidth() - getInsets().right - textWidth, baseline);
|
if (shortcut != null) {
|
||||||
|
paintKeycap(canvas);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
canvas.dispose();
|
canvas.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shaped like the selection the look and feel paints, so moving between them doesn't jump.
|
||||||
|
private void paintHoverBackground(Graphics2D canvas) {
|
||||||
|
Insets inset = UIManager.getInsets("List.selectionInsets");
|
||||||
|
int left = inset == null ? 0 : StudioTheme.scale(inset.left);
|
||||||
|
int right = inset == null ? 0 : StudioTheme.scale(inset.right);
|
||||||
|
int arc = StudioTheme.scale(UIManager.getInt("List.selectionArc"));
|
||||||
|
canvas.setColor(StudioTheme.HOVER_BACKGROUND);
|
||||||
|
canvas.fillRoundRect(left, 0, getWidth() - left - right, getHeight(), arc, arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintKeycap(Graphics2D canvas) {
|
||||||
|
canvas.setFont(StudioTheme.smallFont());
|
||||||
|
int textWidth = canvas.getFontMetrics().stringWidth(shortcut);
|
||||||
|
int height = StudioTheme.scale(KEYCAP_SIZE);
|
||||||
|
int width = Math.max(height, textWidth + StudioTheme.scale(8));
|
||||||
|
int x = getWidth() - getInsets().right - width;
|
||||||
|
int y = (getHeight() - height) / 2;
|
||||||
|
int arc = StudioTheme.scale(KEYCAP_ARC);
|
||||||
|
canvas.setColor(StudioTheme.CONTROL_BORDER);
|
||||||
|
canvas.drawRoundRect(x, y, width - 1, height - 1, arc, arc);
|
||||||
|
canvas.setColor(StudioTheme.SECONDARY_TEXT);
|
||||||
|
int baseline = y + (height + canvas.getFontMetrics().getAscent() - canvas.getFontMetrics().getDescent()) / 2;
|
||||||
|
canvas.drawString(shortcut, x + (width - textWidth) / 2, baseline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ViewIcon(MapView view) implements Icon {
|
||||||
|
@Override
|
||||||
|
public void paintIcon(Component component, Graphics graphics, int x, int y) {
|
||||||
|
MapViewIcon.paint((Graphics2D) graphics, view, x, y, getIconWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconWidth() {
|
||||||
|
return StudioTheme.scale(RowRenderer.ICON_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconHeight() {
|
||||||
|
return getIconWidth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,7 @@ import java.awt.event.WindowAdapter;
|
|||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The studio map: one window showing the world as tiles in several views, with the palette, object and noise explorers
|
* The studio map: one window showing the world as tiles in several views, with the palette, object and noise explorers
|
||||||
@@ -141,6 +142,7 @@ public final class MapWindow implements MapCanvas.Listener {
|
|||||||
frame.add(inspectorSlot, BorderLayout.EAST);
|
frame.add(inspectorSlot, BorderLayout.EAST);
|
||||||
frame.add(statusBars, BorderLayout.SOUTH);
|
frame.add(statusBars, BorderLayout.SOUTH);
|
||||||
installShortcuts(frame.getRootPane());
|
installShortcuts(frame.getRootPane());
|
||||||
|
keepClearOfIsland(canvas::setCoveredLeftWidth);
|
||||||
frame.setSize(GuiHost.fitToScreen(StudioTheme.scaledSize(1440, 880)));
|
frame.setSize(GuiHost.fitToScreen(StudioTheme.scaledSize(1440, 880)));
|
||||||
frame.setMinimumSize(StudioTheme.scaledSize(820, 520));
|
frame.setMinimumSize(StudioTheme.scaledSize(820, 520));
|
||||||
frame.setLocationRelativeTo(null);
|
frame.setLocationRelativeTo(null);
|
||||||
@@ -260,16 +262,19 @@ public final class MapWindow implements MapCanvas.Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createObjectExplorer() {
|
private void keepClearOfIsland(IntConsumer setCoveredLeftWidth) {
|
||||||
objectExplorer = new ObjectExplorer(start.engine(), start.worldId());
|
setCoveredLeftWidth.accept(sidebarIsland.getWidth());
|
||||||
ObjectViewport viewport = objectExplorer.viewport();
|
|
||||||
viewport.setCoveredLeftWidth(sidebarIsland.getWidth());
|
|
||||||
sidebarIsland.addComponentListener(new ComponentAdapter() {
|
sidebarIsland.addComponentListener(new ComponentAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void componentResized(ComponentEvent event) {
|
public void componentResized(ComponentEvent event) {
|
||||||
viewport.setCoveredLeftWidth(sidebarIsland.getWidth());
|
setCoveredLeftWidth.accept(sidebarIsland.getWidth());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createObjectExplorer() {
|
||||||
|
objectExplorer = new ObjectExplorer(start.engine(), start.worldId());
|
||||||
|
keepClearOfIsland(objectExplorer.viewport()::setCoveredLeftWidth);
|
||||||
content.add(objectExplorer.view(), OBJECTS_CARD);
|
content.add(objectExplorer.view(), OBJECTS_CARD);
|
||||||
statusBars.add(objectExplorer.statusBar(), OBJECTS_CARD);
|
statusBars.add(objectExplorer.statusBar(), OBJECTS_CARD);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ final class StudioTheme {
|
|||||||
Map.entry("List.selectionInsets", "0,6,0,6"),
|
Map.entry("List.selectionInsets", "0,6,0,6"),
|
||||||
Map.entry("Tree.selectionArc", "6"),
|
Map.entry("Tree.selectionArc", "6"),
|
||||||
Map.entry("Tree.selectionInsets", "0,6,0,6"),
|
Map.entry("Tree.selectionInsets", "0,6,0,6"),
|
||||||
|
Map.entry("Tree.border", "0,8,0,0"),
|
||||||
Map.entry("ScrollBar.width", "10"),
|
Map.entry("ScrollBar.width", "10"),
|
||||||
Map.entry("ScrollBar.thumbArc", "999"),
|
Map.entry("ScrollBar.thumbArc", "999"),
|
||||||
Map.entry("ScrollBar.thumbInsets", "2,2,2,2"),
|
Map.entry("ScrollBar.thumbInsets", "2,2,2,2"),
|
||||||
|
|||||||
Reference in new issue
Block a user