biskuteri-cafe-JKomasto2/ImageWindow.java
Snowyfox 775faa0bcc Fixed window updater thread issue (seemingly).
Better support for multithreading.
Fixed notifications window refresh bug.
Fixed autoview window bug (temporary scrollpane doesn't reset scroll position)
2022-05-06 16:34:22 -04:00

325 lines
6.0 KiB
Java

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);
}
}