Skip to content

qt_quick: dateTimeInput has no calendar/date-picker widget, just a formatted text field #1024

Closed

Description

@Yaraslaut

Summary

morph::ui::dateTimeInput promises a date (or date-and-time) input, but the Qt Quick backend's implementation, src/qt_quick/qml/MorphDateTimeInput.qml, is a plain TextField with a format-hinting placeholder ("yyyy-mm-dd" or "yyyy-mm-dd hh:mm") and C++-side parse/format on blur. There is no calendar popup, spinner, or any clickable date-picking affordance — the node's own file comment says as much: "A date, or a date and a time, typed in the display zone."

For an app author following a design that expects a real date picker (click a field, pick a day from a calendar), dateTimeInput does not deliver one; it is behaviorally identical to a textInput with a date-shaped placeholder and validation. This was surfaced by a downstream user (LASTRADA's LicenceServer) expecting dateTimeInput to give users a picker for seat/feature expiry dates, since the node's name and spec entry (docs/spec/ui/document.md ui/1 table) suggest exactly that.

Repro

Author any screen with ui::dateTimeInput(value, label). Run it on the Qt Quick frontend. Click the field: a text cursor appears, no calendar.

What's missing

  • A calendar/date-picker popup (or at minimum an optional one, toggled by mode or a new option) in the Qt Quick backend's MorphDateTimeInput.qml, matching what a user would expect from a field called "date input" rather than "formatted text input."
  • Searched src/qt_quick/qml/ for any calendar component (grep -il calendar, datepick): none exists in the tree at the inspected revision.

Scope

  1. A spec decision in docs/spec/ui/document.md (and backend_contract.md) on whether dateTimeInput should default to a picker, opt into one via a new option, or whether a distinct node (datePicker?) is warranted instead of changing dateTimeInput's existing contract.
  2. src/qt_quick/qml/MorphDateTimeInput.qml: add a calendar popup (Qt Quick Controls has Calendar/DatePicker-equivalent building blocks via QtQuick.Controls or a custom popup) triggered by a button/icon inside the field, writing back through the same fire("edit", text) path so the C++ side needs no change.
  3. TUI backend (src/tui/) parity, or an explicit decision that the picker is Qt-Quick-only (terminal apps reasonably keep typed dates).

Verification status

Reproduced by reading the code: src/qt_quick/qml/MorphDateTimeInput.qml (full file, 45 lines) is a MorphField wrapping one TextField; no Calendar, Popup, or date-grid component is instantiated or imported. include/morph/ui/author.hpp's dateTimeInput(value, label, commit) free function exposes no option that would change this (no mode, despite docs/spec/ui/document.md's ui/1 table listing mode as one of dateTimeInput's fields — the authoring convenience wrapper omits it). Not yet checked whether mode is read by the interpreter/view layer even though the author wrapper omits it (i.e. whether a hand-built document node with "mode" set would do anything differently) — worth confirming before scoping the fix, since if mode already exists in the document schema but is simply unexposed in author.hpp, the fix may be narrower than described above.

Activity

  1. Yaraslaut commented on Oct 21, 2026

    @Yaraslaut
    MemberAuthor

    Additional finding from trying to adopt dateTimeInput for a plain string-typed "YYYY-MM-DD" draft field (LicenceServer's seat/feature dates, stored as std::string, not a timestamp type): it's not a drop-in replacement for textInput even setting the missing-picker issue aside.

    include/morph/ui/interpreter.hpp (~line 6061-6084), the dateTimeInput document-node handler:

    spec.value = slotProp<std::optional<time::Timestamp>>([element]() -> std::optional<time::Timestamp> {
        time::DateTime const* const instant = element->draft.get().asTimestamp();
        return instant == nullptr ? std::nullopt : std::optional<time::Timestamp>{time::Timestamp{*instant}};
    });

    The bound value must be (or convert to) a time::Timestamp-shaped value via asTimestamp(); a plain string draft value that isn't already in that internal timestamp representation reads back as nullopt, so the field never displays what was typed and never round-trips through onCommit/onChange the way textInput does for the same kind of string field. Confirmed by swapping a working textInput-backed "YYYY-MM-DD" field to dateTimeInput with no other change: client.type(...) + reading the value back afterward returned empty every time (both via the GUI automation driver and by eye).

    This means an app with dates modeled as plain ISO date strings (a common, reasonable choice, especially for apps with pre-existing string-based persistence) cannot use dateTimeInput at all today, calendar widget aside — it would first need to migrate its draft/value model to whatever time::Timestamp/asTimestamp() expects. Worth covering explicitly in the spec decision this issue asks for in its Scope section: either dateTimeInput should also accept a plain ISO date/datetime string value (coercing it, the way other inputs coalesce loosely-typed drafts), or the docs should say plainly that a string-backed date field must convert to morph's timestamp type first, with an example of how.

  2. Yaraslaut commented on Oct 22, 2026

    @Yaraslaut
    MemberAuthor

    Confirmed the open question in the verification status: mode already exists in the document schema and is read by the interpreter (interpreter.hpp: spec.mode = onceText("mode") == "date" ? DateMode::Date : DateMode::DateTime), but author::dateTimeInput(value, label, commit) has no parameter for it and never writes the "mode" key — so a hand-authored document node with .put("mode", "date") set directly would already render date-only, while the public wrapper function cannot reach that path at all. The fix for this half of the gap is narrow: add a mode parameter (or an options struct matching textInput's pattern) to author::dateTimeInput that writes "mode" when set to date-only. This is separate from the calendar-popup widget work tracked in this issue's main body — LicenceServer needs the mode fix to show a date without inviting a time-of-day the underlying value never carries.

  3. Yaraslaut commented on Oct 22, 2026

    @Yaraslaut
    MemberAuthor

    Found and fixed a second, independent bug in the calendar popup itself while verifying it end-to-end against a real click (not just reading the code): MorphDateTimeInput.qml's openPicker() function sets picker.viewDate, picker.hour, picker.minute and picker.hasDay before calling popup.open() -- but the Popup's actual id is popup, not picker (every other reference in the file correctly uses popup.*). This is a plain reference-name typo: picker is never declared anywhere, so openPicker() throws a ReferenceError on its very first line and the function returns having never called popup.open(). Since QML swallows an exception thrown from a signal handler as a console-only warning, the calendar trigger renders and is clickable, but clicking it has had zero visible effect since the feature was written -- it looks like nothing happens, no error shown anywhere a normal diagnostic workflow (screenshots, log files, GUI test assertions) would catch, since the thrown exception never reaches any of those. Confirmed via a temporary try { root.openPicker() } catch (e) { field.text = "ERROR:" + e } instrumentation: the caught value was exactly ReferenceError: picker is not defined. Fix is a 4-line rename (picker. -> popup.) in openPicker(); verified the popup opens and a day can be picked after the fix.

  4. Yaraslaut commented on Oct 23, 2026

    @Yaraslaut
    MemberAuthor

    Partially addressed by #1038, which leaves this issue open.

    What #1038 does: dateTimeInput() gains a DateTimeInputOptions overload that exposes mode. This answers the open question in this issue's verification status: mode was already in the document schema and handled by the interpreter. Only the positional author wrapper didn't expose it.

    What is still missing (the core of this issue): the Qt Quick backend still has no calendar or date picker. #1038 doesn't change src/qt_quick/qml/MorphDateTimeInput.qml, so clicking the field still gives a text cursor. The spec decision in Scope item 1 (picker by default, a picker opted into via mode or a new option, or a separate node) is also still open, and so is the TUI-parity decision.

    Verification status: inferred from the PR's diff (file list and author.hpp hunk), not from running the app.

    Close when: the Qt Quick dateTimeInput offers a clickable date-picking affordance, and the spec records how it is chosen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions