biskuteri-cafe-JKomasto2/ImageWindow.java
Snowyfox e6fea4c061 Fixed bug when redraft makes no changes
(Before this, JKomasto and sometimes the Mastodon web client would get '411 Record Not Found' when submitting the same text after deleting and redrafting. Presumably the Mastodon server caches both whether an idempotency key was fulfilled and which post it leads to, and for some reason it looks up the second and fails.)
2022-05-31 03:39:56 -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);
}
}