| 1 | /** |
|---|
| 2 | * Copyright (c) 2008-2011 Ardor Labs, Inc. |
|---|
| 3 | * |
|---|
| 4 | * This file is part of Ardor3D. |
|---|
| 5 | * |
|---|
| 6 | * Ardor3D is free software: you can redistribute it and/or modify it |
|---|
| 7 | * under the terms of its license which may be found in the accompanying |
|---|
| 8 | * LICENSE file or at <http://www.ardor3d.com/LICENSE>. |
|---|
| 9 | */ |
|---|
| 10 | |
|---|
| 11 | package com.ardor3d.extension.ui; |
|---|
| 12 | |
|---|
| 13 | import java.util.List; |
|---|
| 14 | |
|---|
| 15 | import com.ardor3d.extension.ui.event.ActionEvent; |
|---|
| 16 | import com.ardor3d.extension.ui.event.ActionListener; |
|---|
| 17 | import com.ardor3d.extension.ui.event.SelectionListener; |
|---|
| 18 | import com.ardor3d.extension.ui.layout.BorderLayout; |
|---|
| 19 | import com.ardor3d.extension.ui.layout.BorderLayoutData; |
|---|
| 20 | import com.ardor3d.extension.ui.model.ComboBoxModel; |
|---|
| 21 | import com.ardor3d.extension.ui.model.DefaultComboBoxModel; |
|---|
| 22 | import com.ardor3d.extension.ui.skin.SkinningTask; |
|---|
| 23 | import com.ardor3d.extension.ui.text.StyleConstants; |
|---|
| 24 | import com.ardor3d.input.InputState; |
|---|
| 25 | import com.ardor3d.input.MouseButton; |
|---|
| 26 | import com.ardor3d.scenegraph.Spatial; |
|---|
| 27 | import com.google.common.collect.Lists; |
|---|
| 28 | |
|---|
| 29 | /** |
|---|
| 30 | * A UI component that contains several possible choices, but shows only the currently selected one. Changing the |
|---|
| 31 | * selection is allowed via a popup menu shown when the component is clicked on. |
|---|
| 32 | */ |
|---|
| 33 | public class UIComboBox extends UIPanel { |
|---|
| 34 | |
|---|
| 35 | protected ComboBoxModel _model; |
|---|
| 36 | |
|---|
| 37 | protected UILabel _valueLabel; |
|---|
| 38 | protected UIButton _openButton; |
|---|
| 39 | protected UIPopupMenu _valuesMenu; |
|---|
| 40 | |
|---|
| 41 | protected int _selectedIndex = 0; |
|---|
| 42 | |
|---|
| 43 | private final List<SelectionListener<UIComboBox>> _listeners = Lists.newArrayList(); |
|---|
| 44 | |
|---|
| 45 | private SkinningTask _itemSkinCallback; |
|---|
| 46 | |
|---|
| 47 | public UIComboBox() { |
|---|
| 48 | this(new DefaultComboBoxModel()); |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | public UIComboBox(final ComboBoxModel model) { |
|---|
| 52 | super(new BorderLayout()); |
|---|
| 53 | if (model == null) { |
|---|
| 54 | throw new IllegalArgumentException("model can not be null."); |
|---|
| 55 | } |
|---|
| 56 | _model = model; |
|---|
| 57 | |
|---|
| 58 | _valueLabel = new UILabel(_model.size() > 0 ? _model.getViewAt(0) : "") { |
|---|
| 59 | @Override |
|---|
| 60 | public boolean mouseReleased(final MouseButton button, final InputState state) { |
|---|
| 61 | _openButton.doClick(); |
|---|
| 62 | return true; |
|---|
| 63 | } |
|---|
| 64 | }; |
|---|
| 65 | _valueLabel.setLayoutData(BorderLayoutData.CENTER); |
|---|
| 66 | add(_valueLabel); |
|---|
| 67 | |
|---|
| 68 | _openButton = new UIButton("\\/"); |
|---|
| 69 | _openButton.setLayoutData(BorderLayoutData.EAST); |
|---|
| 70 | add(_openButton); |
|---|
| 71 | |
|---|
| 72 | _valuesMenu = new UIPopupMenu() { |
|---|
| 73 | @Override |
|---|
| 74 | public UIComponent getUIComponent(final int hudX, final int hudY) { |
|---|
| 75 | final UIComponent component = super.getUIComponent(hudX, hudY); |
|---|
| 76 | if (component != null) { |
|---|
| 77 | if (component instanceof UIButton) { |
|---|
| 78 | final UIButton over = (UIButton) component; |
|---|
| 79 | final UIState state = over.getCurrentState(); |
|---|
| 80 | if (state == over.getDefaultState() || state == over.getSelectedState()) { |
|---|
| 81 | clearOver(); |
|---|
| 82 | } |
|---|
| 83 | } |
|---|
| 84 | } |
|---|
| 85 | return component; |
|---|
| 86 | } |
|---|
| 87 | }; |
|---|
| 88 | |
|---|
| 89 | _openButton.addActionListener(new ActionListener() { |
|---|
| 90 | @Override |
|---|
| 91 | public void actionPerformed(final ActionEvent event) { |
|---|
| 92 | if (!isEnabled()) { |
|---|
| 93 | return; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | if (_valuesMenu.isAttachedToHUD()) { |
|---|
| 97 | _valuesMenu.getHud().closePopupMenus(); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | _valuesMenu.clearItems(); |
|---|
| 101 | for (int i = 0; i < _model.size(); i++) { |
|---|
| 102 | final UIMenuItem item = new UIMenuItem("" + _model.getValueAt(i)); |
|---|
| 103 | if (_itemSkinCallback != null) { |
|---|
| 104 | _itemSkinCallback.skinComponent(item); |
|---|
| 105 | } |
|---|
| 106 | if (i == getSelectedIndex()) { |
|---|
| 107 | item.addFontStyle(StyleConstants.KEY_BOLD, Boolean.TRUE); |
|---|
| 108 | } |
|---|
| 109 | final int index = i; |
|---|
| 110 | item.addActionListener(new ActionListener() { |
|---|
| 111 | @Override |
|---|
| 112 | public void actionPerformed(final ActionEvent event) { |
|---|
| 113 | setSelectedIndex(index); |
|---|
| 114 | } |
|---|
| 115 | }); |
|---|
| 116 | |
|---|
| 117 | // Apply model for name and toolTipText |
|---|
| 118 | item.setName(_model.getViewAt(i)); |
|---|
| 119 | item.setTooltipText(_model.getToolTipAt(i)); |
|---|
| 120 | _valuesMenu.addItem(item); |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | _valuesMenu.updateMinimumSizeFromContents(); |
|---|
| 124 | _valuesMenu.pack(); |
|---|
| 125 | if (_valuesMenu.getLocalComponentWidth() < UIComboBox.this.getLocalComponentWidth()) { |
|---|
| 126 | _valuesMenu.setLocalComponentWidth(UIComboBox.this.getLocalComponentWidth()); |
|---|
| 127 | } |
|---|
| 128 | _valuesMenu.layout(); |
|---|
| 129 | getHud().closePopupMenus(); |
|---|
| 130 | getHud().showSubPopupMenu(_valuesMenu); |
|---|
| 131 | _valuesMenu.showAt(_valueLabel.getHudX(), _valueLabel.getHudY()); |
|---|
| 132 | } |
|---|
| 133 | }); |
|---|
| 134 | |
|---|
| 135 | applySkin(); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | protected void clearOver() { |
|---|
| 139 | _openButton.switchState(_openButton.getDefaultState()); |
|---|
| 140 | for (int i = _valuesMenu.getNumberOfChildren(); --i >= 0;) { |
|---|
| 141 | final Spatial item = _valuesMenu.getChild(i); |
|---|
| 142 | if (item instanceof UIButton) { |
|---|
| 143 | final UIButton over = (UIButton) item; |
|---|
| 144 | over.switchState(over.getDefaultState()); |
|---|
| 145 | } |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | public int getSelectedIndex() { |
|---|
| 150 | return _selectedIndex; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | public Object getSelectedValue() { |
|---|
| 154 | return _model.getValueAt(getSelectedIndex()); |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | public void setSelectedIndex(final int index) { |
|---|
| 158 | setSelectedIndex(index, true); |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | public void setSelectedIndex(final int index, final boolean fireEvent) { |
|---|
| 162 | if (index != _selectedIndex) { |
|---|
| 163 | _selectedIndex = index; |
|---|
| 164 | if (fireEvent) { |
|---|
| 165 | fireSelectionEvent(); |
|---|
| 166 | } |
|---|
| 167 | fireComponentDirty(); |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | if (index == -1 || _model == null || _model.size() == 0) { |
|---|
| 171 | _valueLabel.setText(""); |
|---|
| 172 | } else { |
|---|
| 173 | _valueLabel.setText(_model.getViewAt(index)); |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | protected void fireSelectionEvent() { |
|---|
| 178 | if (!isEnabled()) { |
|---|
| 179 | return; |
|---|
| 180 | } |
|---|
| 181 | for (final SelectionListener<UIComboBox> listener : _listeners) { |
|---|
| 182 | listener.selectionChanged(this, getSelectedValue()); |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | @Override |
|---|
| 187 | public void setEnabled(final boolean enabled) { |
|---|
| 188 | super.setEnabled(enabled); |
|---|
| 189 | _valueLabel.setEnabled(enabled); |
|---|
| 190 | _openButton.setEnabled(enabled); |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | @Override |
|---|
| 194 | public String getTooltipText() { |
|---|
| 195 | if (_tooltipText == null) { |
|---|
| 196 | final String rVal = _model.getToolTipAt(_selectedIndex); |
|---|
| 197 | if (rVal != null) { |
|---|
| 198 | return rVal; |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | return super.getTooltipText(); |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | public UILabel getValueLabel() { |
|---|
| 205 | return _valueLabel; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | public ComboBoxModel getModel() { |
|---|
| 209 | return _model; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | public UIButton getOpenButton() { |
|---|
| 213 | return _openButton; |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | public UIPopupMenu getValuesMenu() { |
|---|
| 217 | return _valuesMenu; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | public void addSelectionListener(final SelectionListener<UIComboBox> listener) { |
|---|
| 221 | _listeners.add(listener); |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | public void removeSelectionListener(final SelectionListener<UIComboBox> listener) { |
|---|
| 225 | _listeners.remove(listener); |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | public void clearSelectionListeners() { |
|---|
| 229 | _listeners.clear(); |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | public void setItemSkinCallback(final SkinningTask callback) { |
|---|
| 233 | _itemSkinCallback = callback; |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | public SkinningTask getItemSkinCallback() { |
|---|
| 237 | return _itemSkinCallback; |
|---|
| 238 | } |
|---|
| 239 | } |
|---|