TimeField
A segmented input for a time of day. Each part — hour, minute, optional second and optional AM/PM — is edited on its own with the keyboard, and the field keeps its width while digits are typed. DatePicker uses it to edit the time of a date.
#Import
use gpui_kit::component::time_field::{
HourCycle, TimeField, TimeFieldEvent, TimeFieldState, TimePrecision,
};// Installed in ui/components. That directory is on the Slint include path, so import by file name:
import { TimePrecision, HourCycle, TimeField } from "time-field.slint";use iced::widget::{column, container, mouse_area, row, scrollable, svg, text};
use iced::{Alignment, Element, Length, Task, Theme};#Usage
#Basic Time Field
let time = cx.new(|cx| TimeFieldState::new(window, cx));
TimeField::new(&time)VerticalLayout {
spacing: 12px;
cross-axis-alignment: center;
TimeField {
hour: 9;
minute: 30;
}
TimeField {
hour: 0;
minute: 0;
}
TimeField {
hour: 23;
minute: 59;
}
}// Slint's first box is three fields — 09:30, 00:00 and 23:59 — over a
// 24-hour clock, each one the caller's own value.
let basic = column![
TimeField::new("basic-0")
.hour(app.basic[0].hour)
.minute(app.basic[0].minute)
.on_change(|change| Message::Basic { index: 0, change }),
TimeField::new("basic-1")
.hour(app.basic[1].hour)
.minute(app.basic[1].minute)
.on_change(|change| Message::Basic { index: 1, change }),
TimeField::new("basic-2")
.hour(app.basic[2].hour)
.minute(app.basic[2].minute)
.on_change(|change| Message::Basic { index: 2, change }),
muted_line(&format!(
"The first field reads {}. Each segment is a field of its own, and \
the caller owns the value.",
app.basic[0].hhmm()
)),
]
.spacing(12.0);The field starts at 00:00. Set a value with set_time, which does not emit an event:
use chrono::NaiveTime;
time.update(cx, |state, cx| {
state.set_time(NaiveTime::from_hms_opt(9, 30, 0).unwrap(), window, cx);
});SlintNo Slint version of this example yet.
#With Seconds
let time = cx.new(|cx| {
TimeFieldState::new(window, cx).precision(TimePrecision::Second)
});
TimeField::new(&time) // 09:30:15HorizontalLayout {
alignment: center;
TimeField {
hour: 14;
minute: 5;
second: 42;
precision: TimePrecision.hours_minutes_seconds;
}
}// `precision(TimePrecision::HoursMinutesSeconds)` draws the third segment,
// the Slint `with-seconds`.
let seconds = column![
TimeField::new("seconds")
.hour(app.seconds.hour)
.minute(app.seconds.minute)
.second(app.seconds.second)
.precision(TimePrecision::HoursMinutesSeconds)
.on_change(Message::Seconds),
muted_line(&format!(
"With seconds: {} — the third segment appears with the precision.",
app.seconds.hhmmss()
)),
]
.spacing(12.0);#12-Hour Clock
GPUINo GPUI version of this example yet.
SlintNo Slint version of this example yet.
// `hour_cycle(HourCycle::H12)` shows 12–11 and the AM/PM label. iced hands a
// widget no key event, so GPUI's `a`/`p` toggle has nowhere to live and the
// label is read-only, as it is in the Slint component.
let h12 = column![
TimeField::new("h12-0")
.hour(app.h12[0].hour)
.minute(app.h12[0].minute)
.hour_cycle(HourCycle::H12)
.on_change(|change| Message::H12 { index: 0, change }),
TimeField::new("h12-1")
.hour(app.h12[1].hour)
.minute(app.h12[1].minute)
.hour_cycle(HourCycle::H12)
.on_change(|change| Message::H12 { index: 1, change }),
TimeField::new("h12-2")
.hour(app.h12[2].hour)
.minute(app.h12[2].minute)
.hour_cycle(HourCycle::H12)
.on_change(|change| Message::H12 { index: 2, change }),
muted_line(&format!(
"12-hour clock: {}, {} and {}.",
app.h12[0].h12(),
app.h12[1].h12(),
app.h12[2].h12()
)),
]
.spacing(12.0);The field uses a 24-hour clock by default. HourCycle::H12 shows hours from 12 to 11 followed by an AM/PM segment:
let time = cx.new(|cx| {
TimeFieldState::new(window, cx).hour_cycle(HourCycle::H12)
});
TimeField::new(&time) // 09:30 PMVerticalLayout {
spacing: 12px;
cross-axis-alignment: center;
TimeField {
hour: 9;
minute: 30;
hour-cycle: HourCycle.h12;
}
TimeField {
hour: 14;
minute: 5;
hour-cycle: HourCycle.h12;
}
TimeField {
hour: 0;
minute: 0;
hour-cycle: HourCycle.h12;
}
}#Sizes, Disabled and Invalid
TimeField::new(&time).small()
TimeField::new(&time).large()
TimeField::new(&time).disabled(true)
// Show the owner's validation result; edits are not rejected.
TimeField::new(&time).invalid(true)VerticalLayout {
spacing: 12px;
alignment: start;
TimeField {
hour: 8;
minute: 15;
size: ControlSize.small;
}
TimeField {
hour: 8;
minute: 15;
}
TimeField {
hour: 8;
minute: 15;
size: ControlSize.large;
}
TimeField {
hour: 8;
minute: 15;
enabled: false;
}
TimeField {
hour: 99;
minute: 99;
invalid: true;
}
}// The size ladder is 20 / 24 / 32 / 40, the Slint `control-height`; a
// disabled field is the muted fill and text, because iced has no whole-field
// opacity; and an invalid field keeps the danger edge while it is edited.
let sizes = column![
row![
TimeField::new("size-small")
.hour(app.sizes[0].hour)
.minute(app.sizes[0].minute)
.size(ControlSize::Small)
.on_change(|change| Message::Size { index: 0, change }),
TimeField::new("size-medium")
.hour(app.sizes[1].hour)
.minute(app.sizes[1].minute)
.size(ControlSize::Medium)
.on_change(|change| Message::Size { index: 1, change }),
TimeField::new("size-large")
.hour(app.sizes[2].hour)
.minute(app.sizes[2].minute)
.size(ControlSize::Large)
.on_change(|change| Message::Size { index: 2, change }),
]
.spacing(16.0)
.align_y(Alignment::Center),
muted_line("The size ladder: 24 / 32 / 40, the Slint theme's control-height."),
TimeField::new("disabled")
.hour(app.disabled.hour)
.minute(app.disabled.minute)
.disabled(true),
muted_line("disabled(true) refuses input and draws the muted field."),
TimeField::new("invalid")
.hour(app.invalid.hour)
.minute(app.invalid.minute)
.invalid(true)
.on_change(Message::Invalid),
muted_line("invalid(true): the frame's edge takes the danger colour, and edits are still accepted."),
]
.spacing(12.0);#Handle Changes
GPUINo GPUI version of this example yet.
SlintNo Slint version of this example yet.
// `on_change` reports the time an edit left behind — the Slint
// `changed(hour, minute, second)` — and the caller stores it. Type into a
// segment and the readout below moves.
let changes = column![
TimeField::new("changes")
.hour(app.changes.hour)
.minute(app.changes.minute)
.on_change(Message::Changes),
muted_line(&format!("on_change reported: {}.", app.last)),
]
.spacing(8.0);User edits emit TimeFieldEvent::Change with the new time:
cx.subscribe(&time, |this, _, event, cx| match event {
TimeFieldEvent::Change(time) => {
this.reminder = *time;
cx.notify();
}
});SlintNo Slint version of this example yet.
#Keyboard
| Key | Action |
|---|---|
Up / Down | Step the selected segment; it wraps without changing the next unit |
Left / Right | Move between segments |
Tab / Shift-Tab | Move between segments, then leave the field |
0–9 | Type the selected segment and move on once it is complete |
a / p | Set AM or PM on a 12-hour clock |
Backspace / Delete | Reset the selected segment |