new image viewer
authorNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 16:02:41 +0000 (18:02 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 16:02:41 +0000 (18:02 +0200)
src/be/nikiroo/fanfix_swing/Actions.java
src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java [new file with mode: 0644]

index 849d3ace1bdef84430b7f6c5c62e6fd79d7c4edf..5b8f0d3eb65baa8e4e2350a79e9dc47fef68a2b7 100644 (file)
@@ -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 (file)
index 0000000..4599604
--- /dev/null
@@ -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.
+ * <p>
+ * 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<Image> 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<Image>();
+               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<ImageIcon, Void>() {
+                       @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);
+       }
+}