Class DatePicker
CalendarView in a popup, and this class is the wiring between them.
new DatePicker() // a date, with a calendar
new DatePicker().setGranularity(MINUTE) // a date and a time; the popup gains a time row
new DatePicker().setGranularity(MONTH) // a month picker
DatePicker.ofRange() // a period: two fields, one calendar
DatePicker.ofRange().setGranularity(MONTH) // a period of whole months
Composition rather than modes. The typing, the segments and the validity are
DateField's and are not reimplemented here; the grid, the bounds and the marks are
CalendarView's. What this class owns is exactly three things: the trailing button, when
the popup is open, and keeping the two halves in step.
Because the field is a widget rather than a painted region, a period is two fields with the caret moving between them on Tab, the clipboard works, and a screen reader walks a subtree that was already described. The picker paints one box around them so it reads as one control.
The popup takes no focus in a window of its own, which is the toolkit's popup contract and not this widget's choice: the field keeps the keyboard, and the navigation keys are forwarded to the grid while it is open, so Up, Down, PageUp, PageDown and Enter drive the calendar and the digits still reach the segments. In the in-scene presentation the overlay holds the focus instead and forwards every key and every character the same way, so the two presentations type alike. At an hour granularity or finer the popup carries a time row under the grid, and Tab walks the card from top to bottom, the header, the grid and that row. A pointer click in the popup's window makes it the desktop's key window; the keys it then receives are handed on exactly as the field's would be, and closing the popup gives the owner window the keyboard back.
The presentation follows DisplayMode: a window of its own where the platform can place
one, an overlay inside the owner window where it cannot or where the owner is fullscreen, for the
reasons that type gives — and an application that documents
itself with screenshots asks for DisplayMode.IN_SCENE on purpose, because a native popup
is absent from a capture of the window. The presentation is chosen when the popup opens; one
already open in a window of its own when the owner enters or leaves fullscreen closes instead, as
if dismissed, and what the fields hold is left as it was.
Like every widget, it is touched from the UI thread only: each method that changes it checks, and throws on any other thread.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected Widget<?> Where a caption bound to this picker lands: on the single field, which is the node a reader arrives at; a range picker keeps it on the group, whose two ends are named "Start date" and "End date" for themselves.calendar()close()Closes the calendar.@Nullable LocalDatedate()@Nullable LocalDateTimedateTime()@Nullable DateFieldendField()field()protected voidhandleUserChange(Change.Aspect aspect) Runs this widget's application handler for a change it has just announced.booleanisOpen()static DatePickerofRange()A picker for a period: two fields with the calendar between them in range mode.protected voidWhat the composite says of itself: a single picker says nothing and is no node — its field is the picker a reader meets, carries the label bound to the picker, the popup state and the verbs that open and close it — and a range picker is a group that keeps the label over its two named ends.protected voidCalled when this widget leaves the scene: detached from the tree, moved into another scene (told this before theWidget.onAttached()of the scene it joins), or still in it when the scene's window closes, which detaches every widget the scene has.protected voidonLayout()Containers position children here (measure +Widget.layoutBox(float, float, float, float)per child).protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidWidget's own background/content, in local coordinates.The application's response to the user choosing: a date typed or picked from the grid, the end of a period, or a time of day.open()Opens the calendar.protected floatHow far beyond this widget's bounds its painting may reach, in logical points: its own painting and any descendant no ancestor clips (a drop shadow, a glow, a child positioned outside the parent's box).protected booleanThe box, the focus ring and a period's dash are the chrome around the fields and the button, which say everything a reader needs.@Nullable DateRangerange()setChronology(@Nullable Chronology chronology) The calendar system the field and the grid are drawn in; the value stays ISO.Where the picker's parts read today from: the calendar's ring and opening month, and the fields' first step on an empty segment.Sets the date.setDateFilter(@Nullable Predicate<LocalDate> filter) Which dates are acceptable, on the field and the grid alike.setDateTime(@Nullable LocalDateTime value) Sets date and time at once.setDisplayMode(DisplayMode mode) Asks for a presentation of the calendar; seeDisplayMode.How fine this picker goes, on its field (or both ends of a period) and on its calendar at once.setMaxDate(@Nullable LocalDate date) The latest acceptable date, on the field and the grid alike.setMinDate(@Nullable LocalDate date) The earliest acceptable date, on the field and the grid: the two enforce it at different moments (the grid refuses a click, the field holds a typed date and says it is invalid), and setting it in one place is what keeps them from disagreeing.Sets the period, filling both fields.@Nullable LocalTimetime()Methods inherited from class limn.scene.Widget
acceptsTextInput, accessibleLabelAccessKey, accessibleLabelText, add, add, announceChange, backdropReach, baselineOffset, baselineOffsetOf, caretRect, children, clipboard, clipHeight, clipsChildren, clipWidth, clipX, clipY, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedBackward, focusArrivedByTraversal, height, hitTest, hitTestChild, id, imageCursor, inheritanceHost, invalidate, invalidate, invalidateAccessible, isEnabled, isFocusable, isFocused, isRightToLeft, isSelfEnabled, isShowing, isVisible, isVisibleByItsOwnFlag, layoutBox, layoutDirection, locale, localToScene, localToSceneBounds, markNeedsContainedLayout, markNeedsLayout, markNeedsLayoutInPlace, maxHeight, maxWidth, measure, minHeight, minWidth, moveChild, moveChild, moveChild, neutralBase, notifyChange, notifyTextEdit, observeChanges, onAccessibilityAction, onAccessibilityChild, onAccessibilityChildAction, onAccessibilityChildIdentity, onAttached, onCanEdit, onCharTyped, onDragExit, onDragOver, onDragStart, onDrop, onEdit, onFocusGained, onFocusLost, onHitTest, onKeyEvent, onMouseEvent, onPaintOverlay, onPreedit, onSyntheticAction, overlayPassesPointer, paintChildren, paintsFromBackdrop, paintWidget, parent, remove, remove, requestFocus, requestFocus, revealInView, revealInView, runHandler, scene, sceneNanos, sceneToLocal, self, setAccessibleDescribedBy, setAccessibleDescription, setAccessibleDescription, setAccessibleIgnored, setAccessibleLabelledBy, setAccessibleName, setAccessibleName, setAccessibleRole, setControlSize, setCursor, setEnabled, setFocusable, setId, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setMaxHeight, setMaxWidth, setMinHeight, setMinWidth, setPresentedElsewhere, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, tooltipSource, width, x, y
-
Constructor Details
-
DatePicker
public DatePicker()A picker for a date.
-
-
Method Details
-
setGranularity
How fine this picker goes, on its field (or both ends of a period) and on its calendar at once.DateField.Granularity.MONTHmakes a month picker: the field shows a month and a year and the popup opens on the twelve months, where a pick is the selection.DateField.Granularity.YEARlikewise.DateField.Granularity.HOURand finer keep the day grid and add a time row under it.Set here and not on
field(): the calendar has to follow, and a field told alone would leave a month picker opening on days it cannot pick.- Parameters:
level- how fine to go- Returns:
- this
-
granularity
- Returns:
- how fine this picker goes;
DateField.Granularity.DAYunless it was changed
-
ofRange
A picker for a period: two fields with the calendar between them in range mode. Focus in the first field anchors the grid on the start and focus in the second on the end, and the grid writes back into whichever end is being filled.The period reads as one line packed at the start of the box, as it would be typed: the first date, an en dash a small gap after it, the second date a small gap after the dash, and whatever room the box has left after the second date, before the calendar button. The dash follows the first date as it fills.
- Returns:
- the picker
-
field
- Returns:
- the field this picker types into; the first of the two for a period
-
endField
- Returns:
- the second field of a period, or
nullfor a picker that is not one
-
calendar
- Returns:
- the grid this picker opens. Reach through it for anything the picker does not repeat:
CalendarView.setShowWeekNumbers(boolean),CalendarView.setDayMarks(java.util.function.Function<java.time.LocalDate, limn.components.date.DayMark>),CalendarView.setFirstDayOfWeek(java.time.DayOfWeek)
-
date
- Returns:
- the date, or
nullwhile the field is incomplete
-
time
- Returns:
- the time of day, or
nullunless this picker carries one and it is complete
-
dateTime
- Returns:
- date and time together, or
nullunless both are complete
-
range
- Returns:
- the period, or
nullunless this is a range picker with both ends filled
-
setDate
Sets the date. Reaches the field, which announces it, which is what this picker forwards.- Parameters:
date- the date, ornullto clear- Returns:
- this
-
setDateTime
Sets date and time at once.- Parameters:
value- the moment, ornullto clear- Returns:
- this
-
setRange
Sets the period, filling both fields.- Parameters:
range- the period, ornullto clear both ends- Returns:
- this
- Throws:
IllegalStateException- if this picker is not a range picker
-
setMinDate
The earliest acceptable date, on the field and the grid: the two enforce it at different moments (the grid refuses a click, the field holds a typed date and says it is invalid), and setting it in one place is what keeps them from disagreeing.- Parameters:
date- the bound, ornullfor none- Returns:
- this
-
setMaxDate
The latest acceptable date, on the field and the grid alike.- Parameters:
date- the bound, ornullfor none- Returns:
- this
-
setDateFilter
Which dates are acceptable, on the field and the grid alike. The grid calls it once per painted cell, so the obligationCalendarView.setDateFilter(java.util.function.Predicate<java.time.LocalDate>)states — cheap, and pure — is the one that binds here.- Parameters:
filter- the filter, ornullto accept every date- Returns:
- this
-
setChronology
The calendar system the field and the grid are drawn in; the value stays ISO.- Parameters:
chronology- the calendar, ornullto follow the language- Returns:
- this
-
setClock
Where the picker's parts read today from: the calendar's ring and opening month, and the fields' first step on an empty segment. SeeCalendarView.setClock(java.time.Clock).- Parameters:
clock- the clock, ornullfor the system's- Returns:
- this
-
isOpen
public boolean isOpen()- Returns:
- whether the calendar is showing
-
setDisplayMode
Asks for a presentation of the calendar; seeDisplayMode. DefaultDisplayMode.NATIVE_WINDOW, so the grid can extend past the window's edge the way a platform picker's does.A preference, not a guarantee. A calendar asked for
NATIVE_WINDOWis still drawn in scene on a window that cannot be positioned at an anchor (Wayland), and over a fullscreen window, for the reasonsDisplayModegives.IN_SCENEis always honoured. ReaddisplayMode()for what happened. Takes effect on the next open.- Parameters:
mode- what to ask for- Returns:
- this
-
displayMode
- Returns:
- how the calendar is presented: while it is open, what it actually chose, including a
fullscreen owner or a platform forcing
IN_SCENEover a request for a window. While it is closed, what was last asked for, since the next open decides afresh over the window as it is then.
-
open
Opens the calendar. Does nothing if it is already open or the picker is disabled, nor, in a scene, while the picker is hidden, drawn as nothing by a transform above it, or on its way out of its window.- Returns:
- this
-
close
Closes the calendar. -
onSelect
The application's response to the user choosing: a date typed or picked from the grid, the end of a period, or a time of day. The handler reads what it needs,date(),range()ordateTime().- Parameters:
listener- what to run, ornullto clear the slot- Returns:
- this
- Throws:
IllegalStateException- if a handler is already registered
-
handleUserChange
Description copied from class:WidgetRuns this widget's application handler for a change it has just announced. Called byWidget.runHandler(limn.scene.Change), and so byWidget.notifyChange(limn.scene.Change), only for aUSERorigin and after every watcher has run.A component overrides it once and switches on the aspect, reading its own accessors for the payload: a slider passes
value(), a combo boxselectedIndex(), a text fieldtext(). A component with no handler does not override it.An override that does not recognise the aspect must call
super, because a subclass of a component that has a handler inherits that component's dispatch through this method: aSearchFieldthat overrode this for its own aspect and did not chain would silently deleteTextField's. The ordering lives in the base class, this is the one link in it a subclass can break, and the contract test drives every subclass through its parent's gestures to catch one that does.- Overrides:
handleUserChangein classWidget<DatePicker>- Parameters:
aspect- what changed; the origin isUSERor this is not called
-
onDetached
protected void onDetached()Description copied from class:WidgetCalled when this widget leaves the scene: detached from the tree, moved into another scene (told this before theWidget.onAttached()of the scene it joins), or still in it when the scene's window closes, which detaches every widget the scene has. What was taken inWidget.onAttached()from something that outlives the window (a listener's place in a list of the process's, a resource of the system's) is given back here.Widget.scene()still answers the scene being left, and becomesnullonce this returns, so releasing something the scene owns needs no field of your own to remember it by. Fires bottom-up, so children run before their parent, and every one of them can still reach the scene.Release resources here, but GPU resources must be handed to
Scene.disposeLater(limn.graphics.GpuSurface)(disposal needs the owning GL context, which is only current inside a frame). Not called onWidget.setVisible(boolean). Default no-op.- Overrides:
onDetachedin classWidget<DatePicker>
-
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.Resolve the
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved.- Specified by:
onMeasurein classWidget<DatePicker>
-
onLayout
protected void onLayout()Description copied from class:WidgetContainers position children here (measure +Widget.layoutBox(float, float, float, float)per child).- Overrides:
onLayoutin classWidget<DatePicker>
-
paintOutset
protected float paintOutset()Description copied from class:WidgetHow far beyond this widget's bounds its painting may reach, in logical points: its own painting and any descendant no ancestor clips (a drop shadow, a glow, a child positioned outside the parent's box). Partial rendering uses it both ways:Widget.invalidate()damage grows by it, and a repaint pass skips this subtree only when bounds + outset miss the pass region; painting farther than declared leaves stale pixels.The work is divided by who knows the number. A widget declares what it paints itself outside its box:
Label's icon overhang, the focus ringButton,CheckboxandRadioButtondraw outside theirs. A widget that lays out children and does not clip them declares how far they may paint past it, because a ring on a child at its edge hangs past it too, and a pass landing only in that band would otherwise skip it and never reach the child. Every layout the toolkit ships does that by default with the reach the theme gives a focus ring, and takes another number through its publicpaintOverflow, which sets what this hook answers; a layout an application writes inherits both by extendinglimn.scene.layout.Container, and one that extends this class directly overrides this hook itself. A widget that clips its children declares only its own painting, since the clip bounds theirs.Asked of every widget a repaint pass considers, and on every
invalidate(), so an override answers in constant time without allocating: a number held or looked up, never a walk over the children. Default0: everything stays inside the bounds, which is true for most leaves.- Overrides:
paintOutsetin classWidget<DatePicker>
-
onPaint
Description copied from class:WidgetWidget's own background/content, in local coordinates.- Overrides:
onPaintin classWidget<DatePicker>
-
paintsDecoration
protected boolean paintsDecoration()The box, the focus ring and a period's dash are the chrome around the fields and the button, which say everything a reader needs. A single picker is no node, so the walk's paints-and-says-nothing guard named this class in every application's log and recommendedsetAccessibleName— the one call that would make the group a node again and leave the field nameless — orsetAccessibleIgnored, which would take the field and the button out with it. TheTabbedPaneandBackdropPanelcase; a range picker keeps its group and is never asked.- Overrides:
paintsDecorationin classWidget<DatePicker>- Returns:
true; what this widget draws frames its children
-
onAccessibility
What the composite says of itself: a single picker says nothing and is no node — its field is the picker a reader meets, carries the label bound to the picker, the popup state and the verbs that open and close it — and a range picker is a group that keeps the label over its two named ends. The expanded state this group once carried, and the verbs it accepted without publishing, are the field's now; the button is a plain press. The fields and the button are real children and describe themselves, which is the whole reason they are widgets.- Overrides:
onAccessibilityin classWidget<DatePicker>- Parameters:
a- the node being described; write into it, and never keep it
-
accessibleLabelTarget
Where a caption bound to this picker lands: on the single field, which is the node a reader arrives at; a range picker keeps it on the group, whose two ends are named "Start date" and "End date" for themselves.- Overrides:
accessibleLabelTargetin classWidget<DatePicker>- Returns:
- the widget that carries a label bound to this one;
thisby default - See Also:
-