#36 Use image scaling in example
[fanfix.git] / src / jexer / TCalendar.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 java.util.Calendar;
32 import java.util.GregorianCalendar;
33
34 import jexer.bits.CellAttributes;
35 import jexer.bits.GraphicsChars;
36 import jexer.event.TKeypressEvent;
37 import jexer.event.TMouseEvent;
38 import static jexer.TKeypress.*;
39
40 /**
41 * TCalendar is a date picker widget.
42 */
43 public class TCalendar extends TWidget {
44
45 // ------------------------------------------------------------------------
46 // Variables --------------------------------------------------------------
47 // ------------------------------------------------------------------------
48
49 /**
50 * The calendar being displayed.
51 */
52 private GregorianCalendar displayCalendar = new GregorianCalendar();
53
54 /**
55 * The calendar with the selected day.
56 */
57 private GregorianCalendar calendar = new GregorianCalendar();
58
59 /**
60 * The action to perform when the user changes the value of the calendar.
61 */
62 private TAction updateAction = null;
63
64 // ------------------------------------------------------------------------
65 // Constructors -----------------------------------------------------------
66 // ------------------------------------------------------------------------
67
68 /**
69 * Public constructor.
70 *
71 * @param parent parent widget
72 * @param x column relative to parent
73 * @param y row relative to parent
74 * @param updateAction action to call when the user changes the value of
75 * the calendar
76 */
77 public TCalendar(final TWidget parent, final int x, final int y,
78 final TAction updateAction) {
79
80 // Set parent and window
81 super(parent, x, y, 28, 8);
82
83 this.updateAction = updateAction;
84 }
85
86 // ------------------------------------------------------------------------
87 // Event handlers ---------------------------------------------------------
88 // ------------------------------------------------------------------------
89
90 /**
91 * Returns true if the mouse is currently on the left arrow.
92 *
93 * @param mouse mouse event
94 * @return true if the mouse is currently on the left arrow
95 */
96 private boolean mouseOnLeftArrow(final TMouseEvent mouse) {
97 if ((mouse.getY() == 0)
98 && (mouse.getX() == 1)
99 ) {
100 return true;
101 }
102 return false;
103 }
104
105 /**
106 * Returns true if the mouse is currently on the right arrow.
107 *
108 * @param mouse mouse event
109 * @return true if the mouse is currently on the right arrow
110 */
111 private boolean mouseOnRightArrow(final TMouseEvent mouse) {
112 if ((mouse.getY() == 0)
113 && (mouse.getX() == getWidth() - 2)
114 ) {
115 return true;
116 }
117 return false;
118 }
119
120 /**
121 * Handle mouse down clicks.
122 *
123 * @param mouse mouse button down event
124 */
125 @Override
126 public void onMouseDown(final TMouseEvent mouse) {
127 if ((mouseOnLeftArrow(mouse)) && (mouse.isMouse1())) {
128 displayCalendar.add(Calendar.MONTH, -1);
129 } else if ((mouseOnRightArrow(mouse)) && (mouse.isMouse1())) {
130 displayCalendar.add(Calendar.MONTH, 1);
131 } else if (mouse.isMouse1()) {
132 // Find the day this might correspond to, and set it.
133 int index = (mouse.getY() - 2) * 7 + (mouse.getX() / 4) + 1;
134 // System.err.println("index: " + index);
135
136 int lastDayNumber = displayCalendar.getActualMaximum(
137 Calendar.DAY_OF_MONTH);
138 GregorianCalendar firstOfMonth = new GregorianCalendar();
139 firstOfMonth.setTimeInMillis(displayCalendar.getTimeInMillis());
140 firstOfMonth.set(Calendar.DAY_OF_MONTH, 1);
141 int dayOf1st = firstOfMonth.get(Calendar.DAY_OF_WEEK) - 1;
142 // System.err.println("dayOf1st: " + dayOf1st);
143
144 int day = index - dayOf1st;
145 // System.err.println("day: " + day);
146
147 if ((day < 1) || (day > lastDayNumber)) {
148 return;
149 }
150 calendar.setTimeInMillis(displayCalendar.getTimeInMillis());
151 calendar.set(Calendar.DAY_OF_MONTH, day);
152 }
153 }
154
155 /**
156 * Handle mouse double click.
157 *
158 * @param mouse mouse double click event
159 */
160 @Override
161 public void onMouseDoubleClick(final TMouseEvent mouse) {
162 if (updateAction != null) {
163 updateAction.DO();
164 }
165 }
166
167 /**
168 * Handle keystrokes.
169 *
170 * @param keypress keystroke event
171 */
172 @Override
173 public void onKeypress(final TKeypressEvent keypress) {
174 int increment = 0;
175
176 if (keypress.equals(kbUp)) {
177 increment = -7;
178 } else if (keypress.equals(kbDown)) {
179 increment = 7;
180 } else if (keypress.equals(kbLeft)) {
181 increment = -1;
182 } else if (keypress.equals(kbRight)) {
183 increment = 1;
184 } else if (keypress.equals(kbEnter)) {
185 if (updateAction != null) {
186 updateAction.DO();
187 }
188 return;
189 } else {
190 // Pass to parent for the things we don't care about.
191 super.onKeypress(keypress);
192 return;
193 }
194
195 if (increment != 0) {
196 calendar.add(Calendar.DAY_OF_YEAR, increment);
197
198 if ((displayCalendar.get(Calendar.MONTH) != calendar.get(
199 Calendar.MONTH))
200 || (displayCalendar.get(Calendar.YEAR) != calendar.get(
201 Calendar.YEAR))
202 ) {
203 if (increment < 0) {
204 displayCalendar.add(Calendar.MONTH, -1);
205 } else {
206 displayCalendar.add(Calendar.MONTH, 1);
207 }
208 }
209 }
210
211 }
212
213 // ------------------------------------------------------------------------
214 // TWidget ----------------------------------------------------------------
215 // ------------------------------------------------------------------------
216
217 /**
218 * Draw the combobox down arrow.
219 */
220 @Override
221 public void draw() {
222 CellAttributes backgroundColor = getTheme().getColor(
223 "tcalendar.background");
224 CellAttributes dayColor = getTheme().getColor(
225 "tcalendar.day");
226 CellAttributes selectedDayColor = getTheme().getColor(
227 "tcalendar.day.selected");
228 CellAttributes arrowColor = getTheme().getColor(
229 "tcalendar.arrow");
230 CellAttributes titleColor = getTheme().getColor(
231 "tcalendar.title");
232
233 // Fill in the interior background
234 for (int i = 0; i < getHeight(); i++) {
235 hLineXY(0, i, getWidth(), ' ', backgroundColor);
236 }
237
238 // Draw the title
239 String title = String.format("%tB %tY", displayCalendar,
240 displayCalendar);
241 int titleLeft = (getWidth() - title.length() - 2) / 2;
242 putCharXY(titleLeft, 0, ' ', titleColor);
243 putStringXY(titleLeft + 1, 0, title, titleColor);
244 putCharXY(titleLeft + title.length() + 1, 0, ' ',
245 titleColor);
246
247 // Arrows
248 putCharXY(1, 0, GraphicsChars.LEFTARROW, arrowColor);
249 putCharXY(getWidth() - 2, 0, GraphicsChars.RIGHTARROW,
250 arrowColor);
251
252 /*
253 * Now draw out the days.
254 */
255 putStringXY(0, 1, " S M T W T F S ", dayColor);
256 int lastDayNumber = displayCalendar.getActualMaximum(
257 Calendar.DAY_OF_MONTH);
258 GregorianCalendar firstOfMonth = new GregorianCalendar();
259 firstOfMonth.setTimeInMillis(displayCalendar.getTimeInMillis());
260 firstOfMonth.set(Calendar.DAY_OF_MONTH, 1);
261 int dayOf1st = firstOfMonth.get(Calendar.DAY_OF_WEEK) - 1;
262 int dayColumn = dayOf1st * 4;
263 int row = 2;
264
265 int dayOfMonth = 1;
266 while (dayOfMonth <= lastDayNumber) {
267 if (dayColumn == 4 * 7) {
268 dayColumn = 0;
269 row++;
270 }
271 if ((dayOfMonth == calendar.get(Calendar.DAY_OF_MONTH))
272 && (displayCalendar.get(Calendar.MONTH) == calendar.get(
273 Calendar.MONTH))
274 && (displayCalendar.get(Calendar.YEAR) == calendar.get(
275 Calendar.YEAR))
276 ) {
277 putStringXY(dayColumn, row,
278 String.format(" %2d ", dayOfMonth), selectedDayColor);
279 } else {
280 putStringXY(dayColumn, row,
281 String.format(" %2d ", dayOfMonth), dayColor);
282 }
283 dayColumn += 4;
284 dayOfMonth++;
285 }
286
287 }
288
289 // ------------------------------------------------------------------------
290 // TCalendar --------------------------------------------------------------
291 // ------------------------------------------------------------------------
292
293 /**
294 * Get calendar value.
295 *
296 * @return the current calendar value (clone instance)
297 */
298 public Calendar getValue() {
299 return (Calendar) calendar.clone();
300 }
301
302 /**
303 * Set calendar value.
304 *
305 * @param calendar the new value to use
306 */
307 public final void setValue(final Calendar calendar) {
308 this.calendar.setTimeInMillis(calendar.getTimeInMillis());
309 }
310
311 /**
312 * Set calendar value.
313 *
314 * @param millis the millis to set to
315 */
316 public final void setValue(final long millis) {
317 this.calendar.setTimeInMillis(millis);
318 }
319
320 }