From: Niki Roo Date: Sun, 3 May 2020 20:15:15 +0000 (+0200) Subject: Fix Image Viewer X-Git-Tag: fanfix-swing-1.1.1~7 X-Git-Url: https://git.nikiroo.be/?a=commitdiff_plain;h=550fbf32f87c73e9704a8125bf7dc85c9b6ffbad;p=fanfix-swing.git Fix Image Viewer --- diff --git a/libs/famfamfam_silk_icons_v013.zip b/libs/famfamfam_silk_icons_v013.zip new file mode 100644 index 00000000..67fa2bab Binary files /dev/null and b/libs/famfamfam_silk_icons_v013.zip differ diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java b/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java index cfc25822..e8b3d560 100644 --- a/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/NewViewerImages.java @@ -4,6 +4,8 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyAdapter; @@ -15,20 +17,30 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; +import javax.swing.BorderFactory; +import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JToolBar; import javax.swing.SwingWorker; 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.fanfix_swing.images.IconGenerator; +import be.nikiroo.fanfix_swing.images.IconGenerator.Icon; +import be.nikiroo.fanfix_swing.images.IconGenerator.Size; import be.nikiroo.utils.Image; import be.nikiroo.utils.ui.DelayWorker; import be.nikiroo.utils.ui.ImageUtilsAwt; @@ -38,23 +50,73 @@ import be.nikiroo.utils.ui.UIUtils; /** * An internal, Swing-based {@link Story} viewer. *

