Skip to content

Commit def8717

Browse files
committed
Blend mode button in side panel
1 parent 3bc8de8 commit def8717

21 files changed

+436
-0
lines changed

src/main/java/bdv/ui/viewermodepanel/DisplaySettingsPanel.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,18 @@
3030

3131
import static bdv.viewer.Interpolation.NEARESTNEIGHBOR;
3232
import static bdv.viewer.Interpolation.NLINEAR;
33+
import static bdv.viewer.ViewerStateChange.ACCUMULATE_PROJECTOR_CHANGED;
3334
import static bdv.viewer.ViewerStateChange.DISPLAY_MODE_CHANGED;
3435
import static bdv.viewer.ViewerStateChange.INTERPOLATION_CHANGED;
3536

37+
import javax.swing.Icon;
3638
import javax.swing.ImageIcon;
3739
import javax.swing.JPanel;
3840
import javax.swing.SwingUtilities;
3941
import javax.swing.UIManager;
4042

4143
import bdv.ui.UIUtils;
44+
import bdv.viewer.BlendModeSwitcher;
4245
import bdv.viewer.DisplayMode;
4346
import bdv.viewer.Interpolation;
4447
import bdv.viewer.ViewerState;
@@ -59,12 +62,21 @@ public class DisplaySettingsPanel extends JPanel
5962
private static final String SOURCE_MODE_TOOL_TIP = "<html><b>Source</b>/Group</html>";
6063
private static final String NEAREST_INTERPOLATION_TOOL_TIP = "<html><b>Nearest</b>/Linear</html>";
6164
private static final String LINEAR_INTERPOLATION_TOOL_TIP = "<html>Nearest/<b>Linear</b></html>";
65+
private static final String SUM_BLENDING_TOOL_TIP = "<html><b>Sum</b>/Average</html>";
66+
private static final String AVG_BLENDING_TOOL_TIP = "<html>Sum/<b>Average</html>";
67+
private static final String CUSTOM_BLENDING_TOOL_TIP = "<html>Sum/Average/<b>Custom</b></html>";
6268

6369
private final LabeledToggleButton fusion;
6470
private final LabeledToggleButton grouping;
6571
private final LabeledToggleButton interpolation;
72+
private final LabeledOptionButton blending;
6673

6774
public DisplaySettingsPanel( final ViewerState state )
75+
{
76+
this( state, true ); // TODO: change to false by default, so that it doesn't show in BVV
77+
}
78+
79+
public DisplaySettingsPanel( final ViewerState state, final boolean showBlendMode )
6880
{
6981
super( new MigLayout( "ins 2 0 0 0, fillx, filly", "[][][]", "top" ) );
7082

@@ -128,6 +140,35 @@ else if ( e == INTERPOLATION_CHANGED )
128140
this.add( fusion );
129141
this.add( grouping );
130142
this.add( interpolation );
143+
144+
if ( showBlendMode )
145+
{
146+
final BlendModeSwitcher blendModeSwitcher = new BlendModeSwitcher( state );
147+
blending = new LabeledOptionButton(
148+
new Icon[] {
149+
new ImageIcon( this.getClass().getResource( "blend_sum" + isDark + isLarge + ".png" ) ),
150+
new ImageIcon( this.getClass().getResource( "blend_avg" + isDark + isLarge + ".png" ) ),
151+
new ImageIcon( this.getClass().getResource( "blend_custom" + isDark + isLarge + ".png" ) ) },
152+
new String[] {
153+
"Sum",
154+
"Avg",
155+
"Custom"
156+
},
157+
new String[] {
158+
SUM_BLENDING_TOOL_TIP,
159+
AVG_BLENDING_TOOL_TIP,
160+
CUSTOM_BLENDING_TOOL_TIP } );
161+
blending.setOption( blendModeSwitcher.getCurrentMode().ordinal() );
162+
blending.addActionListener( e -> blendModeSwitcher.switchToNextMode() );
163+
blendModeSwitcher.changeListeners().add( mode -> {
164+
blending.setOption( mode.ordinal() );
165+
} );
166+
this.add( blending );
167+
}
168+
else
169+
{
170+
blending = null;
171+
}
131172
}
132173

