this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

use landscape thumbnails

+84 -129
+38 -95
src/main/java/app/pane/AssetsPanel.java
··· 1 1 package app.pane; 2 2 3 + import java.awt.BorderLayout; 3 4 import java.awt.Color; 4 5 import java.awt.Cursor; 5 6 import java.awt.Dimension; ··· 22 23 import java.util.ArrayList; 23 24 import java.util.List; 24 25 26 + import javax.swing.BorderFactory; 27 + import javax.swing.Icon; 25 28 import javax.swing.ImageIcon; 26 29 import javax.swing.JLabel; 27 30 import javax.swing.JPanel; ··· 53 56 private Thread watchThread; 54 57 private List<WatchKey> watchKeys = new ArrayList<>(); 55 58 59 + private static final int ITEM_SIZE = AssetHandle.THUMBNAIL_WIDTH + 4 * 2; 60 + 56 61 public AssetsPanel() 57 62 { 58 63 setLayout(new MigLayout("ins 4, fill", "[grow]", "[pref!][grow]")); ··· 60 65 breadcrumbBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); 61 66 add(breadcrumbBar, "growx, wrap"); 62 67 63 - resultsPanel = new JPanel(new UniformGridLayout(88, 88, 2, 2)); 68 + resultsPanel = new JPanel(new UniformGridLayout(ITEM_SIZE, ITEM_SIZE, 0, 0)); 64 69 resultsPanel.addMouseListener(new MouseAdapter() { 65 70 @Override 66 71 public void mouseClicked(MouseEvent e) ··· 209 214 210 215 private JPanel createSubdirItem(String name) 211 216 { 212 - JPanel panel = createItemPanel(); 213 - 214 - JLabel icon = new JLabel(ThemedIcon.FOLDER_OPEN_24); 215 - JLabel label = new JLabel(name); 216 - label.setFont(label.getFont().deriveFont(12f)); 217 - 218 - panel.add(icon, "wrap, alignx center"); 219 - panel.add(label, "alignx center, aligny center, wmax 80"); 220 - 221 - panel.addMouseListener(new MouseAdapter() { 222 - @Override 223 - public void mouseEntered(MouseEvent e) 224 - { 225 - panel.putClientProperty("hovered", true); 226 - panel.repaint(); 227 - } 228 - 229 - @Override 230 - public void mouseExited(MouseEvent e) 231 - { 232 - panel.putClientProperty("hovered", false); 233 - panel.repaint(); 234 - } 235 - 236 - @Override 237 - public void mouseClicked(MouseEvent e) 238 - { 239 - if (e.getClickCount() == 1) { 240 - select(name, panel); 241 - } 242 - else if (e.getClickCount() == 2) { 243 - navigateTo(currentPath + name + "/"); 244 - } 245 - } 217 + JPanel panel = createItem(name, ThemedIcon.FOLDER_OPEN_24, () -> { 218 + navigateTo(currentPath + name + "/"); 246 219 }); 247 - 248 220 return panel; 249 221 } 250 222 251 223 private JPanel createAssetItem(AssetHandle asset) 252 224 { 253 - JPanel panel = createItemPanel(); 225 + JPanel panel = createItem(asset.getAssetName(), ThemedIcon.PACKAGE_24, () -> { 226 + openAsset(asset); 227 + }); 254 228 255 - JLabel icon = new JLabel(ThemedIcon.PACKAGE_24); 229 + JLabel icon = (JLabel) ((BorderLayout) panel.getLayout()).getLayoutComponent(BorderLayout.CENTER); 256 230 257 231 // Load thumbnail asynchronously 258 232 new SwingWorker<Image, Void>() { ··· 270 244 if (thumb != null) { 271 245 icon.setIcon(new ImageIcon(thumb)); 272 246 panel.revalidate(); 247 + panel.repaint(); 273 248 } 274 249 } 275 250 catch (Exception e) { ··· 278 253 } 279 254 }.execute(); 280 255 281 - JLabel name = createShadowLabel(asset.getAssetName()); 282 - 283 - panel.add(icon, "alignx center"); 284 - panel.add(name, "pos 0 null 100% (100%-4), alignx center"); 285 - panel.setComponentZOrder(name, 0); 286 - 287 256 String desc = asset.getAssetDescription(); 288 257 if (desc != null && !desc.isEmpty()) { 289 258 panel.setToolTipText(desc); 290 259 } 291 260 261 + return panel; 262 + } 263 + 264 + private JPanel createItem(String name, Icon defaultIcon, Runnable onDoubleClick) 265 + { 266 + JPanel panel = createItemPanel(); 267 + 268 + JLabel icon = new JLabel(defaultIcon); 269 + icon.setHorizontalAlignment(JLabel.CENTER); 270 + icon.setVerticalAlignment(JLabel.CENTER); 271 + 272 + JLabel label = new JLabel(name); 273 + label.setHorizontalAlignment(JLabel.CENTER); 274 + 275 + panel.add(icon, BorderLayout.CENTER); 276 + panel.add(label, BorderLayout.SOUTH); 277 + 292 278 panel.addMouseListener(new MouseAdapter() { 293 279 @Override 294 280 public void mouseEntered(MouseEvent e) ··· 308 294 public void mouseClicked(MouseEvent e) 309 295 { 310 296 if (e.getClickCount() == 1) { 311 - select(asset.getAssetName(), panel); 297 + select(name, panel); 312 298 } 313 299 else if (e.getClickCount() == 2) { 314 - openAsset(asset); 300 + onDoubleClick.run(); 315 301 } 316 302 } 317 303 }); ··· 321 307 322 308 private JPanel createItemPanel() 323 309 { 324 - JPanel panel = new JPanel(new MigLayout("ins 4, fill", "[grow]", "[grow]")) { 310 + JPanel panel = new JPanel(new BorderLayout()) { 325 311 @Override 326 312 protected void paintComponent(Graphics g) 327 313 { 328 - boolean hovered = Boolean.TRUE.equals(getClientProperty("hovered")); 329 - boolean selected = (this == selectedPanel); 330 - 331 - if (selected || hovered) { 314 + if (this == selectedPanel) { 332 315 Graphics2D g2 = (Graphics2D) g.create(); 333 316 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 334 317 335 - Color bg = UIManager.getColor("Table.selectionBackground"); 336 - if (selected) { 337 - g2.setColor(bg); 338 - } 339 - else { 340 - // Lighter for hover 341 - g2.setColor(new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), 80)); 342 - } 318 + Color bg = UIManager.getColor("Component.borderColor"); 319 + g2.setColor(bg); 343 320 g2.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8); 344 321 g2.dispose(); 345 322 } ··· 347 324 super.paintComponent(g); 348 325 } 349 326 }; 350 - panel.setPreferredSize(new Dimension(88, 88)); 327 + panel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); 328 + panel.setPreferredSize(new Dimension(ITEM_SIZE, ITEM_SIZE)); 351 329 panel.setOpaque(false); 352 330 return panel; 353 - } 354 - 355 - private JLabel createShadowLabel(String text) 356 - { 357 - return new JLabel(text) { 358 - @Override 359 - protected void paintComponent(Graphics g) 360 - { 361 - Graphics2D g2 = (Graphics2D) g.create(); 362 - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 363 - g2.setFont(getFont()); 364 - 365 - var fm = g2.getFontMetrics(); 366 - int textW = fm.stringWidth(getText()); 367 - int x = (getWidth() - textW) / 2; 368 - int y = fm.getAscent(); 369 - 370 - // Soft shadow: draw text at nearby offsets with low alpha 371 - int radius = 3; 372 - for (int dx = -radius; dx <= radius; dx++) { 373 - for (int dy = -radius; dy <= radius; dy++) { 374 - float dist = (float) Math.sqrt(dx * dx + dy * dy); 375 - if (dist > radius) 376 - continue; 377 - int alpha = (int)(40 * (1f - dist / radius)); 378 - g2.setColor(new Color(0, 0, 0, alpha)); 379 - g2.drawString(getText(), x + dx, y + dy + 1); 380 - } 381 - } 382 - 383 - g2.setColor(getForeground()); 384 - g2.drawString(getText(), x, y); 385 - g2.dispose(); 386 - } 387 - }; 388 331 } 389 332 390 333 private void openAsset(AssetHandle asset)
+22 -14
src/main/java/assets/AssetHandle.java
··· 13 13 14 14 public class AssetHandle extends File 15 15 { 16 - public static final int THUMBNAIL_SIZE = 80 * 2; 16 + public static final int THUMBNAIL_WIDTH = 80; 17 + public static final int THUMBNAIL_HEIGHT = 50; 17 18 18 19 public final File assetDir; 19 20 public final String assetPath; // relative path from assetDir ··· 68 69 69 70 private static Image createMultiResThumbnail(Image src) 70 71 { 71 - var img1x = resizeImage(src, THUMBNAIL_SIZE / 2); 72 - var img2x = resizeImage(src, THUMBNAIL_SIZE); 72 + var img1x = resizeImage(src, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); 73 + var img2x = resizeImage(src, THUMBNAIL_WIDTH * 2, THUMBNAIL_HEIGHT * 2); 73 74 return new BaseMultiResolutionImage(img1x, img2x); 74 75 } 75 76 76 - private static BufferedImage resizeImage(Image src, int targetSize) 77 + private static BufferedImage resizeImage(Image src, int maxW, int maxH) 77 78 { 78 79 int srcW = src.getWidth(null); 79 80 int srcH = src.getHeight(null); 80 - float srcRatio = (float) srcW / srcH; 81 - int w, h; 82 - if (srcRatio >= 1f) { 83 - w = targetSize; 84 - h = Math.max(1, Math.round(targetSize / srcRatio)); 81 + 82 + int dstW, dstH; 83 + boolean scalingUp = maxW > srcW || maxH > srcH; 84 + if (scalingUp) { 85 + // Integer scaling with nearest neighbour 86 + int scale = Math.max(1, Math.min(maxW / srcW, maxH / srcH)); 87 + dstW = srcW * scale; 88 + dstH = srcH * scale; 85 89 } 86 90 else { 87 - h = targetSize; 88 - w = Math.max(1, Math.round(targetSize * srcRatio)); 91 + // Fit within bounds, preserving aspect ratio 92 + float ratio = Math.min((float) maxW / srcW, (float) maxH / srcH); 93 + dstW = Math.max(1, Math.round(srcW * ratio)); 94 + dstH = Math.max(1, Math.round(srcH * ratio)); 89 95 } 90 96 91 - var bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 97 + var bi = new BufferedImage(dstW, dstH, BufferedImage.TYPE_INT_ARGB); 92 98 Graphics2D g = bi.createGraphics(); 93 - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 94 - g.drawImage(src, 0, 0, w, h, null); 99 + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 100 + scalingUp ? RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR 101 + : RenderingHints.VALUE_INTERPOLATION_BILINEAR); 102 + g.drawImage(src, 0, 0, dstW, dstH, null); 95 103 g.dispose(); 96 104 return bi; 97 105 }
+1 -1
src/main/java/assets/ui/MapAsset.java
··· 113 113 Logger.log("Capturing thumbnail for " + asset.assetPath + "...", Priority.MILESTONE); 114 114 if (editor == null) 115 115 editor = new MapEditor(false); 116 - editor.generateThumbnail(asset, thumbFile, THUMBNAIL_SIZE); 116 + editor.generateThumbnail(asset, thumbFile, THUMBNAIL_WIDTH * 2, THUMBNAIL_HEIGHT * 2); 117 117 } 118 118 } 119 119 catch (Exception e) {
+23 -19
src/main/java/game/map/editor/MapEditor.java
··· 738 738 private boolean thumbnailInitialized = false; 739 739 740 740 /** Renders a thumbnail at 2x resolution and downsamples to the given size. */ 741 - public void generateThumbnail(File mapFile, File thumbFile, int size) 741 + public void generateThumbnail(File mapFile, File thumbFile, int width, int height) 742 742 { 743 743 Map newMap = Map.loadMap(mapFile); 744 744 if (newMap == null) 745 745 return; 746 746 747 - int renderSize = size * 2; 747 + int renderWidth = width * 2; 748 + int renderHeight = height * 2; 748 749 thumbnailMode = true; 749 - thumbnailSize = renderSize; 750 + thumbnailWidth = renderWidth; 751 + thumbnailHeight = renderHeight; 750 752 openMap(newMap, true); 751 753 for (MapObject obj : getCollisionMap().colliderTree) 752 754 obj.hidden = true; ··· 816 818 float halfH = (screenMaxY - screenMinY) / 2f; 817 819 thumbnailOrthoHalfHeight = Math.max(50f, Math.min(Math.max(halfW, halfH), 5000f)); 818 820 819 - perspectiveView.resize(0, 0, renderSize, renderSize); 821 + perspectiveView.resize(0, 0, renderWidth, renderHeight); 820 822 821 823 for (int i = 0; i < 2; i++) { 822 824 step(); 823 825 glCanvas.render(); 824 826 } 825 827 826 - renderThumbnail(thumbFile, size); 828 + renderThumbnail(thumbFile, width, height); 827 829 } 828 830 829 831 public void shutdownThumbnail() ··· 3513 3515 { 3514 3516 RenderingOptions opts = new RenderingOptions(); 3515 3517 if (thumbnailMode) { 3516 - opts.canvasSizeX = thumbnailSize; 3517 - opts.canvasSizeY = thumbnailSize; 3518 + opts.canvasSizeX = thumbnailWidth; 3519 + opts.canvasSizeY = thumbnailHeight; 3518 3520 } 3519 3521 else { 3520 3522 opts.canvasSizeX = glCanvasPixelWidth(); ··· 3648 3650 obj.prepareVertexBuffers(opts); 3649 3651 } 3650 3652 3651 - private int thumbnailSize; 3653 + private int thumbnailWidth; 3654 + private int thumbnailHeight; 3652 3655 3653 3656 private void initThumbnail() 3654 3657 { ··· 3670 3673 thumbnailMode = true; 3671 3674 } 3672 3675 3673 - private void renderThumbnail(File thumbFile, int size) 3676 + private void renderThumbnail(File thumbFile, int width, int height) 3674 3677 { 3675 3678 runInContext(() -> { 3676 3679 glBindFramebuffer(GL_READ_FRAMEBUFFER, perspectiveView.getSceneFrameBuffer()); 3677 3680 glReadBuffer(GL_COLOR_ATTACHMENT0); 3678 - int renderSize = thumbnailSize; 3681 + int renderW = thumbnailWidth; 3682 + int renderH = thumbnailHeight; 3679 3683 int bpp = 4; 3680 - ByteBuffer buffer = BufferUtils.createByteBuffer(renderSize * renderSize * bpp); 3681 - glReadPixels(0, 0, renderSize, renderSize, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 3684 + ByteBuffer buffer = BufferUtils.createByteBuffer(renderW * renderH * bpp); 3685 + glReadPixels(0, 0, renderW, renderH, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 3682 3686 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 3683 3687 3684 - var renderImage = new BufferedImage(renderSize, renderSize, BufferedImage.TYPE_INT_ARGB); 3685 - for (int x = 0; x < renderSize; x++) { 3686 - for (int y = 0; y < renderSize; y++) { 3687 - int i = (x + (renderSize * y)) * bpp; 3688 + var renderImage = new BufferedImage(renderW, renderH, BufferedImage.TYPE_INT_ARGB); 3689 + for (int x = 0; x < renderW; x++) { 3690 + for (int y = 0; y < renderH; y++) { 3691 + int i = (x + (renderW * y)) * bpp; 3688 3692 int r = buffer.get(i) & 0xFF; 3689 3693 int g = buffer.get(i + 1) & 0xFF; 3690 3694 int b = buffer.get(i + 2) & 0xFF; 3691 3695 int a = buffer.get(i + 3) & 0xFF; 3692 - renderImage.setRGB(x, renderSize - (y + 1), (a << 24) | (r << 16) | (g << 8) | b); 3696 + renderImage.setRGB(x, renderH - (y + 1), (a << 24) | (r << 16) | (g << 8) | b); 3693 3697 } 3694 3698 } 3695 3699 3696 - var image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); 3700 + var image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 3697 3701 Graphics2D g = image.createGraphics(); 3698 3702 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 3699 - g.drawImage(renderImage, 0, 0, size, size, null); 3703 + g.drawImage(renderImage, 0, 0, width, height, null); 3700 3704 g.dispose(); 3701 3705 3702 3706 try {