From 111c86b37ca732dc64de59bc8648298c8a06dfe4 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 3 May 2020 18:02:41 +0200 Subject: [PATCH] new image viewer --- src/be/nikiroo/fanfix_swing/Actions.java | 16 +- .../gui/viewer/NewViewerImages.java | 247 ++++++++++++++++++ 2 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java diff --git a/src/be/nikiroo/fanfix_swing/Actions.java b/src/be/nikiroo/fanfix_swing/Actions.java index 849d3ace..5b8f0d3e 100644 --- a/src/be/nikiroo/fanfix_swing/Actions.java +++ b/src/be/nikiroo/fanfix_swing/Actions.java @@ -26,6 +26,7 @@ import be.nikiroo.fanfix.library.LocalLibrary; import be.nikiroo.fanfix_swing.gui.book.BookInfo; import be.nikiroo.fanfix_swing.gui.utils.CoverImager; import be.nikiroo.fanfix_swing.gui.utils.UiHelper; +import be.nikiroo.fanfix_swing.gui.viewer.NewViewerImages; import be.nikiroo.fanfix_swing.gui.viewer.Viewer; import be.nikiroo.utils.Progress; import be.nikiroo.utils.StringUtils; @@ -136,8 +137,15 @@ public class Actions { * the story to open */ static private void openInternal(Story story) { - Viewer viewer = new Viewer(Instance.getInstance().getLibrary(), story); - viewer.setVisible(true); + if (story.getMeta().isImageDocument()) { + NewViewerImages viewer = new NewViewerImages(story); + viewer.setVisible(true); + } else { + Viewer viewer = new Viewer(Instance.getInstance().getLibrary(), + story); + viewer.setVisible(true); + } + } /** @@ -251,13 +259,13 @@ public class Actions { try { Instance.getInstance().getLibrary().imprt(getUrl(url), pg); pg.done(); - + if (onSuccess != null) { onSuccess.run(); } } catch (IOException e) { pg.done(); - + if (e instanceof UnknownHostException) { UiHelper.error(parent, Instance.getInstance().getTransGui().getString( diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java b/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java new file mode 100644 index 00000000..4599604e --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java @@ -0,0 +1,247 @@ +package be.nikiroo.fanfix_swing.gui.viewer; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.SwingWorker; +import javax.swing.UIManager; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.bundles.StringIdGui; +import be.nikiroo.fanfix.data.Chapter; +import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.data.Paragraph; +import be.nikiroo.fanfix.data.Story; +import be.nikiroo.fanfix_swing.gui.MainFrame; +import be.nikiroo.fanfix_swing.gui.utils.UiHelper; +import be.nikiroo.utils.Image; +import be.nikiroo.utils.ui.DelayWorker; +import be.nikiroo.utils.ui.ImageUtilsAwt; +import be.nikiroo.utils.ui.ImageUtilsAwt.Rotation; +import be.nikiroo.utils.ui.UIUtils; + +/** + * An internal, Swing-based {@link Story} viewer. + *

+ * Works on both text and image document (see {@link MetaData#isImageDocument()} + * ). + * + * @author niki + */ +public class NewViewerImages extends JFrame { + private static final long serialVersionUID = 1L; + + private List images; + private int index; + + private double zoom = -1; // -1 = snap to width or height + private boolean zoomSnapWidth = true; + private Rotation rotation = Rotation.NONE; + + private JLabel area; + private JScrollPane scroll; + + private int ss; // ScrollSize + + private DelayWorker worker; + + /** + * Create a new {@link Story} viewer. + * + * @param story + * the {@link Story} to display + */ + public NewViewerImages(Story story) { + setTitle(MainFrame.trans(StringIdGui.TITLE_STORY, + story.getMeta().getLuid(), story.getMeta().getTitle())); + + setSize(800, 600); + + images = new ArrayList(); + if (!story.getMeta().isFakeCover()) { + images.add(story.getMeta().getCover()); + } + for (Chapter chap : story) { + for (Paragraph para : chap) { + Image img = para.getContentImage(); + if (img != null) { + images.add(img); + } + } + } + + worker = new DelayWorker(100); + worker.start(); + + initGui(); + display(index, Rotation.NONE); + + if (!images.isEmpty()) { + UiHelper.setFrameIcon(this, images.get(0)); + } + } + + private void initGui() { + // TODO: menu + bar + + this.setLayout(new BorderLayout()); + + ss = ((Integer) UIManager.get("ScrollBar.width")).intValue(); + + area = new JLabel(); + area.setOpaque(false); + area.setFocusable(true); + area.requestFocus(); + + scroll = UIUtils.scroll(area, true); + this.add(scroll, BorderLayout.CENTER); + + listen(); + } + + private synchronized void display(int index, final Rotation rotation) { + if (images.isEmpty()) { + return; + } + + this.rotation = rotation; + + int addW = 0; + if (scroll.getVerticalScrollBar().isVisible()) { + addW = ss; + } + + int addH = 0; + if (scroll.getHorizontalScrollBar().isVisible()) { + addH = ss; + } + + final Image img = images.get(index); + final Dimension areaSize = new Dimension( // + scroll.getViewport().getWidth() + addW, // + scroll.getViewport().getHeight() + addH// + ); + + worker.delay("display", new SwingWorker() { + @Override + protected ImageIcon doInBackground() throws Exception { + BufferedImage image = ImageUtilsAwt.fromImage(img, rotation); + BufferedImage resizedImage = ImageUtilsAwt.scaleImage(areaSize, + image, zoom, zoomSnapWidth); + + return new ImageIcon(resizedImage); + } + + @Override + protected void done() { + try { + ImageIcon img = get(); + + if (zoom > 0) { + scroll.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scroll.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + } else if (zoomSnapWidth) { + scroll.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroll.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + } else { + scroll.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scroll.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_NEVER); + } + + area.setSize(scroll.getViewport().getSize()); + area.setIcon(img); + } catch (InterruptedException e) { + Instance.getInstance().getTraceHandler().error(e); + } catch (ExecutionException e) { + Instance.getInstance().getTraceHandler().error(e); + } + } + }); + } + + private void listen() { + // TODO: mousewheel = move + // TODO: keys = move if possible, next/prev if not + area.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_SPACE + || e.getKeyCode() == KeyEvent.VK_ENTER) { + next(); + } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE + || e.getKeyCode() == KeyEvent.VK_LEFT + || e.getKeyCode() == KeyEvent.VK_UP) { + previous(); + } else if (e.getKeyCode() == KeyEvent.VK_HOME) { + first(); + } else if (e.getKeyCode() == KeyEvent.VK_END) { + last(); + } + } + }); + area.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + next(); + } else { + previous(); + } + } + }); + area.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + display(index, rotation); + } + }); + } + + private synchronized void next() { + index++; + if (index >= images.size()) { + index = images.size(); + } + + display(index, Rotation.NONE); + } + + private synchronized void previous() { + index--; + if (index < 0) { + index = 0; + } + + display(index, Rotation.NONE); + } + + private synchronized void first() { + index = 0; + display(index, Rotation.NONE); + } + + private synchronized void last() { + index = images.size(); + display(index, Rotation.NONE); + } +} -- 2.27.0