- * Works on both text and image document (see {@link MetaData#isImageDocument()} - * ). + * Only useful for images document. * * @author niki */ public class NewViewerImages extends JFrame { + private enum ZoomLevel { + FIT_TO_WIDTH(-1, true), // + FIT_TO_HEIGHT(-1, false), // + ACTUAL_SIZE(1, true), // + HALF_SIZE(0.5, true), // + DOUBLE_SIZE(2, true),// + ; + + public final double zoom; + public final boolean zoomSnapWidth; + + private ZoomLevel(double zoom, boolean zoomSnapWidth) { + this.zoom = zoom; + this.zoomSnapWidth = zoomSnapWidth; + } + + @Override + public String toString() { + switch (this) { + case FIT_TO_WIDTH: + return "Fit to width"; + case FIT_TO_HEIGHT: + return "Fit to height"; + case ACTUAL_SIZE: + return "Actual size"; + case HALF_SIZE: + return "Half size"; + case DOUBLE_SIZE: + return "Double size"; + } + return super.toString(); + } + + static ZoomLevel[] values(boolean orderedSelection) { + if (orderedSelection) { + return new ZoomLevel[] { // + FIT_TO_WIDTH, // + FIT_TO_HEIGHT, // + ACTUAL_SIZE, // + HALF_SIZE, // + DOUBLE_SIZE,// + }; + } + + return values(); + } + } + private static final long serialVersionUID = 1L; private List images; private int index; private double zoom = -1; // -1 = snap to width or height + private double currentZoom = 1; // used to go from snap to + or - private boolean zoomSnapWidth = true; private Rotation rotation = Rotation.NONE; private JLabel area; private JScrollPane scroll; + private JTextField page; + private DefaultComboBoxModel zoomBoxModel; private DelayWorker worker; @@ -95,27 +157,252 @@ public class NewViewerImages extends JFrame { } private void initGui() { - // TODO: menu + bar with all the options - this.setLayout(new BorderLayout()); + this.add(createToolBar(), BorderLayout.NORTH); area = new JLabel(); + area.setHorizontalAlignment(JLabel.CENTER); area.setOpaque(false); area.setFocusable(true); - area.requestFocus(); scroll = UIUtils.scroll(area, true); this.add(scroll, BorderLayout.CENTER); + area.requestFocus(); + listen(); } + private JToolBar createToolBar() { + JToolBar toolBar = new JToolBar(); + + // Page navigation + JButton first = new JButton( + IconGenerator.get(Icon.arrow_double_left, Size.x32)); + first.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + first(); + } + }); + + JButton previous = new JButton( + IconGenerator.get(Icon.arrow_left, Size.x32)); + previous.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + previous(); + } + }); + + page = new JTextField("1"); + page.setPreferredSize(new Dimension(page.getPreferredSize().width * 2, + page.getPreferredSize().height)); + page.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + int pageNb = Integer.parseInt(page.getText()); + pageNb--; + if (pageNb < 0 || pageNb >= images.size()) { + throw new NumberFormatException("invalid"); + } + display(pageNb, rotation, true); + } catch (NumberFormatException nfe) { + page.setText(Integer.toString(index + 1)); + } + } + }); + + JLabel maxPage = new JLabel(" of " + images.size()); + + JButton next = new JButton( + IconGenerator.get(Icon.arrow_right, Size.x32)); + next.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + next(); + } + }); + + JButton last = new JButton( + IconGenerator.get(Icon.arrow_double_right, Size.x32)); + last.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + last(); + } + }); + + // Rotate + JButton left = new JButton(IconGenerator.get(Icon.turn_left, Size.x32)); + left.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + switch (rotation) { + case NONE: + display(index, Rotation.LEFT, true); + break; + case LEFT: + display(index, Rotation.UTURN, true); + break; + case RIGHT: + display(index, Rotation.NONE, true); + break; + case UTURN: + display(index, Rotation.RIGHT, true); + break; + } + } + }); + + JButton right = new JButton( + IconGenerator.get(Icon.turn_right, Size.x32)); + right.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + switch (rotation) { + case NONE: + display(index, Rotation.RIGHT, true); + break; + case LEFT: + display(index, Rotation.NONE, true); + break; + case RIGHT: + display(index, Rotation.UTURN, true); + break; + case UTURN: + display(index, Rotation.LEFT, true); + break; + } + } + }); + + // Zoom + + JButton zoomIn = new JButton(IconGenerator.get(Icon.zoom_in, Size.x32)); + zoomIn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + double newZoom = currentZoom + (currentZoom < 0.1 ? 0.01 : 0.1); + if (newZoom > 0.1) { + newZoom = Math.round(newZoom * 10.0) / 10.0; // snap to 10% + } else { + newZoom = Math.round(newZoom * 100.0) / 100.0; // snap to 1% + } + setZoom(newZoom, zoomSnapWidth); + } + }); + + zoomBoxModel = new DefaultComboBoxModel( + ZoomLevel.values(true)); + JComboBox zoomBox = new JComboBox(zoomBoxModel); + zoomBox.setEditable(true); + zoomBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Object selected = zoomBoxModel.getSelectedItem(); + + if (selected == null) { + return; + } + + if (selected instanceof ZoomLevel) { + ZoomLevel selectedZoomLevel = (ZoomLevel) selected; + setZoom(selectedZoomLevel.zoom, + selectedZoomLevel.zoomSnapWidth); + return; + } + + String selectedString = selected.toString(); + selectedString = selectedString.trim(); + if (selectedString.endsWith("%")) { + selectedString = selectedString + .substring(0, selectedString.length() - 1).trim(); + } + + try { + boolean newZoomSnapWidth = zoomSnapWidth; + int pc = Integer.parseInt(selectedString); + if (pc <= 0) { + throw new NumberFormatException("invalid"); + } + + setZoom(pc / 100.0, newZoomSnapWidth); + } catch (NumberFormatException nfe) { + } + } + }); + + JButton zoomOut = new JButton( + IconGenerator.get(Icon.zoom_out, Size.x32)); + zoomOut.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + double newZoom = currentZoom + - (currentZoom > 0.19 ? 0.1 : 0.01); + if (newZoom < 0.01) + newZoom = 0.01; + if (newZoom > 0.1) { + newZoom = Math.round(newZoom * 10.0) / 10.0; // snap to 10% + } else { + newZoom = Math.round(newZoom * 100.0) / 100.0; // snap to 1% + } + setZoom(newZoom, zoomSnapWidth); + } + + }); + + // Add to toolbar + + toolBar.add(first); + toolBar.add(previous); + toolBar.add(page); + toolBar.add(maxPage); + toolBar.add(next); + toolBar.add(last); + + toolBar.add(sep()); + + toolBar.add(left); + toolBar.add(right); + + toolBar.add(sep()); + + toolBar.add(zoomIn); + toolBar.add(zoomBox); + toolBar.add(zoomOut); + + return toolBar; + } + + private JComponent sep() { + JComponent sep = new JPanel(); + sep.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + return sep; + } + + private void setZoom(double newZoom, boolean newZoomSnapWidth) { + if (newZoom > 0) { + zoomBoxModel.setSelectedItem( + Integer.toString((int) Math.round(newZoom * 100)) + " %"); + } + + zoom = newZoom; + zoomSnapWidth = newZoomSnapWidth; + display(index, rotation, true); + } + private synchronized void display(int index, final Rotation rotation, final boolean resetScroll) { if (images.isEmpty()) { return; } + // So we can use the keyboard navigation even after a toolbar click + area.requestFocus(); + this.rotation = rotation; final Image img = images.get(index); @@ -133,6 +420,9 @@ public class NewViewerImages extends JFrame { BufferedImage resizedImage = ImageUtilsAwt.scaleImage( areaSize, image, zoom, zoomSnapWidth); + currentZoom = (1.0 * resizedImage.getWidth()) + / image.getWidth(); + return new ImageIcon(resizedImage); } @@ -242,6 +532,7 @@ public class NewViewerImages extends JFrame { public void mouseReleased(MouseEvent e) { super.mouseReleased(e); origin[0] = null; + area.requestFocus(); } @Override @@ -266,7 +557,7 @@ public class NewViewerImages extends JFrame { } } }); - area.addComponentListener(new ComponentAdapter() { + this.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { display(index, rotation, false); @@ -290,6 +581,7 @@ public class NewViewerImages extends JFrame { if (index >= images.size()) { index = images.size() - 1; } else { + updatePage(); display(index, Rotation.NONE, true); } } @@ -299,17 +591,24 @@ public class NewViewerImages extends JFrame { if (index < 0) { index = 0; } else { + updatePage(); display(index, Rotation.NONE, true); } } private synchronized void first() { index = 0; + updatePage(); display(index, Rotation.NONE, true); } private synchronized void last() { index = images.size() - 1; + updatePage(); display(index, Rotation.NONE, true); } + + private void updatePage() { + page.setText(Integer.toString(index + 1)); + } } diff --git a/src/be/nikiroo/fanfix_swing/images/IconGenerator.java b/src/be/nikiroo/fanfix_swing/images/IconGenerator.java index 00677745..49529703 100644 --- a/src/be/nikiroo/fanfix_swing/images/IconGenerator.java +++ b/src/be/nikiroo/fanfix_swing/images/IconGenerator.java @@ -29,12 +29,24 @@ public class IconGenerator { unknown, /** A small, left-pointed arrow */ arrow_left, + /** A small, double left-pointed arrow */ + arrow_double_left, /** A small, right-pointed arrow */ arrow_right, + /** A small, double right-pointed arrow */ + arrow_double_right, /** A small, up-pointed arrow */ arrow_up, /** A small, down-pointed arrow */ arrow_down, + /** A "turn left" icon */ + turn_left, + /** A "turn right" icon */ + turn_right, + /** A zoom in icon */ + zoom_in, + /** A zoom out icon */ + zoom_out, /** An empty (transparent) icon */ empty, /** An icon for the program */ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left-16x16.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-16x16.png new file mode 100644 index 00000000..32add32e Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left-24x24.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-24x24.png new file mode 100644 index 00000000..bb2de55b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left-32x32.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-32x32.png new file mode 100644 index 00000000..1be1c66a Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left-64x64.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-64x64.png new file mode 100644 index 00000000..ca2cd58a Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left-8x8.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-8x8.png new file mode 100644 index 00000000..3c6ae51b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_left.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_left.png new file mode 100644 index 00000000..268cd61d Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_left.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right-16x16.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-16x16.png new file mode 100644 index 00000000..21156025 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right-24x24.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-24x24.png new file mode 100644 index 00000000..a7900cd8 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right-32x32.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-32x32.png new file mode 100644 index 00000000..e1e621f7 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right-64x64.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-64x64.png new file mode 100644 index 00000000..7e174011 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right-8x8.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-8x8.png new file mode 100644 index 00000000..42151a1b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/arrow_double_right.png b/src/be/nikiroo/fanfix_swing/images/arrow_double_right.png new file mode 100644 index 00000000..b3d09d1d Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/arrow_double_right.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left-16x16.png b/src/be/nikiroo/fanfix_swing/images/turn_left-16x16.png new file mode 100644 index 00000000..463d60db Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left-24x24.png b/src/be/nikiroo/fanfix_swing/images/turn_left-24x24.png new file mode 100644 index 00000000..007f4546 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left-32x32.png b/src/be/nikiroo/fanfix_swing/images/turn_left-32x32.png new file mode 100644 index 00000000..1349ba1b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left-64x64.png b/src/be/nikiroo/fanfix_swing/images/turn_left-64x64.png new file mode 100644 index 00000000..5034417c Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left-8x8.png b/src/be/nikiroo/fanfix_swing/images/turn_left-8x8.png new file mode 100644 index 00000000..82808ac9 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_left.png b/src/be/nikiroo/fanfix_swing/images/turn_left.png new file mode 100644 index 00000000..a3d6c9e3 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_left.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right-16x16.png b/src/be/nikiroo/fanfix_swing/images/turn_right-16x16.png new file mode 100644 index 00000000..a14d1044 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right-24x24.png b/src/be/nikiroo/fanfix_swing/images/turn_right-24x24.png new file mode 100644 index 00000000..756aee8b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right-32x32.png b/src/be/nikiroo/fanfix_swing/images/turn_right-32x32.png new file mode 100644 index 00000000..38017ee5 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right-64x64.png b/src/be/nikiroo/fanfix_swing/images/turn_right-64x64.png new file mode 100644 index 00000000..4be73e7f Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right-8x8.png b/src/be/nikiroo/fanfix_swing/images/turn_right-8x8.png new file mode 100644 index 00000000..d6e48038 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/turn_right.png b/src/be/nikiroo/fanfix_swing/images/turn_right.png new file mode 100644 index 00000000..629f20d6 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/turn_right.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in-16x16.png b/src/be/nikiroo/fanfix_swing/images/zoom_in-16x16.png new file mode 100644 index 00000000..6136ccd9 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in-24x24.png b/src/be/nikiroo/fanfix_swing/images/zoom_in-24x24.png new file mode 100644 index 00000000..8bb8da7e Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in-32x32.png b/src/be/nikiroo/fanfix_swing/images/zoom_in-32x32.png new file mode 100644 index 00000000..1804e70b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in-64x64.png b/src/be/nikiroo/fanfix_swing/images/zoom_in-64x64.png new file mode 100644 index 00000000..af46e87e Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in-8x8.png b/src/be/nikiroo/fanfix_swing/images/zoom_in-8x8.png new file mode 100644 index 00000000..6f693ea1 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_in.png b/src/be/nikiroo/fanfix_swing/images/zoom_in.png new file mode 100644 index 00000000..cdf0a52f Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_in.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out-16x16.png b/src/be/nikiroo/fanfix_swing/images/zoom_out-16x16.png new file mode 100644 index 00000000..977de6ca Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out-16x16.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out-24x24.png b/src/be/nikiroo/fanfix_swing/images/zoom_out-24x24.png new file mode 100644 index 00000000..b4576f5b Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out-24x24.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out-32x32.png b/src/be/nikiroo/fanfix_swing/images/zoom_out-32x32.png new file mode 100644 index 00000000..0e75bc62 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out-32x32.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out-64x64.png b/src/be/nikiroo/fanfix_swing/images/zoom_out-64x64.png new file mode 100644 index 00000000..b87410d3 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out-64x64.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out-8x8.png b/src/be/nikiroo/fanfix_swing/images/zoom_out-8x8.png new file mode 100644 index 00000000..722aefb4 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out-8x8.png differ diff --git a/src/be/nikiroo/fanfix_swing/images/zoom_out.png b/src/be/nikiroo/fanfix_swing/images/zoom_out.png new file mode 100644 index 00000000..07bf98a7 Binary files /dev/null and b/src/be/nikiroo/fanfix_swing/images/zoom_out.png differ