133174
@Override
@@ -152,6 +193,14 @@ public void updateUI()
152193
new ImageIcon( this.getClass().getResource( "nearest" + isDark + isLarge + ".png" ) ),
153194
new ImageIcon( this.getClass().getResource( "linear" + isDark + isLarge + ".png" ) )
154195
);
196+
if ( blending != null )
197+
{
198+
blending.setIcons( new Icon[] {
199+
new ImageIcon( this.getClass().getResource( "blend_sum" + isDark + isLarge + ".png" ) ),
200+
new ImageIcon( this.getClass().getResource( "blend_avg" + isDark + isLarge + ".png" ) ),
201+
new ImageIcon( this.getClass().getResource( "blend_custom" + isDark + isLarge + ".png" ) )
202+
} );
203+
}
155204
}
156205
}
157206
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*-
2+
* #%L
3+
* BigDataViewer core classes with minimal dependencies.
4+
* %%
5+
* Copyright (C) 2012 - 2025 BigDataViewer developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package bdv.ui.viewermodepanel;
30+
31+
import javax.swing.Icon;
32+
import javax.swing.JLabel;
33+
34+
import bdv.ui.UIUtils;
35+
36+
public class LabeledOptionButton extends OptionButton
37+
{
38+
private final JLabel label;
39+
40+
public LabeledOptionButton(
41+
final Icon[] icons,
42+
final String[] texts,
43+
final String[] tooltipTexts )
44+
{
45+
super( icons, tooltipTexts );
46+
if ( texts.length != icons.length )
47+
throw new IllegalArgumentException();
48+
49+
label = new JLabel( texts[ 0 ] );
50+
setFont( label );
51+
button.addPropertyChangeListener( e -> {
52+
if ( e.getPropertyName().equals( "option" ) )
53+
label.setText( texts[ getOption() ] );
54+
} );
55+
56+
this.add( label, "center" );
57+
}
58+
59+
private void setFont( final JLabel label )
60+
{
61+
label.setFont( UIUtils.getFont( "monospaced.bold.mini.font" ) );
62+
// label.setFont( new Font( Font.MONOSPACED, Font.BOLD, ( int )Math.round(9 * UIUtils.getUIScaleFactor( this ) ) ) );
63+
}
64+
65+
@Override
66+
public void updateUI()
67+
{
68+
super.updateUI();
69+
70+
if ( label != null )
71+
setFont( label );
72+
}
73+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*-
2+
* #%L
3+
* BigDataViewer core classes with minimal dependencies.
4+
* %%
5+
* Copyright (C) 2012 - 2025 BigDataViewer developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package bdv.ui.viewermodepanel;
30+
31+
import java.awt.Dimension;
32+
import java.awt.event.ActionListener;
33+
34+
import javax.swing.Icon;
35+
import javax.swing.JButton;
36+
import javax.swing.JPanel;
37+
38+
import net.miginfocom.swing.MigLayout;
39+
40+
/**
41+
* A compact UI button that can be used to cycles through multiple exclusive
42+
* options (icon + tooltip) each time it's clicked.
43+
* <p>
44+
* The update of the current option has to be managed by outside logic that
45+
* calls {@link #setOption} in response to {@code ActionEvent}s.
46+
*/
47+
class OptionButton extends JPanel
48+
{
49+
final JButton button;
50+
51+
private final Icon[] icons;
52+
53+
private int currentOption = 0;
54+
55+
public OptionButton(
56+
final Icon[] icons,
57+
final String[] tooltipTexts )
58+
{
59+
super( new MigLayout( "ins 0, fillx, filly", "[]", "[]0lp![]" ) );
60+
61+
if ( icons == null || tooltipTexts == null )
62+
throw new NullPointerException();
63+
64+
if ( icons.length == 0 || icons.length != tooltipTexts.length )
65+
throw new IllegalArgumentException();
66+
67+
this.icons = icons;
68+
69+
button = new JButton( icons[ 0 ] );
70+
button.setToolTipText( tooltipTexts[ 0 ] );
71+
setLook( button );
72+
73+
button.addPropertyChangeListener( e -> {
74+
if ( e.getPropertyName().equals( "option" ) )
75+
{
76+
button.setIcon( this.icons[ currentOption ] );
77+
button.setToolTipText( tooltipTexts[ currentOption ] );
78+
}
79+
} );
80+
81+
this.add( button, "growx, center, wrap" );
82+
}
83+
84+
public void setIcons( final Icon[] icons )
85+
{
86+
if ( icons.length != this.icons.length )
87+
throw new IllegalArgumentException();
88+
89+
System.arraycopy( icons, 0, this.icons, 0, icons.length );
90+
91+
button.setIcon( icons[ currentOption ] );
92+
setLook( button );
93+
}
94+
95+
public int getOption()
96+
{
97+
return currentOption;
98+
}
99+
100+
public void setOption( int option )
101+
{
102+
if ( option < 0 || option >= icons.length )
103+
throw new IllegalArgumentException( "Invalid option index: " + option );
104+
final int oldOption = currentOption;
105+
currentOption = option;
106+
button.firePropertyChange( "option", oldOption, currentOption );
107+
}
108+
109+
public void addActionListener( final ActionListener l )
110+
{
111+
button.addActionListener( l );
112+
}
113+
114+
public void removeActionListener( final ActionListener l )
115+
{
116+
button.removeActionListener( l );
117+
}
118+
119+
private void setLook( final JButton button )
120+
{
121+
button.setMaximumSize( new Dimension( button.getIcon().getIconWidth(), button.getIcon().getIconHeight() ) );
122+
button.setBorderPainted( false );
123+
button.setFocusPainted( false );
124+
button.setContentAreaFilled( false );
125+
}
126+
}
519 Bytes
Loading
Lines changed: 24 additions & 0 deletions
Loading
1.08 KB
Loading
633 Bytes
Loading
Lines changed: 24 additions & 0 deletions
Loading
1.27 KB
Loading
922 Bytes
Loading

0 commit comments

Comments
 (0)