Merge branch 'subtree'
[fanfix.git] / src / jexer / TRadioGroup.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer;
30
31 import jexer.bits.CellAttributes;
32 import jexer.bits.StringUtils;
33
34 /**
35 * TRadioGroup is a collection of TRadioButtons with a box and label.
36 */
37 public class TRadioGroup extends TWidget {
38
39 // ------------------------------------------------------------------------
40 // Variables --------------------------------------------------------------
41 // ------------------------------------------------------------------------
42
43 /**
44 * Label for this radio button group.
45 */
46 private String label;
47
48 /**
49 * Only one of my children can be selected.
50 */
51 private TRadioButton selectedButton = null;
52
53 /**
54 * If true, one of the children MUST be selected. Note package private
55 * access.
56 */
57 boolean requiresSelection = false;
58
59 // ------------------------------------------------------------------------
60 // Constructors -----------------------------------------------------------
61 // ------------------------------------------------------------------------
62
63 /**
64 * Public constructor.
65 *
66 * @param parent parent widget
67 * @param x column relative to parent
68 * @param y row relative to parent
69 * @param width width of group
70 * @param label label to display on the group box
71 */
72 public TRadioGroup(final TWidget parent, final int x, final int y,
73 final int width, final String label) {
74
75 // Set parent and window
76 super(parent, x, y, width, 2);
77
78 this.label = label;
79 }
80
81 /**
82 * Public constructor.
83 *
84 * @param parent parent widget
85 * @param x column relative to parent
86 * @param y row relative to parent
87 * @param label label to display on the group box
88 */
89 public TRadioGroup(final TWidget parent, final int x, final int y,
90 final String label) {
91
92 // Set parent and window
93 super(parent, x, y, StringUtils.width(label) + 4, 2);
94
95 this.label = label;
96 }
97
98 // ------------------------------------------------------------------------
99 // TWidget ----------------------------------------------------------------
100 // ------------------------------------------------------------------------
101
102 /**
103 * Override TWidget's width: we can only set width at construction time.
104 *
105 * @param width new widget width (ignored)
106 */
107 @Override
108 public void setWidth(final int width) {
109 // Do nothing
110 }
111
112 /**
113 * Override TWidget's height: we can only set height at construction
114 * time.
115 *
116 * @param height new widget height (ignored)
117 */
118 @Override
119 public void setHeight(final int height) {
120 // Do nothing
121 }
122
123 /**
124 * Draw a radio button with label.
125 */
126 @Override
127 public void draw() {
128 CellAttributes radioGroupColor;
129
130 if (isAbsoluteActive()) {
131 radioGroupColor = getTheme().getColor("tradiogroup.active");
132 } else {
133 radioGroupColor = getTheme().getColor("tradiogroup.inactive");
134 }
135
136 drawBox(0, 0, getWidth(), getHeight(), radioGroupColor, radioGroupColor,
137 3, false);
138
139 hLineXY(1, 0, StringUtils.width(label) + 2, ' ', radioGroupColor);
140 putStringXY(2, 0, label, radioGroupColor);
141 }
142
143 // ------------------------------------------------------------------------
144 // TRadioGroup ------------------------------------------------------------
145 // ------------------------------------------------------------------------
146
147 /**
148 * Get the radio button ID that was selected.
149 *
150 * @return ID of the selected button, or 0 if no button is selected
151 */
152 public int getSelected() {
153 if (selectedButton == null) {
154 return 0;
155 }
156 return selectedButton.getId();
157 }
158
159 /**
160 * Set the new selected radio button. 1-based.
161 *
162 * @param id ID of the selected button, or 0 to unselect
163 */
164 public void setSelected(final int id) {
165 if ((id < 0) || (id > getChildren().size())) {
166 return;
167 }
168
169 for (TWidget widget: getChildren()) {
170 ((TRadioButton) widget).selected = false;
171 }
172 if (id == 0) {
173 selectedButton = null;
174 return;
175 }
176 assert ((id > 0) && (id <= getChildren().size()));
177 TRadioButton button = (TRadioButton) (getChildren().get(id - 1));
178 button.selected = true;
179 selectedButton = button;
180 }
181
182 /**
183 * Get the radio button that was selected.
184 *
185 * @return the selected button, or null if no button is selected
186 */
187 public TRadioButton getSelectedButton() {
188 return selectedButton;
189 }
190
191 /**
192 * Convenience function to add a radio button to this group.
193 *
194 * @param label label to display next to (right of) the radiobutton
195 * @param selected if true, this will be the selected radiobutton
196 * @return the new radio button
197 */
198 public TRadioButton addRadioButton(final String label,
199 final boolean selected) {
200
201 TRadioButton button = addRadioButton(label);
202 setSelected(button.id);
203 return button;
204 }
205
206 /**
207 * Convenience function to add a radio button to this group.
208 *
209 * @param label label to display next to (right of) the radiobutton
210 * @return the new radio button
211 */
212 public TRadioButton addRadioButton(final String label) {
213 return new TRadioButton(this, 0, 0, label, 0);
214 }
215
216 /**
217 * Package private method for RadioButton to add itself to a RadioGroup
218 * container.
219 *
220 * @param button the button to add
221 */
222 void addRadioButton(final TRadioButton button) {
223 super.setHeight(getChildren().size() + 2);
224 button.setX(1);
225 button.setY(getChildren().size());
226 button.id = getChildren().size();
227 String label = button.getMnemonic().getRawLabel();
228
229 if (StringUtils.width(label) + 4 > getWidth()) {
230 super.setWidth(StringUtils.width(label) + 7);
231 }
232
233 if (getParent().getLayoutManager() != null) {
234 getParent().getLayoutManager().resetSize(this);
235 }
236
237 // Default to the first item on the list.
238 activate(getChildren().get(0));
239 }
240
241 /**
242 * Get the requires selection flag.
243 *
244 * @return true if this radiogroup requires that one of the buttons be
245 * selected
246 */
247 public boolean getRequiresSelection() {
248 return requiresSelection;
249 }
250
251 /**
252 * Set the requires selection flag.
253 *
254 * @param requiresSelection if true, then this radiogroup requires that
255 * one of the buttons be selected
256 */
257 public void setRequiresSelection(final boolean requiresSelection) {
258 this.requiresSelection = requiresSelection;
259 if (requiresSelection) {
260 if ((getChildren().size() > 0) && (selectedButton == null)) {
261 setSelected(1);
262 }
263 }
264 }
265
266 }