001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.component.renderer; 020 021import java.awt.Color; 022import java.awt.Component; 023import java.awt.Insets; 024import java.util.Map; 025 026import javax.swing.Icon; 027import javax.swing.JComboBox; 028import javax.swing.JComponent; 029import javax.swing.JLabel; 030import javax.swing.JList; 031import javax.swing.border.EmptyBorder; 032import javax.swing.plaf.ColorUIResource; 033import javax.swing.plaf.ComboBoxUI; 034import javax.swing.plaf.ListUI; 035 036import org.pushingpixels.substance.api.ColorSchemeAssociationKind; 037import org.pushingpixels.substance.api.ComponentState; 038import org.pushingpixels.substance.api.ComponentStateFacet; 039import org.pushingpixels.substance.api.SubstanceColorScheme; 040import org.pushingpixels.substance.api.SubstanceLookAndFeel; 041import org.pushingpixels.substance.api.renderers.SubstanceDefaultComboBoxRenderer; 042import org.pushingpixels.substance.internal.animation.StateTransitionTracker; 043import org.pushingpixels.substance.internal.animation.StateTransitionTracker.ModelStateInfo; 044import org.pushingpixels.substance.internal.animation.StateTransitionTracker.StateContributionInfo; 045import org.pushingpixels.substance.internal.ui.SubstanceComboBoxUI; 046import org.pushingpixels.substance.internal.ui.SubstanceListUI; 047import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities; 048import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils; 049import org.pushingpixels.substance.internal.utils.SubstanceStripingUtils; 050import org.pushingpixels.substance.internal.utils.SubstanceTextUtilities; 051import org.pushingpixels.substance.internal.utils.UpdateOptimizationInfo; 052 053/** 054 * CustomComboBox renderer, based on Substance look and feel code.<br> 055 * Override the getListCellRendererComponent() or updateItem() methods to do your own rendering. 056 * 057 * @author Stephane 058 */ 059public class CustomComboBoxRenderer extends SubstanceDefaultComboBoxRenderer 060{ 061 /** 062 * 063 */ 064 private static final long serialVersionUID = -3392789033779535472L; 065 066 private final JComboBox combo; 067 068 public CustomComboBoxRenderer(JComboBox combo) 069 { 070 super(combo); 071 072 this.combo = combo; 073 } 074 075 public JComboBox getComboBox() 076 { 077 return combo; 078 } 079 080 @Override 081 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, 082 boolean cellHasFocus) 083 { 084 JComponent result = (JComponent) getRendererComponent(list, value, index, isSelected); 085 086 ListUI baseListUI = list.getUI(); 087 ComboBoxUI baseComboUI = combo.getUI(); 088 089 if ((baseListUI instanceof SubstanceListUI) && (baseComboUI instanceof SubstanceComboBoxUI)) 090 { 091 SubstanceListUI listUI = (SubstanceListUI) baseListUI; 092 SubstanceComboBoxUI comboUI = (SubstanceComboBoxUI) baseComboUI; 093 094 // special case for the combobox. The selected value is 095 // painted using the renderer of the list, and the index 096 // is -1. 097 if (index == -1) 098 { 099 StateTransitionTracker stateTransitionTracker = comboUI.getTransitionTracker(); 100 ModelStateInfo modelStateInfo = stateTransitionTracker.getModelStateInfo(); 101 ComponentState currState = modelStateInfo.getCurrModelState(); 102 float comboAlpha = SubstanceColorSchemeUtilities.getAlpha(combo, currState); 103 Color fg = SubstanceTextUtilities.getForegroundColor(combo, ((JLabel) result).getText(), 104 modelStateInfo, comboAlpha); 105 result.setForeground(fg); 106 } 107 else 108 { 109 // use highlight color scheme for selected and rollover 110 // elements in the drop down list 111 StateTransitionTracker.ModelStateInfo modelStateInfo = listUI.getModelStateInfo(index, result); 112 ComponentState currState = listUI.getCellState(index, result); 113 114 if (modelStateInfo == null) 115 { 116 SubstanceColorScheme scheme = getColorSchemeForState(list, index, listUI, currState); 117 result.setForeground(new ColorUIResource(scheme.getForegroundColor())); 118 } 119 else 120 { 121 Map<ComponentState, StateContributionInfo> activeStates = modelStateInfo.getStateContributionMap(); 122 SubstanceColorScheme colorScheme = getColorSchemeForState(list, index, listUI, currState); 123 124 if (currState.isDisabled() || (activeStates == null) || (activeStates.size() == 1)) 125 { 126 super.setForeground(new ColorUIResource(colorScheme.getForegroundColor())); 127 } 128 else 129 { 130 float aggrRed = 0.0f; 131 float aggrGreen = 0.0f; 132 float aggrBlue = 0.0f; 133 134 for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo 135 .getStateContributionMap().entrySet()) 136 { 137 ComponentState activeState = activeEntry.getKey(); 138 float activeContribution = activeEntry.getValue().getContribution(); 139 if (activeContribution == 0.0f) 140 continue; 141 142 SubstanceColorScheme scheme = getColorSchemeForState(list, index, listUI, activeState); 143 Color schemeFg = scheme.getForegroundColor(); 144 aggrRed += schemeFg.getRed() * activeContribution; 145 aggrGreen += schemeFg.getGreen() * activeContribution; 146 aggrBlue += schemeFg.getBlue() * activeContribution; 147 } 148 149 result.setForeground(new ColorUIResource(new Color((int) aggrRed, (int) aggrGreen, 150 (int) aggrBlue))); 151 } 152 } 153 } 154 155 SubstanceStripingUtils.applyStripedBackground(list, index, this); 156 } 157 158 result.setEnabled(combo.isEnabled() & isEnabled()); 159 160 return result; 161 } 162 163 protected Component getRendererComponent(JList list, Object value, int index, boolean isSelected) 164 { 165 setComponentOrientation(list.getComponentOrientation()); 166 167 ListUI listUI = list.getUI(); 168 169 if (listUI instanceof SubstanceListUI) 170 { 171 SubstanceListUI ui = (SubstanceListUI) listUI; 172 173 StateTransitionTracker.ModelStateInfo modelStateInfo = ui.getModelStateInfo(index, this); 174 ComponentState currState = ui.getCellState(index, this); 175 176 // special case for drop location 177 JList.DropLocation dropLocation = list.getDropLocation(); 178 boolean isDropLocation = (dropLocation != null && !dropLocation.isInsert() && dropLocation.getIndex() == index); 179 180 if (!isDropLocation && (modelStateInfo != null)) 181 { 182 Map<ComponentState, StateContributionInfo> activeStates = modelStateInfo.getStateContributionMap(); 183 SubstanceColorScheme colorScheme = getColorSchemeForState(list, ui, currState); 184 185 if (currState.isDisabled() || (activeStates == null) || (activeStates.size() == 1)) 186 super.setForeground(new ColorUIResource(colorScheme.getForegroundColor())); 187 else 188 { 189 float aggrRed = 0; 190 float aggrGreen = 0; 191 float aggrBlue = 0; 192 193 for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo 194 .getStateContributionMap().entrySet()) 195 { 196 ComponentState activeState = activeEntry.getKey(); 197 SubstanceColorScheme scheme = getColorSchemeForState(list, ui, activeState); 198 Color schemeFg = scheme.getForegroundColor(); 199 float contribution = activeEntry.getValue().getContribution(); 200 201 aggrRed += schemeFg.getRed() * contribution; 202 aggrGreen += schemeFg.getGreen() * contribution; 203 aggrBlue += schemeFg.getBlue() * contribution; 204 } 205 206 super.setForeground(new ColorUIResource(new Color((int) aggrRed, (int) aggrGreen, (int) aggrBlue))); 207 } 208 } 209 else 210 { 211 SubstanceColorScheme scheme = getColorSchemeForState(list, ui, currState); 212 213 if (isDropLocation) 214 { 215 scheme = SubstanceColorSchemeUtilities.getColorScheme(list, 216 ColorSchemeAssociationKind.TEXT_HIGHLIGHT, currState); 217 } 218 219 super.setForeground(new ColorUIResource(scheme.getForegroundColor())); 220 } 221 } 222 else 223 { 224 if (isSelected) 225 setForeground(list.getSelectionForeground()); 226 else 227 setForeground(list.getForeground()); 228 } 229 230 if (SubstanceLookAndFeel.isCurrentLookAndFeel() && (list.getLayoutOrientation() == JList.VERTICAL)) 231 SubstanceStripingUtils.applyStripedBackground(list, index, this); 232 233 updateItem(list, value); 234 235 Insets ins = SubstanceSizeUtils.getListCellRendererInsets(SubstanceSizeUtils.getComponentFontSize(list)); 236 setBorder(new EmptyBorder(ins.top, ins.left, ins.bottom, ins.right)); 237 setOpaque(false); 238 239 return this; 240 } 241 242 protected void updateItem(JList list, Object value) 243 { 244 if (value instanceof Icon) 245 { 246 setIcon((Icon) value); 247 setText(""); 248 } 249 else 250 { 251 setIcon(null); 252 setText((value == null) ? "" : value.toString()); 253 setToolTipText((value == null) ? "" : value.toString()); 254 } 255 256 setEnabled(list.isEnabled()); 257 setFont(list.getFont()); 258 } 259 260 private SubstanceColorScheme getColorSchemeForState(JList list, SubstanceListUI ui, ComponentState state) 261 { 262 final UpdateOptimizationInfo updateOptimizationInfo = ui.getUpdateOptimizationInfo(); 263 264 if (state == ComponentState.ENABLED) 265 { 266 if (updateOptimizationInfo == null) 267 return SubstanceColorSchemeUtilities.getColorScheme(list, state); 268 269 return updateOptimizationInfo.getDefaultScheme(); 270 } 271 272 if (updateOptimizationInfo == null) 273 return SubstanceColorSchemeUtilities.getColorScheme(list, ColorSchemeAssociationKind.HIGHLIGHT, state); 274 275 return updateOptimizationInfo.getHighlightColorScheme(state); 276 } 277 278 private SubstanceColorScheme getColorSchemeForState(JList list, int index, SubstanceListUI listUI, 279 ComponentState state) 280 { 281 final boolean toUseHighlightKindForCurrState = (index >= 0) 282 && (state.isFacetActive(ComponentStateFacet.ROLLOVER) || state 283 .isFacetActive(ComponentStateFacet.SELECTION)); 284 final UpdateOptimizationInfo updateOptimizationInfo = listUI.getUpdateOptimizationInfo(); 285 286 if (toUseHighlightKindForCurrState) 287 { 288 if (updateOptimizationInfo == null) 289 return SubstanceColorSchemeUtilities.getColorScheme(list, ColorSchemeAssociationKind.HIGHLIGHT, state); 290 291 return updateOptimizationInfo.getHighlightColorScheme(state); 292 } 293 294 if (updateOptimizationInfo == null) 295 return SubstanceColorSchemeUtilities.getColorScheme(list, state); 296 297 return updateOptimizationInfo.getDefaultScheme(); 298 } 299}