Merge branch 'subtree'
[fanfix.git] / src / be / nikiroo / jexer / TTableCellRenderer.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 David "Niki" ROULET
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 David ROULET [niki@nikiroo.be]
27 * @version 1
28 */
29 package be.nikiroo.jexer;
30
31 import jexer.bits.CellAttributes;
32 import jexer.bits.ColorTheme;
33
34 /**
35 * A {@link TTable} cell renderer allows you to customize the way a single cell
36 * will be displayed on screen.
37 * <p>
38 * It can be used in a {@link TTable} for the haeders or the separators or in a
39 * {@link TTableColumn} for the data.
40 *
41 * @author niki
42 */
43 abstract public class TTableCellRenderer {
44 private CellRendererMode mode;
45
46 /**
47 * The simple renderer mode.
48 *
49 * @author niki
50 */
51 public enum CellRendererMode {
52 /** Normal text mode */
53 NORMAL,
54 /** Only display a separator */
55 SEPARATOR,
56 /** Header text mode */
57 HEADER,
58 /** Both HEADER and SEPARATOR at once */
59 HEADER_SEPARATOR;
60
61 /**
62 * This mode represents a separator.
63 *
64 * @return TRUE for separators
65 */
66 public boolean isSeparator() {
67 return this == SEPARATOR || this == HEADER_SEPARATOR;
68 }
69
70 /**
71 * This mode represents a header.
72 *
73 * @return TRUE for headers
74 */
75 public boolean isHeader() {
76 return this == HEADER || this == HEADER_SEPARATOR;
77 }
78 }
79
80 /**
81 * Create a new renderer of the given mode.
82 *
83 * @param mode
84 * the renderer mode, cannot be NULL
85 */
86 public TTableCellRenderer(CellRendererMode mode) {
87 if (mode == null) {
88 throw new IllegalArgumentException(
89 "Cannot create a renderer of type NULL");
90 }
91
92 this.mode = mode;
93 }
94
95 /**
96 * Render the given value.
97 *
98 * @param table
99 * the table to write on
100 * @param value
101 * the value to write
102 * @param rowIndex
103 * the row index in the table
104 * @param colIndex
105 * the column index in the table
106 * @param y
107 * the Y position at which to draw this row
108 */
109 abstract public void renderTableCell(TTable table, Object value,
110 int rowIndex, int colIndex, int y);
111
112 /**
113 * The mode of this {@link TTableCellRenderer}.
114 *
115 * @return the mode
116 */
117 public CellRendererMode getMode() {
118 return mode;
119 }
120
121 /**
122 * The cell attributes to use for the given state.
123 *
124 * @param theme
125 * the color theme to use
126 * @param isSelected
127 * TRUE if the cell is selected
128 * @param hasFocus
129 * TRUE if the cell has focus
130 *
131 * @return the attributes
132 */
133 public CellAttributes getCellAttributes(ColorTheme theme,
134 boolean isSelected, boolean hasFocus) {
135 return theme.getColor(getColorKey(isSelected, hasFocus));
136 }
137
138 /**
139 * Measure the width of the value.
140 *
141 * @param value
142 * the value to measure
143 *
144 * @return its width
145 */
146 public int getWidthOf(Object value) {
147 if (getMode().isSeparator()) {
148 return asText(null, 0, false).length();
149 }
150 return ("" + value).length();
151 }
152
153 /**
154 * The colour to use for the given state, specified as a Jexer colour key.
155 *
156 * @param isSelected
157 * TRUE if the cell is selected
158 * @param hasFocus
159 * TRUE if the cell has focus
160 *
161 * @return the colour key
162 */
163 protected String getColorKey(boolean isSelected, boolean hasFocus) {
164 if (mode.isHeader()) {
165 return "tlabel";
166 }
167
168 String colorKey = "tlist";
169 if (isSelected) {
170 colorKey += ".selected";
171 } else if (!hasFocus) {
172 colorKey += ".inactive";
173 }
174
175 return colorKey;
176 }
177
178 /**
179 * Return the X offset to use to draw a column at the given index.
180 *
181 * @param table
182 * the table to draw into
183 * @param colIndex
184 * the column index
185 *
186 * @return the offset
187 */
188 protected int getXOffset(TTable table, int colIndex) {
189 int xOffset = -table.getHorizontalValue();
190 for (int i = 0; i <= colIndex; i++) {
191 TTableColumn tcol = table.getColumns().get(i);
192 xOffset += tcol.getWidth();
193 if (i > 0) {
194 xOffset += table.getSeparatorRenderer().getWidthOf(null);
195 }
196 }
197
198 TTableColumn tcol = table.getColumns().get(colIndex);
199 if (!getMode().isSeparator()) {
200 xOffset -= tcol.getWidth();
201 }
202
203 return xOffset;
204 }
205
206 /**
207 * Return the text to use (usually the converted-to-text value, except for
208 * the special separator mode).
209 *
210 * @param value
211 * the value to get the text of
212 * @param width
213 * the width we should tale
214 * @param align
215 * the text to the right
216 *
217 * @return the {@link String} to display
218 */
219 protected String asText(Object value, int width, boolean rightAlign) {
220 if (getMode().isSeparator()) {
221 // some nice characters for the separator: ┃ │ |
222 return " │ ";
223 }
224
225 if (width <= 0) {
226 return "";
227 }
228
229 String format;
230 if (!rightAlign) {
231 // Left align
232 format = "%-" + width + "s";
233 } else {
234 // right align
235 format = "%" + width + "s";
236 }
237
238 return String.format(format, value);
239 }
240 }