boofcv.gui.BoofSwingUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boofcv-swing Show documentation
Show all versions of boofcv-swing Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.gui;
import boofcv.BoofVerbose;
import boofcv.abst.geo.bundle.SceneStructureMetric;
import boofcv.alg.cloud.PointCloudReader;
import boofcv.core.image.ConvertImage;
import boofcv.gui.dialogs.FilePreviewChooser;
import boofcv.gui.dialogs.OpenImageSetDialog;
import boofcv.gui.dialogs.OpenStereoSequencesChooser;
import boofcv.gui.settings.GlobalDemoSettings;
import boofcv.io.image.ConvertImageMisc;
import boofcv.io.image.UtilImageIO;
import boofcv.io.points.PointCloudIO;
import boofcv.misc.BoofLambdas;
import boofcv.misc.BoofMiscOps;
import boofcv.struct.Point3dRgbI_F64;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.GrayU16;
import boofcv.struct.image.GrayU8;
import boofcv.struct.image.ImageGray;
import boofcv.visualize.PointCloudViewer;
import georegression.struct.point.Point3D_F64;
import georegression.struct.se.Se3_F64;
import georegression.transform.se.SePointOps_F64;
import org.apache.commons.io.FilenameUtils;
import org.ddogleg.struct.DogArray;
import org.ddogleg.struct.VerbosePrint;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.NumberFormatter;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.List;
import java.util.*;
import java.util.prefs.Preferences;
public class BoofSwingUtil {
public static final String KEY_RECENT_FILES = "RecentFiles";
public static final String KEY_PREVIOUS_SELECTION = "PreviouslySelected";
public static final String KEY_PREVIOUS_DIRECTORY = "PreviousDirectory";
public static final double MIN_ZOOM = 0.01;
public static final double MAX_ZOOM = 50;
/**
* Standard initialization of Swing for applications
*/
public static void initializeSwing() {
try {
// In Mac OS X Display the menubar in the correct location
System.setProperty("apple.laf.useScreenMenuBar", "true");
// smoother font
System.setProperty("apple.awt.textantialiasing", "true");
} catch (Exception ignore) {
}
// If the default layout manager tabbed panes will get smaller and smaller since it has a border
Insets insets = UIManager.getInsets("TabbedPane.contentBorderInsets");
insets.bottom = 0; // because the sides are now mangled it looks better without the bottom border too
insets.left = 0;
insets.right = 0;
UIManager.put("TabbedPane.contentBorderInsets", insets);
GlobalDemoSettings.SETTINGS.changeTheme();
}
public static void setVerboseWithDemoSettings( VerbosePrint v ) {
if (GlobalDemoSettings.SETTINGS.verboseRecursive)
v.setVerbose(System.out, BoofMiscOps.hashSet(BoofVerbose.RECURSIVE));
else
v.setVerbose(null, null);
}
public static boolean isRightClick( MouseEvent e ) {
return (e.getButton() == MouseEvent.BUTTON3 ||
(System.getProperty("os.name").contains("Mac OS X") &&
(e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 &&
(e.getModifiers() & InputEvent.CTRL_MASK) != 0));
}
public static boolean isMiddleMouseButton( MouseEvent e ) {
boolean clicked = SwingUtilities.isMiddleMouseButton(e);
// This is for Mac OS X. Checks to see if control-command are held down with the mouse press
clicked |= e.isControlDown() && ((e.getModifiersEx() & 256) != 0);
return clicked;
}
public static double mouseWheelImageZoom( double scale, MouseWheelEvent e ) {
if (e.getWheelRotation() > 0) {
scale *= e.getWheelRotation()*1.1;
} else if (e.getWheelRotation() < 0) {
scale /= -e.getWheelRotation()*1.1;
}
return scale;
}
public static void recursiveEnable( JComponent panel, Boolean isEnabled ) {
panel.setEnabled(isEnabled);
Component[] components = panel.getComponents();
for (Component component : components) {
if (component instanceof JComponent) {
recursiveEnable((JComponent)component, isEnabled);
}
component.setEnabled(isEnabled);
}
}
public static File ensureSuffix( File f, String suffix ) {
String name = f.getName();
if (!name.toLowerCase().endsWith(suffix)) {
name = FilenameUtils.getBaseName(name) + suffix;
f = new File(f.getParent(), name);
}
return f;
}
public static @Nullable File saveFileChooser( Component parent, FileTypes... filters ) {
return fileChooser(null, parent, false, new File(".").getPath(), null, filters);
}
public static @Nullable String[] openImageSetChooser( @Nullable Window parent,
OpenImageSetDialog.Mode mode, int numberOfImages ) {
Preferences prefs;
if (parent == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(parent.getClass().getSimpleName());
}
File defaultPath = BoofSwingUtil.directoryUserHome();
String previousPath = prefs.get(KEY_PREVIOUS_SELECTION, defaultPath.getPath());
String[] response = OpenImageSetDialog.showDialog(new File(previousPath), mode, numberOfImages, parent);
if (response != null) {
prefs.put(KEY_PREVIOUS_SELECTION, new File(response[0]).getParent());
}
return response;
}
public static @Nullable OpenStereoSequencesChooser.Selected openStereoChooser(
Window parent, @Nullable Class> owner, boolean isSequence, boolean justImages ) {
Preferences prefs;
if (owner == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(owner.getSimpleName());
}
File defaultPath = BoofSwingUtil.directoryUserHome();
String previousPath = prefs.get(KEY_PREVIOUS_SELECTION, defaultPath.getPath());
OpenStereoSequencesChooser.Selected response =
OpenStereoSequencesChooser.showDialog(parent, isSequence, justImages, new File(previousPath));
if (response != null) {
prefs.put(KEY_PREVIOUS_SELECTION, response.left.getParent());
}
return response;
}
public static String getDefaultPath( @Nullable Object parent, @Nullable String key ) {
File defaultPath = BoofSwingUtil.directoryUserHome();
if (key == null)
return defaultPath.getPath();
Preferences prefs;
if (parent == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(parent.getClass().getSimpleName());
}
return prefs.get(key, defaultPath.getPath());
}
public static void saveDefaultPath( @Nullable Object parent, @Nullable String key, File file ) {
if (key == null)
return;
Preferences prefs;
if (parent == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(parent.getClass().getSimpleName());
}
if (!file.isDirectory())
file = file.getParentFile();
prefs.put(key, file.getAbsolutePath());
}
/**
* Opens a file choose when there is no parent component. Instead a string can be passed in so that the
* preference is specific to the application still
*/
public static @Nullable File openFileChooser( @Nullable String preferenceName, FileTypes... filters ) {
return fileChooser(preferenceName, null, true, new File(".").getPath(), null, filters);
}
public static @Nullable File openFilePreview( @Nullable String preferenceName, FileTypes... filters ) {
return fileChooserPreview(preferenceName, null, true, new File(".").getPath(), filters);
}
public static @Nullable File openFileChooser( @Nullable Component parent, FileTypes... filters ) {
return openFileChooser(parent, new File(".").getPath(), filters);
}
public static @Nullable File openFilePreview( @Nullable Component parent, FileTypes... filters ) {
return fileChooserPreview(null, parent, true, new File(".").getPath(), filters);
}
public static @Nullable File openFileChooser( @Nullable Component parent, String defaultPath, FileTypes... filters ) {
// For now don't use the preview chooser if there are directories
boolean directories = false;
// Make sure it will try to load images
boolean images = false;
for (var filter : filters) {
switch (filter) {
case DIRECTORIES -> directories = true;
case IMAGES, VIDEOS -> images = true;
default -> {
}
}
}
if (!directories && images) {
// Default to the new preview if they only want to see images
return fileChooserPreview(null, parent, true, defaultPath, filters);
} else {
return fileChooser(null, parent, true, defaultPath, null, filters);
}
}
/**
* Opens a file chooser for the specified file types. Previous path is loaded using preferences.
*
* @param massageName A lambda that lets you change the name of the previous path. Useful when a file type is selected.
*/
public static @Nullable File fileChooser( @Nullable String preferenceName,
@Nullable Component parent,
boolean openFile,
String defaultPath,
@Nullable BoofLambdas.MassageString massageName,
FileTypes... filters ) {
if (preferenceName == null && parent != null) {
preferenceName = parent.getClass().getSimpleName();
}
Preferences prefs;
if (preferenceName == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(preferenceName);
}
File previousPath = new File(prefs.get(KEY_PREVIOUS_SELECTION, defaultPath));
if (massageName != null) {
previousPath = new File(massageName.process(previousPath.getPath()));
}
var chooser = new JFileChooser();
boolean selectDirectories = false;
for (FileTypes t : filters) {
javax.swing.filechooser.FileFilter ff;
ff = switch (t) {
case FILES -> new javax.swing.filechooser.FileFilter() {
@Override public boolean accept( File pathname ) {return true;}
@Override public String getDescription() {return "All";}
};
case YAML -> new FileNameExtensionFilter("yaml", "yaml", "yml");
case XML -> new FileNameExtensionFilter("xml", "xml");
case IMAGES -> new FileNameExtensionFilter("Images", ImageIO.getReaderFileSuffixes());
case VIDEOS -> new FileNameExtensionFilter("Videos", "mpg", "mp4", "mov", "avi", "wmv");
case MESH -> new FileNameExtensionFilter("Mesh3D", "ply", "stl", "obj");
case DIRECTORIES -> {
selectDirectories = true;
yield null;
}
default -> throw new RuntimeException("Unknown file type");
};
if (ff == null)
break;
chooser.addChoosableFileFilter(ff);
}
if (selectDirectories) {
if (filters.length == 1)
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
else
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
}
if (chooser.getChoosableFileFilters().length > 1) {
chooser.setFileFilter(chooser.getChoosableFileFilters()[1]);
}
// Point it at the directory containing the previous selection
File currentDirectory = previousPath.getParentFile();
if (currentDirectory != null && currentDirectory.exists()) {
chooser.setCurrentDirectory(currentDirectory);
chooser.setSelectedFile(previousPath);
} else {
// otherwise, set the name to the previous file/directory name
chooser.setSelectedFile(new File(previousPath.getName()));
}
File selected = null;
int returnVal = openFile ? chooser.showOpenDialog(parent) : chooser.showSaveDialog(parent);
if (returnVal == JFileChooser.APPROVE_OPTION) {
selected = chooser.getSelectedFile();
prefs.put(KEY_PREVIOUS_SELECTION, selected.getPath());
}
return selected;
}
/**
* File chooser with a preview. Work in progress for replacing the old file chooser
*/
public static @Nullable File fileChooserPreview( @Nullable String preferenceName,
@Nullable Component parent,
boolean openFile,
String defaultPath, FileTypes... filters ) {
if (preferenceName == null && parent != null) {
preferenceName = parent.getClass().getSimpleName();
}
Preferences prefs;
if (preferenceName == null) {
prefs = Preferences.userRoot();
} else {
prefs = Preferences.userRoot().node(preferenceName);
}
File previousPath = new File(prefs.get(KEY_PREVIOUS_SELECTION, defaultPath)).getAbsoluteFile();
FilePreviewChooser chooser = new FilePreviewChooser(openFile);
escape:
for (FileTypes t : filters) {
javax.swing.filechooser.FileFilter ff;
switch (t) {
case FILES:
ff = new javax.swing.filechooser.FileFilter() {
@Override
public boolean accept( File pathname ) {
return true;
}
@Override
public String getDescription() {
return "All";
}
};
break;
case YAML:
ff = new FileNameExtensionFilter("yaml", "yaml", "yml");
break;
case XML:
ff = new FileNameExtensionFilter("xml", "xml");
break;
case IMAGES:
ff = new FileNameExtensionFilter("Images", UtilImageIO.IMAGE_SUFFIXES);
break;
case VIDEOS:
ff = new FileNameExtensionFilter("Videos", "mpg", "mp4", "mov", "avi", "wmv");
break;
case MESH:
ff = new FileNameExtensionFilter("Mesh3D", "ply", "stl", "obj");
break;
case DIRECTORIES:
break escape;
default:
throw new RuntimeException("Unknown file type");
}
chooser.getBrowser().addFileFilter(ff);
}
chooser.getBrowser().setSelectedFile(previousPath);
// if( selectDirectories ) {
// if( filters.length == 1 )
// chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
// else
// chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
// }
// if( chooser.getChoosableFileFilters().length > 1 ) {
// chooser.setFileFilter(chooser.getChoosableFileFilters()[1]);
// }
File selected = chooser.showDialog(parent);
System.out.println("Chooser file " + selected);
if (selected != null) {
prefs.put(KEY_PREVIOUS_SELECTION, selected.getPath());
}
return selected;
}
public static java.util.List getListOfRecentFiles( Component parent ) {
return getListOfRecentFiles(parent.getClass().getSimpleName());
}
public static java.util.List getListOfRecentFiles( String preferenceName ) {
Preferences prefs = Preferences.userRoot().node(preferenceName);
String encodedString = prefs.get(KEY_RECENT_FILES, "");
// See if recent file list exists, if not just return an empty list
if (encodedString.length() == 0) {
return new java.util.ArrayList<>();
}
try {
java.util.List results = new ArrayList<>();
java.util.List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy