2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.util
.Calendar
;
32 import java
.util
.GregorianCalendar
;
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
.*;
41 * TCalendar is a date picker widget.
43 public class TCalendar
extends TWidget
{
45 // ------------------------------------------------------------------------
46 // Variables --------------------------------------------------------------
47 // ------------------------------------------------------------------------
50 * The calendar being displayed.
52 private GregorianCalendar displayCalendar
= new GregorianCalendar();
55 * The calendar with the selected day.
57 private GregorianCalendar calendar
= new GregorianCalendar();
60 * The action to perform when the user changes the value of the calendar.
62 private TAction updateAction
= null;
64 // ------------------------------------------------------------------------
65 // Constructors -----------------------------------------------------------
66 // ------------------------------------------------------------------------
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
77 public TCalendar(final TWidget parent
, final int x
, final int y
,
78 final TAction updateAction
) {
80 // Set parent and window
81 super(parent
, x
, y
, 28, 8);
83 this.updateAction
= updateAction
;
86 // ------------------------------------------------------------------------
87 // Event handlers ---------------------------------------------------------
88 // ------------------------------------------------------------------------
91 * Returns true if the mouse is currently on the left arrow.
93 * @param mouse mouse event
94 * @return true if the mouse is currently on the left arrow
96 private boolean mouseOnLeftArrow(final TMouseEvent mouse
) {
97 if ((mouse
.getY() == 0)
98 && (mouse
.getX() == 1)
106 * Returns true if the mouse is currently on the right arrow.
108 * @param mouse mouse event
109 * @return true if the mouse is currently on the right arrow
111 private boolean mouseOnRightArrow(final TMouseEvent mouse
) {
112 if ((mouse
.getY() == 0)
113 && (mouse
.getX() == getWidth() - 2)
121 * Handle mouse down clicks.
123 * @param mouse mouse button down event
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);
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);
144 int day
= index
- dayOf1st
;
145 // System.err.println("day: " + day);
147 if ((day
< 1) || (day
> lastDayNumber
)) {
150 calendar
.setTimeInMillis(displayCalendar
.getTimeInMillis());
151 calendar
.set(Calendar
.DAY_OF_MONTH
, day
);
156 * Handle mouse double click.
158 * @param mouse mouse double click event
161 public void onMouseDoubleClick(final TMouseEvent mouse
) {
162 if (updateAction
!= null) {
170 * @param keypress keystroke event
173 public void onKeypress(final TKeypressEvent keypress
) {
176 if (keypress
.equals(kbUp
)) {
178 } else if (keypress
.equals(kbDown
)) {
180 } else if (keypress
.equals(kbLeft
)) {
182 } else if (keypress
.equals(kbRight
)) {
184 } else if (keypress
.equals(kbEnter
)) {
185 if (updateAction
!= null) {
190 // Pass to parent for the things we don't care about.
191 super.onKeypress(keypress
);
195 if (increment
!= 0) {
196 calendar
.add(Calendar
.DAY_OF_YEAR
, increment
);
198 if ((displayCalendar
.get(Calendar
.MONTH
) != calendar
.get(
200 || (displayCalendar
.get(Calendar
.YEAR
) != calendar
.get(
204 displayCalendar
.add(Calendar
.MONTH
, -1);
206 displayCalendar
.add(Calendar
.MONTH
, 1);
213 // ------------------------------------------------------------------------
214 // TWidget ----------------------------------------------------------------
215 // ------------------------------------------------------------------------
218 * Draw the combobox down arrow.
222 CellAttributes backgroundColor
= getTheme().getColor(
223 "tcalendar.background");
224 CellAttributes dayColor
= getTheme().getColor(
226 CellAttributes selectedDayColor
= getTheme().getColor(
227 "tcalendar.day.selected");
228 CellAttributes arrowColor
= getTheme().getColor(
230 CellAttributes titleColor
= getTheme().getColor(
233 // Fill in the interior background
234 for (int i
= 0; i
< getHeight(); i
++) {
235 hLineXY(0, i
, getWidth(), ' ', backgroundColor
);
239 String title
= String
.format("%tB %tY", 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, ' ',
248 putCharXY(1, 0, GraphicsChars
.LEFTARROW
, arrowColor
);
249 putCharXY(getWidth() - 2, 0, GraphicsChars
.RIGHTARROW
,
253 * Now draw out the days.
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;
266 while (dayOfMonth
<= lastDayNumber
) {
267 if (dayColumn
== 4 * 7) {
271 if ((dayOfMonth
== calendar
.get(Calendar
.DAY_OF_MONTH
))
272 && (displayCalendar
.get(Calendar
.MONTH
) == calendar
.get(
274 && (displayCalendar
.get(Calendar
.YEAR
) == calendar
.get(
277 putStringXY(dayColumn
, row
,
278 String
.format(" %2d ", dayOfMonth
), selectedDayColor
);
280 putStringXY(dayColumn
, row
,
281 String
.format(" %2d ", dayOfMonth
), dayColor
);
289 // ------------------------------------------------------------------------
290 // TCalendar --------------------------------------------------------------
291 // ------------------------------------------------------------------------
294 * Get calendar value.
296 * @return the current calendar value (clone instance)
298 public Calendar
getValue() {
299 return (Calendar
) calendar
.clone();
303 * Set calendar value.
305 * @param calendar the new value to use
307 public final void setValue(final Calendar calendar
) {
308 this.calendar
.setTimeInMillis(calendar
.getTimeInMillis());
312 * Set calendar value.
314 * @param millis the millis to set to
316 public final void setValue(final long millis
) {
317 this.calendar
.setTimeInMillis(millis
);