/*
* Copyright (C) 2015 Patryk Strach
*
* This file is part of Virtual Slide Viewer.
*
* Virtual Slide Viewer is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* Virtual Slide Viewer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Virtual Slide Viewer.
* If not, see <http://www.gnu.org/licenses/>.
*/
package virtualslideviewer.ui.config;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import java.text.DecimalFormat;
import virtualslideviewer.config.ApplicationConfiguration;
import virtualslideviewer.util.ImageUtil;
public class ConfigDialog extends JDialog
{
private static final long serialVersionUID = 1L;
private static final String RESOLUTION_THRESHOLD_TOOLTIP = "<html>"
+ "A threshold controlling how early the application starts to retrieve pixels"
+ "from higher resolution when zoomed between resolutions.<br>"
+ "The lower the value, the better is the quality, but it also greatly "
+ "lowers the application's performance.</html>";
private static final double MIN_ZOOM_INCREMENT = 1.01;
private static final double MAX_ZOOM_INCREMENT = 5.00;
private final ApplicationConfiguration mConfiguration;
private JSpinner mZoomIncrementSpinner;
private JSlider mResolutionThresholdSlider;
private JFormattedTextField mResolutionThresholdTextField;
private JButton mOKButton;
private JButton mCancelButton;
public ConfigDialog(Component parent, ApplicationConfiguration configuration)
{
if(configuration == null)
throw new IllegalArgumentException("configuration cannot be null.");
mConfiguration = configuration;
super.setTitle("Preferences");
super.setType(Type.NORMAL);
super.setModalityType(ModalityType.APPLICATION_MODAL);
ToolTipManager.sharedInstance().setDismissDelay(15000);
createZoomIncrementSpinner();
createResolutionThresholdSlider();
createResolutionThresholdTextField();
createOkButton();
createCancelButton();
layoutComponents();
centerOnParent(parent);
}
private void centerOnParent(Component parent)
{
if(parent != null)
{
Point positionRelativeToParent = ImageUtil.getCenteredPosition(super.getSize(), parent.getSize());
Point positionRelativeToScreen = new Point(positionRelativeToParent.x + parent.getLocationOnScreen().x,
positionRelativeToParent.y + parent.getLocationOnScreen().y);
super.setLocation(positionRelativeToScreen);
}
}
private void createZoomIncrementSpinner()
{
mZoomIncrementSpinner = new JSpinner();
mZoomIncrementSpinner.setToolTipText("A multiplier to be used when zooming");
mZoomIncrementSpinner.setPreferredSize(new Dimension(100, 20));
mZoomIncrementSpinner.setMinimumSize(mZoomIncrementSpinner.getPreferredSize());
mZoomIncrementSpinner.setModel(new ClampingSpinnerDoubleModel(mConfiguration.getZoomIncrement(), MIN_ZOOM_INCREMENT, MAX_ZOOM_INCREMENT, 0.01));
}
private void createResolutionThresholdSlider()
{
mResolutionThresholdSlider = new JSlider();
mResolutionThresholdSlider.setToolTipText(RESOLUTION_THRESHOLD_TOOLTIP);
mResolutionThresholdSlider.setMinimum(0);
mResolutionThresholdSlider.setValue((int)(mConfiguration.getResolutionTransitionThreshold() * 100));
mResolutionThresholdSlider.setMaximum(100);
mResolutionThresholdSlider.addChangeListener(e ->
{
mResolutionThresholdTextField.setValue(mResolutionThresholdSlider.getValue() * 0.01);
});
}
private void createResolutionThresholdTextField()
{
mResolutionThresholdTextField = new JFormattedTextField(new DecimalFormat("##0.0%"));
mResolutionThresholdTextField.setToolTipText(RESOLUTION_THRESHOLD_TOOLTIP);
mResolutionThresholdTextField.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
mResolutionThresholdTextField.setHorizontalAlignment(SwingConstants.CENTER);
mResolutionThresholdTextField.setColumns(6);
mResolutionThresholdTextField.setValue(mConfiguration.getResolutionTransitionThreshold());
mResolutionThresholdTextField.setMinimumSize(mResolutionThresholdTextField.getPreferredSize());
mResolutionThresholdTextField.addPropertyChangeListener("value", e ->
{
double textFieldValue = ((Number)e.getNewValue()).doubleValue();
if(textFieldValue < 0.0 || textFieldValue > 1.0)
{
mResolutionThresholdTextField.setValue(Math.min(Math.max(textFieldValue, 0.0), 1.0));
return; // setValue will invoke next change event, and slider will be update there
}
mResolutionThresholdSlider.setValue((int)(textFieldValue * 100));
});
}
private void createOkButton()
{
mOKButton = new JButton("OK");
mOKButton.addActionListener(x ->
{
Number zoomIncrement = (Number)mZoomIncrementSpinner.getValue();
Number resolutionThreshold = (Number)mResolutionThresholdTextField.getValue();
mConfiguration.setZoomIncrement(zoomIncrement.doubleValue());
mConfiguration.setResolutionTransitionThreshold(resolutionThreshold.doubleValue());
super.setVisible(false);
});
}
private void createCancelButton()
{
mCancelButton = new JButton("Cancel");
mCancelButton.addActionListener(x -> super.setVisible(false));
}
private void layoutComponents()
{
getContentPane().setLayout(new BorderLayout());
JPanel contentPanel = new JPanel(new GridBagLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
layoutZoomIncrementOption(contentPanel);
layoutResolutionThresholdOption(contentPanel);
layoutButtons();
super.pack();
super.setMinimumSize(super.getSize());
}
private void layoutZoomIncrementOption(JPanel mainPanel)
{
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(new TitledBorder("Zoom increment"));
GridBagConstraints spinnerContraints = new GridBagConstraints();
spinnerContraints.gridx = 0;
spinnerContraints.gridy = 0;
spinnerContraints.anchor = GridBagConstraints.WEST;
spinnerContraints.insets = new Insets(0, 5, 0, 5);
panel.add(mZoomIncrementSpinner, spinnerContraints);
GridBagConstraints glueContraints = new GridBagConstraints();
glueContraints.gridx = 1;
glueContraints.gridy = 0;
glueContraints.weighty = 1.0;
glueContraints.weightx = 1.0;
panel.add(Box.createGlue(), glueContraints);
GridBagConstraints panelContraints = new GridBagConstraints();
panelContraints.gridx = 0;
panelContraints.gridy = 0;
panelContraints.weighty = 1.0;
panelContraints.weightx = 1.0;
panelContraints.insets = new Insets(5, 0, 5, 0);
panelContraints.fill = GridBagConstraints.BOTH;
mainPanel.add(panel, panelContraints);
}
private void layoutResolutionThresholdOption(JPanel mainPanel)
{
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(new TitledBorder("Resolution transition threshold"));
panel.setToolTipText(RESOLUTION_THRESHOLD_TOOLTIP);
GridBagConstraints sliderContraints = new GridBagConstraints();
sliderContraints.gridx = 1;
sliderContraints.gridy = 0;
sliderContraints.weightx = 1.0;
sliderContraints.insets = new Insets(0, 0, 0, 5);
sliderContraints.fill = GridBagConstraints.HORIZONTAL;
panel.add(mResolutionThresholdSlider, sliderContraints);
GridBagConstraints textFieldConstraints = new GridBagConstraints();
textFieldConstraints.gridx = 2;
textFieldConstraints.gridy = 0;
textFieldConstraints.anchor = GridBagConstraints.NORTHWEST;
panel.add(mResolutionThresholdTextField, textFieldConstraints);
GridBagConstraints panelContraints = new GridBagConstraints();
panelContraints.gridx = 0;
panelContraints.gridy = 1;
panelContraints.weighty = 1.0;
panelContraints.weightx = 1.0;
panelContraints.insets = new Insets(0, 0, 3, 0);
panelContraints.fill = GridBagConstraints.BOTH;
mainPanel.add(panel, panelContraints);
}
private void layoutButtons()
{
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPane.add(mOKButton);
buttonPane.add(mCancelButton);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
}
}