jexer/examples/JexerImageViewer.java

316 lines
10 KiB
Java
Raw Permalink Normal View History

2019-02-23 14:27:33 -07:00
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import jexer.TAction;
import jexer.TApplication;
import jexer.TDesktop;
import jexer.TDirectoryList;
import jexer.TImage;
import jexer.backend.SwingTerminal;
import jexer.bits.CellAttributes;
import jexer.bits.GraphicsChars;
import jexer.event.TKeypressEvent;
import jexer.event.TResizeEvent;
import jexer.menu.TMenu;
import jexer.ttree.TDirectoryTreeItem;
import jexer.ttree.TTreeItem;
import jexer.ttree.TTreeViewWidget;
import static jexer.TKeypress.*;
/**
* Implements a simple image thumbnail file viewer. Much of this code was
* stripped down from TFileOpenBox.
*/
public class JexerImageViewer extends TApplication {
/**
* Main entry point.
*/
public static void main(String [] args) throws Exception {
JexerImageViewer app = new JexerImageViewer();
(new Thread(app)).start();
}
/**
* Public constructor chooses the ECMA-48 / Xterm backend.
*/
public JexerImageViewer() throws Exception {
super(BackendType.XTERM);
// The stock tool menu has items for redrawing the screen, opening
// images, and (when using the Swing backend) setting the font.
addToolMenu();
// We will have one menu containing a mix of new and stock commands
TMenu fileMenu = addMenu("&File");
// Stock commands: a new shell, exit program.
fileMenu.addDefaultItem(TMenu.MID_SHELL);
fileMenu.addSeparator();
fileMenu.addDefaultItem(TMenu.MID_EXIT);
// Filter the files list to support image suffixes only.
List<String> filters = new ArrayList<String>();
filters.add("^.*\\.[Jj][Pp][Gg]$");
filters.add("^.*\\.[Jj][Pp][Ee][Gg]$");
filters.add("^.*\\.[Pp][Nn][Gg]$");
filters.add("^.*\\.[Gg][Ii][Ff]$");
filters.add("^.*\\.[Bb][Mm][Pp]$");
setDesktop(new ImageViewerDesktop(this, ".", filters));
}
}
/**
* The desktop contains a tree view on the left, list of files on the top
* right, and image view on the bottom right.
*/
class ImageViewerDesktop extends TDesktop {
/**
* The left-side tree view pane.
*/
private TTreeViewWidget treeView;
/**
* The data behind treeView.
*/
private TDirectoryTreeItem treeViewRoot;
/**
* The top-right-side directory list pane.
*/
private TDirectoryList directoryList;
/**
* The bottom-right-side image pane.
*/
private TImage imageWidget;
/**
* Public constructor.
*
* @param application the TApplication that manages this window
* @param path path of selected file
* @param filters a list of strings that files must match to be displayed
* @throws IOException of a java.io operation throws
*/
public ImageViewerDesktop(final TApplication application, final String path,
final List<String> filters) throws IOException {
super(application);
setActive(true);
// Add directory treeView
2019-08-23 03:39:03 -06:00
treeView = addTreeViewWidget(0, 0, getWidth() / 2, getHeight(),
2019-02-23 14:27:33 -07:00
new TAction() {
public void DO() {
TTreeItem item = treeView.getSelected();
File selectedDir = ((TDirectoryTreeItem) item).getFile();
try {
directoryList.setPath(selectedDir.getCanonicalPath());
if (directoryList.getList().size() > 0) {
setThumbnail(directoryList.getPath());
} else {
if (imageWidget != null) {
getChildren().remove(imageWidget);
}
imageWidget = null;
}
activate(treeView);
} catch (IOException e) {
// If the backend is Swing, we can emit the stack
// trace to stderr. Otherwise, just squash it.
if (getScreen() instanceof SwingTerminal) {
e.printStackTrace();
}
}
}
}
);
treeViewRoot = new TDirectoryTreeItem(treeView, path, true);
// Add directory files list
directoryList = addDirectoryList(path, getWidth() / 2 + 1, 0,
getWidth() / 2 - 1, getHeight() / 2,
new TAction() {
public void DO() {
setThumbnail(directoryList.getPath());
}
},
new TAction() {
public void DO() {
setThumbnail(directoryList.getPath());
}
},
filters);
if (directoryList.getList().size() > 0) {
activate(directoryList);
setThumbnail(directoryList.getPath());
} else {
activate(treeView);
}
}
/**
* Handle window/screen resize events.
*
* @param event resize event
*/
@Override
public void onResize(final TResizeEvent event) {
// Resize the tree and list
treeView.setY(1);
treeView.setWidth(getWidth() / 2);
treeView.setHeight(getHeight() - 1);
2021-12-19 10:57:05 -07:00
treeView.onResize(new TResizeEvent(event.getBackend(),
TResizeEvent.Type.WIDGET,
2019-02-23 14:27:33 -07:00
treeView.getWidth(),
treeView.getHeight()));
2021-12-19 10:57:05 -07:00
treeView.getTreeView().onResize(new TResizeEvent(event.getBackend(),
TResizeEvent.Type.WIDGET,
2019-02-23 14:27:33 -07:00
treeView.getWidth() - 1,
treeView.getHeight() - 1));
directoryList.setX(getWidth() / 2 + 1);
directoryList.setY(1);
directoryList.setWidth(getWidth() / 2 - 1);
directoryList.setHeight(getHeight() / 2 - 1);
2021-12-19 10:57:05 -07:00
directoryList.onResize(new TResizeEvent(event.getBackend(),
TResizeEvent.Type.WIDGET,
2019-02-23 14:27:33 -07:00
directoryList.getWidth(),
directoryList.getHeight()));
// Recreate the image
if (imageWidget != null) {
getChildren().remove(imageWidget);
}
imageWidget = null;
if (directoryList.getList().size() > 0) {
activate(directoryList);
setThumbnail(directoryList.getPath());
} else {
activate(treeView);
}
}
/**
* Handle keystrokes.
*
* @param keypress keystroke event
*/
@Override
public void onKeypress(final TKeypressEvent keypress) {
if (treeView.isActive() || directoryList.isActive()) {
if ((keypress.equals(kbEnter))
|| (keypress.equals(kbUp))
|| (keypress.equals(kbDown))
|| (keypress.equals(kbPgUp))
|| (keypress.equals(kbPgDn))
|| (keypress.equals(kbHome))
|| (keypress.equals(kbEnd))
) {
// Tree view will be changing, update the directory list.
super.onKeypress(keypress);
// This is the same action as treeView's enter.
TTreeItem item = treeView.getSelected();
File selectedDir = ((TDirectoryTreeItem) item).getFile();
try {
if (treeView.isActive()) {
directoryList.setPath(selectedDir.getCanonicalPath());
}
if (directoryList.getList().size() > 0) {
activate(directoryList);
setThumbnail(directoryList.getPath());
} else {
if (imageWidget != null) {
getChildren().remove(imageWidget);
}
imageWidget = null;
activate(treeView);
}
} catch (IOException e) {
// If the backend is Swing, we can emit the stack trace
// to stderr. Otherwise, just squash it.
if (getScreen() instanceof SwingTerminal) {
e.printStackTrace();
}
}
return;
}
}
// Pass to my parent
super.onKeypress(keypress);
}
/**
* Draw me on screen.
*/
@Override
public void draw() {
CellAttributes background = getTheme().getColor("tdesktop.background");
putAll(' ', background);
vLineXY(getWidth() / 2, 0, getHeight(),
GraphicsChars.WINDOW_SIDE, getBackground());
hLineXY(getWidth() / 2, getHeight() / 2, (getWidth() + 1) / 2,
GraphicsChars.WINDOW_TOP, getBackground());
putCharXY(getWidth() / 2, getHeight() / 2,
GraphicsChars.WINDOW_LEFT_TEE, getBackground());
}
/**
* Set the image thumbnail.
*
* @param file the image file
*/
private void setThumbnail(final File file) {
if (file == null) {
return;
}
if (!file.exists() || !file.isFile()) {
return;
}
BufferedImage image = null;
try {
image = ImageIO.read(file);
} catch (IOException e) {
// If the backend is Swing, we can emit the stack trace to
// stderr. Otherwise, just squash it.
if (getScreen() instanceof SwingTerminal) {
e.printStackTrace();
}
return;
}
if (imageWidget != null) {
getChildren().remove(imageWidget);
}
int width = getWidth() / 2 - 1;
int height = getHeight() / 2 - 1;
imageWidget = new TImage(this, getWidth() - width,
getHeight() - height, width, height, image, 0, 0, null);
2019-08-02 13:00:14 -06:00
// Resize the image to fit within the pane.
imageWidget.setScaleType(TImage.Scale.SCALE);
2019-02-23 14:27:33 -07:00
imageWidget.setActive(false);
activate(directoryList);
}
}