/* copyright This file is part of JKomasto2. Written in 2022 by Usawashi 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 . copyright */ import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JButton; import javax.swing.ImageIcon; import java.awt.Graphics; import java.awt.Image; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.BorderLayout; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelListener; import java.awt.event.MouseWheelEvent; import java.awt.Image; import java.net.URL; import java.net.MalformedURLException; class ImageWindow extends JFrame { private Attachment[] attachments; private int offset; // - -%- - private ImageComponent display; // ---%-@-%--- public synchronized void showAttachments(Attachment[] attachments) { this.attachments = attachments; if (attachments.length == 0) { display.setImage(null); display.setNext(null); display.setPrev(null); display.repaint(); return; } toImage(offset = 0); } public void toNextImage() { if (attachments.length == 0) return; assert offset < attachments.length - 1; toImage(++offset); } public void toPrevImage() { if (attachments.length == 0) return; assert offset > 0; toImage(--offset); } // - -%- - private synchronized void toImage(int offset) { int last = attachments.length - 1; assert offset >= 0; assert offset < attachments.length; Attachment prev, curr, next; curr = attachments[offset]; next = offset < last ? attachments[offset + 1] : null; prev = offset > 0 ? attachments[offset - 1] : null; display.setImage(curr.image); display.setNext(next != null ? next.image : null); display.setPrev(prev != null ? prev.image : null); if (!curr.type.equals("image")) display.setToolTipText( display.getToolTipText() + "\n(Media is of type '" + curr.type + "')" ); repaint(); } // ---%-@-%--- ImageWindow() { setDefaultCloseOperation(DISPOSE_ON_CLOSE); setSize(600, 600); display = new ImageComponent(this); showAttachments(new Attachment[0]); setContentPane(display); } } class ImageComponent extends JPanel implements ActionListener, MouseListener, MouseMotionListener, MouseWheelListener { private ImageWindow primaire; // - -%- - private Image image, prevImage, nextImage; private JPanel buttonArea; private JButton prev, next, toggle; private boolean scaleImage; private int xOffset, yOffset, zoomLevel; private int dragX, dragY, xPOffset, yPOffset; // ---%-@-%--- public void setImage(Image image) { this.image = image; if (image != null) { Object p = image.getProperty("comment", this); String desc = p instanceof String ? (String)p : null; setToolTipText(desc); } xOffset = yOffset = xPOffset = yPOffset = 0; zoomLevel = 100; } public void setPrev(Image image) { prev.setEnabled(image != null); prev.setText(image == null ? "<" : ""); prev.setIcon(toIcon(image)); } public void setNext(Image image) { next.setEnabled(image != null); next.setText(image == null ? ">" : ""); next.setIcon(toIcon(image)); } // - -%- - public void actionPerformed(ActionEvent eA) { if (eA.getSource() == prev) primaire.toPrevImage(); if (eA.getSource() == next) primaire.toNextImage(); if (eA.getSource() == toggle) { scaleImage = !scaleImage; if (scaleImage) toggle.setText("Show unscaled"); else toggle.setText("Show scaled to window"); setImage(this.image); repaint(); } } public void mousePressed(MouseEvent eM) { dragX = eM.getX(); dragY = eM.getY(); } public void mouseDragged(MouseEvent eM) { int dx = eM.getX() - dragX; int dy = eM.getY() - dragY; xPOffset = dx; yPOffset = dy; repaint(); } public void mouseReleased(MouseEvent eM) { xOffset += xPOffset; yOffset += yPOffset; xPOffset = yPOffset = 0; } public void mouseWheelMoved(MouseWheelEvent eMw) { zoomLevel += 10 * -eMw.getUnitsToScroll(); if (zoomLevel < 50) zoomLevel = 50; if (zoomLevel > 400) zoomLevel = 400; repaint(); } public void mouseEntered(MouseEvent eM) { } public void mouseExited(MouseEvent eM) { } public void mouseClicked(MouseEvent eM) { } public void mouseMoved(MouseEvent eM) { } // - -%- - private static ImageIcon toIcon(Image image) { if (image == null) return null; return new ImageIcon(image); } // ---%-@-%--- private class Painter extends JPanel { protected void paintComponent(Graphics g) { if (image == null) { String str = "(There are no images being displayed.)"; FontMetrics fm = g.getFontMetrics(); int x = (getWidth() - fm.stringWidth(str)) / 2; int y = (getHeight() + fm.getHeight()) / 2; g.drawString(str, x, y); return; } int wo = image.getWidth(this); int ho = image.getHeight(this); int wn, hn; if (wo > ho) { wn = scaleImage ? getWidth() : wo; hn = ho * wn / wo; } else { hn = scaleImage ? getHeight() : ho; wn = wo * hn / ho; } wn = wn * zoomLevel / 100; hn = hn * zoomLevel / 100; int x = (getWidth() - wn) / 2; int y = (getHeight() - hn) / 2; x += xOffset + xPOffset; y += yOffset + yPOffset; g.drawImage(image, x, y, wn, hn, this); } } // ---%-@-%--- ImageComponent(ImageWindow primaire) { this.primaire = primaire; Dimension BUTTON_SIZE = new Dimension(48, 48); setOpaque(false); scaleImage = true; zoomLevel = 100; prev = new JButton(); toggle = new JButton("Show unscaled"); next = new JButton(); prev.setPreferredSize(BUTTON_SIZE); next.setPreferredSize(BUTTON_SIZE); prev.addActionListener(this); toggle.addActionListener(this); next.addActionListener(this); buttonArea = new JPanel(); buttonArea.setOpaque(false); buttonArea.add(prev); buttonArea.add(toggle); buttonArea.add(next); setPrev(null); setNext(null); setLayout(new BorderLayout()); add(buttonArea, BorderLayout.SOUTH); add(new Painter(), BorderLayout.CENTER); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); } }