DatePicker: finished features

This commit is contained in:
Florian Blasius 2024-05-21 11:48:12 +02:00 committed by Olivier Goffart
parent f75cedb893
commit 973ecac989
66 changed files with 1350 additions and 246 deletions

View file

@ -100,6 +100,10 @@ Files: internal/compiler/widgets/cupertino-base/_*.svg
Copyright: Material Icons <https://github.com/material-icons/material-icons/blob/master/LICENSE> Copyright: Material Icons <https://github.com/material-icons/material-icons/blob/master/LICENSE>
License: Apache-2.0 License: Apache-2.0
Files: internal/compiler/widgets/qt/_*.svg
Copyright: Material Icons <https://github.com/material-icons/material-icons/blob/master/LICENSE>
License: Apache-2.0
Files: internal/compiler/widgets/cosmic-base/_*.svg Files: internal/compiler/widgets/cosmic-base/_*.svg
Copyright: "Cosmic Icons" by System76 <https://github.com/pop-os/cosmic-icons> Copyright: "Cosmic Icons" by System76 <https://github.com/pop-os/cosmic-icons>
License: CC-BY-SA-4.0 License: CC-BY-SA-4.0

View file

@ -533,6 +533,13 @@ fn gen_corelib(
"slint_windowrc_set_logical_size", "slint_windowrc_set_logical_size",
"slint_windowrc_set_physical_size", "slint_windowrc_set_physical_size",
"slint_windowrc_color_scheme", "slint_windowrc_color_scheme",
"slint_windowrc_month_for_date",
"slint_windowrc_month_offset",
"slint_windowrc_format_date",
"slint_windowrc_date_now",
"slint_windowrc_week_days_short",
"slint_windowrc_valid_date",
"slint_windowrc_parse_date",
"slint_windowrc_dispatch_pointer_event", "slint_windowrc_dispatch_pointer_event",
"slint_windowrc_dispatch_key_event", "slint_windowrc_dispatch_key_event",
"slint_windowrc_dispatch_event", "slint_windowrc_dispatch_event",

View file

@ -169,6 +169,34 @@ pub fn use_24_hour_format() -> bool {
i_slint_core::date_time::use_24_hour_format() i_slint_core::date_time::use_24_hour_format()
} }
pub fn month_for_date(month: u32, year: i32) -> ModelRc<ModelRc<i32>> {
i_slint_core::date_time::month_for_date(month, year)
}
pub fn month_offset(month: u32, year: i32) -> i32 {
i_slint_core::date_time::month_offset(month, year)
}
pub fn format_date(format: &SharedString, day: u32, month: u32, year: i32) -> SharedString {
i_slint_core::date_time::format_date(format, day, month, year)
}
pub fn date_now() -> ModelRc<i32> {
i_slint_core::date_time::date_now()
}
pub fn week_days_short() -> ModelRc<SharedString> {
i_slint_core::date_time::week_days_short()
}
pub fn valid_date(date: &str, format: &str) -> bool {
i_slint_core::date_time::valid_date(date, format)
}
pub fn parse_date(date: &str, format: &str) -> ModelRc<i32> {
i_slint_core::date_time::parse_date(date, format)
}
/// internal re_exports used by the macro generated /// internal re_exports used by the macro generated
pub mod re_exports { pub mod re_exports {
pub use alloc::boxed::Box; pub use alloc::boxed::Box;

View file

@ -19,7 +19,10 @@ Use a date picker to let the user select a date.
- **`title`** (_in_ _string_): The text that is displayed at the top of the picker. - **`title`** (_in_ _string_): The text that is displayed at the top of the picker.
- **`cancel-label`** (_in_ _string_): The text written in the cancel button. - **`cancel-label`** (_in_ _string_): The text written in the cancel button.
- **`ok-label`** (_in_ _string_): The text written in the ok button. - **`ok-label`** (_in_ _string_): The text written in the ok button.
- **`date`**: (_in_ _DAte_): Set the initinal displayed date. - **`date`**: (_in_ _Date_): Set the initial displayed date.
- **`input-title`**: (_in_ _string_): Title that displayed on the date input `LineEdit`.
- **`input-placeholder`**: (_in_ _string_): Placeholder text that is displayed on the date input `LineEdit`.
- **`input-format`**: (_in_ _string_): Defines the format that is used to parse the text of `LineEdit`. For more details check the https://docs.rs/chrono/latest/chrono/format/strftime/index.html. (default `"%m/%d/%Y"`)
### Callbacks ### Callbacks

View file

@ -254,12 +254,12 @@ export component ControlsPage inherits Page {
close-on-click: false; close-on-click: false;
DatePicker { DatePicker {
date: { year: 2024, month: 5, day: 27 };
canceled => { canceled => {
date-picker.close(); date-picker.close();
} }
accepted(date) => { accepted(date) => {
debug(date);
date-picker.close(); date-picker.close();
} }
} }

View file

@ -60,6 +60,13 @@ pub enum BuiltinFunction {
Rgb, Rgb,
Hsv, Hsv,
ColorScheme, ColorScheme,
MonthForDate,
MonthOffset,
FormatDate,
DateNow,
WeekDaysShort,
ValidDate,
ParseDate,
TextInputFocused, TextInputFocused,
SetTextInputFocused, SetTextInputFocused,
ImplicitLayoutInfo(Orientation), ImplicitLayoutInfo(Orientation),
@ -245,9 +252,37 @@ impl BuiltinFunction {
)), )),
args: vec![], args: vec![],
}, },
BuiltinFunction::MonthForDate => Type::Function {
return_type: Box::new(Type::Array(Box::new(Type::Array(Box::new(Type::Int32))))),
args: vec![Type::Int32, Type::Int32],
},
BuiltinFunction::MonthOffset => Type::Function {
return_type: Box::new(Type::Int32),
args: vec![Type::Int32, Type::Int32],
},
BuiltinFunction::FormatDate => Type::Function {
return_type: Box::new(Type::String),
args: vec![Type::String, Type::Int32, Type::Int32, Type::Int32],
},
BuiltinFunction::WeekDaysShort => Type::Function {
return_type: Box::new(Type::Array(Box::new(Type::String))),
args: vec![],
},
BuiltinFunction::TextInputFocused => { BuiltinFunction::TextInputFocused => {
Type::Function { return_type: Box::new(Type::Bool), args: vec![] } Type::Function { return_type: Box::new(Type::Bool), args: vec![] }
} }
BuiltinFunction::DateNow => Type::Function {
return_type: Box::new(Type::Array(Box::new(Type::Int32))),
args: vec![],
},
BuiltinFunction::ValidDate => Type::Function {
return_type: Box::new(Type::Bool),
args: vec![Type::String, Type::String],
},
BuiltinFunction::ParseDate => Type::Function {
return_type: Box::new(Type::Array(Box::new(Type::Int32))),
args: vec![Type::String, Type::String],
},
BuiltinFunction::SetTextInputFocused => { BuiltinFunction::SetTextInputFocused => {
Type::Function { return_type: Box::new(Type::Void), args: vec![Type::Bool] } Type::Function { return_type: Box::new(Type::Void), args: vec![Type::Bool] }
} }
@ -287,6 +322,13 @@ impl BuiltinFunction {
BuiltinFunction::GetWindowDefaultFontSize => false, BuiltinFunction::GetWindowDefaultFontSize => false,
BuiltinFunction::AnimationTick => false, BuiltinFunction::AnimationTick => false,
BuiltinFunction::ColorScheme => false, BuiltinFunction::ColorScheme => false,
BuiltinFunction::MonthForDate => false,
BuiltinFunction::MonthOffset => false,
BuiltinFunction::FormatDate => false,
BuiltinFunction::DateNow => false,
BuiltinFunction::WeekDaysShort => false,
BuiltinFunction::ValidDate => false,
BuiltinFunction::ParseDate => false,
// Even if it is not pure, we optimize it away anyway // Even if it is not pure, we optimize it away anyway
BuiltinFunction::Debug => true, BuiltinFunction::Debug => true,
BuiltinFunction::Mod BuiltinFunction::Mod
@ -345,6 +387,13 @@ impl BuiltinFunction {
BuiltinFunction::GetWindowDefaultFontSize => true, BuiltinFunction::GetWindowDefaultFontSize => true,
BuiltinFunction::AnimationTick => true, BuiltinFunction::AnimationTick => true,
BuiltinFunction::ColorScheme => true, BuiltinFunction::ColorScheme => true,
BuiltinFunction::MonthForDate => true,
BuiltinFunction::MonthOffset => true,
BuiltinFunction::FormatDate => true,
BuiltinFunction::DateNow => true,
BuiltinFunction::WeekDaysShort => true,
BuiltinFunction::ValidDate => true,
BuiltinFunction::ParseDate => true,
// Even if it has technically side effect, we still consider it as pure for our purpose // Even if it has technically side effect, we still consider it as pure for our purpose
BuiltinFunction::Debug => true, BuiltinFunction::Debug => true,
BuiltinFunction::Mod BuiltinFunction::Mod

View file

@ -3229,6 +3229,27 @@ fn compile_builtin_function_call(
BuiltinFunction::ColorScheme => { BuiltinFunction::ColorScheme => {
format!("{}.color_scheme()", access_window_field(ctx)) format!("{}.color_scheme()", access_window_field(ctx))
} }
BuiltinFunction::MonthForDate => {
format!("{}.month_for_date()", access_window_field(ctx))
}
BuiltinFunction::MonthOffset => {
format!("{}.month_offset()", access_window_field(ctx))
}
BuiltinFunction::FormatDate => {
format!("{}.format_date()", access_window_field(ctx))
}
BuiltinFunction::DateNow => {
format!("{}.date_now()", access_window_field(ctx))
}
BuiltinFunction::WeekDaysShort => {
format!("{}.week_days_short()", access_window_field(ctx))
}
BuiltinFunction::ValidDate => {
format!("{}.valid_date()", access_window_field(ctx))
}
BuiltinFunction::ParseDate => {
format!("{}.parse_date()", access_window_field(ctx))
}
BuiltinFunction::SetTextInputFocused => { BuiltinFunction::SetTextInputFocused => {
format!("{}.set_text_input_focused({})", access_window_field(ctx), a.next().unwrap()) format!("{}.set_text_input_focused({})", access_window_field(ctx), a.next().unwrap())
} }

View file

@ -2687,6 +2687,33 @@ fn compile_builtin_function_call(
let window_adapter_tokens = access_window_adapter_field(ctx); let window_adapter_tokens = access_window_adapter_field(ctx);
quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).color_scheme()) quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).color_scheme())
} }
BuiltinFunction::MonthForDate => {
let (m, y) = (a.next().unwrap(), a.next().unwrap());
quote!(slint::private_unstable_api::month_for_date(#m as u32, #y as i32))
}
BuiltinFunction::MonthOffset => {
let (m, y) = (a.next().unwrap(), a.next().unwrap());
quote!(slint::private_unstable_api::month_offset(#m as u32, #y as i32))
}
BuiltinFunction::FormatDate => {
let (f, d, m, y) =
(a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap());
quote!(slint::private_unstable_api::format_date(&#f, #d as u32, #m as u32, #y as i32))
}
BuiltinFunction::ValidDate => {
let (d, f) = (a.next().unwrap(), a.next().unwrap());
quote!(slint::private_unstable_api::valid_date(#d.as_str(), #f.as_str()))
}
BuiltinFunction::ParseDate => {
let (d, f) = (a.next().unwrap(), a.next().unwrap());
quote!(slint::private_unstable_api::parse_date(#d.as_str(), #f.as_str()))
}
BuiltinFunction::WeekDaysShort => {
quote!(slint::private_unstable_api::week_days_short())
}
BuiltinFunction::DateNow => {
quote!(slint::private_unstable_api::date_now())
}
BuiltinFunction::TextInputFocused => { BuiltinFunction::TextInputFocused => {
let window_adapter_tokens = access_window_adapter_field(ctx); let window_adapter_tokens = access_window_adapter_field(ctx);
quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).text_input_focused()) quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).text_input_focused())

View file

@ -106,6 +106,13 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize {
BuiltinFunction::RegisterCustomFontByMemory => isize::MAX, BuiltinFunction::RegisterCustomFontByMemory => isize::MAX,
BuiltinFunction::RegisterBitmapFont => isize::MAX, BuiltinFunction::RegisterBitmapFont => isize::MAX,
BuiltinFunction::ColorScheme => isize::MAX, BuiltinFunction::ColorScheme => isize::MAX,
BuiltinFunction::MonthForDate => isize::MAX,
BuiltinFunction::MonthOffset => isize::MAX,
BuiltinFunction::FormatDate => isize::MAX,
BuiltinFunction::DateNow => isize::MAX,
BuiltinFunction::WeekDaysShort => isize::MAX,
BuiltinFunction::ValidDate => isize::MAX,
BuiltinFunction::ParseDate => isize::MAX,
BuiltinFunction::SetTextInputFocused => PROPERTY_ACCESS_COST, BuiltinFunction::SetTextInputFocused => PROPERTY_ACCESS_COST,
BuiltinFunction::TextInputFocused => PROPERTY_ACCESS_COST, BuiltinFunction::TextInputFocused => PROPERTY_ACCESS_COST,
BuiltinFunction::Translate => 2 * ALLOC_COST + PROPERTY_ACCESS_COST, BuiltinFunction::Translate => 2 * ALLOC_COST + PROPERTY_ACCESS_COST,

View file

@ -828,6 +828,7 @@ impl LookupObject for SlintInternal {
} }
.into(), .into(),
) )
})
.or_else(|| { .or_else(|| {
f( f(
"use-24-hour-format", "use-24-hour-format",
@ -843,6 +844,75 @@ impl LookupObject for SlintInternal {
.into(), .into(),
) )
}) })
.or_else(|| {
f(
"month-for-date",
Expression::BuiltinFunctionReference(
BuiltinFunction::MonthForDate,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"month-offset",
Expression::BuiltinFunctionReference(
BuiltinFunction::MonthOffset,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"format-date",
Expression::BuiltinFunctionReference(
BuiltinFunction::FormatDate,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"date-now",
Expression::BuiltinFunctionReference(
BuiltinFunction::DateNow,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"week-days-short",
Expression::BuiltinFunctionReference(
BuiltinFunction::WeekDaysShort,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"valid-date",
Expression::BuiltinFunctionReference(
BuiltinFunction::ValidDate,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
})
.or_else(|| {
f(
"parse-date",
Expression::BuiltinFunctionReference(
BuiltinFunction::ParseDate,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)
.into(),
)
}) })
} }
} }

View file

@ -1,5 +1,8 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { ScrollView, LineEdit } from "std-widgets-impl.slint";
import { StateLayer, IconButton, IconButtonStyle, SelectionButton, SelectionButtonStyle, TextStyle } from "./internal-components.slint";
export struct Date { export struct Date {
year: int, year: int,
@ -20,23 +23,6 @@ export struct CalendarDelegateStyle {
state-brush-today: brush, state-brush-today: brush,
} }
component StateLayer inherits Rectangle {
in property <bool> pressed;
in property <bool> has-hover;
in property <bool> has-focus;
in property <bool> enabled;
in property <brush> state-brush;
states [
highlighted when root.enabled && (root.pressed || root.has-focus) : {
root.background: root.state-brush.with_alpha(0.12);
}
hovered when root.enabled && root.has-hover : {
root.background: root.state-brush.with_alpha(0.08);
}
]
}
component CalendarHeaderDelegate { component CalendarHeaderDelegate {
in property <string> text <=> text-label.text; in property <string> text <=> text-label.text;
in property <length> font-size; in property <length> font-size;
@ -95,10 +81,10 @@ component CalendarDelegate {
} }
background-layer := Rectangle { background-layer := Rectangle {
border-radius: max(self.width, self.height) / 2; border-radius: self.height / 2;
} }
content-layer := VerticalLayout { content-layer := HorizontalLayout {
text-label := Text { text-label := Text {
vertical-alignment: center; vertical-alignment: center;
horizontal-alignment: center; horizontal-alignment: center;
@ -140,22 +126,18 @@ export struct CalendarStyle {
} }
export component Calendar { export component Calendar {
property <int> column-count: 7; in property <int> column-count;
property <int> row-count: 6; in property <int> row-count;
property <length> delegate-size: 40px; in property <length> delegate-size;
in property <CalendarStyle> style; in property <CalendarStyle> style;
in property <int> start-column; in property <int> start-column;
in property <[string]> header-model; in property <[string]> header-model;
in property <[Date]> model; in property <[[int]]> model;
in property <Date> today; in property <Date> today;
in property <Date> selected-date; in property <Date> selected-date;
callback select-date(/* date */ Date); callback select-date(/* date */ Date);
min-width: root.delegate-size * root.column-count + (root.column-count - 1) * root.style.spacing;
min-height: root.delegate-size * root.row-count + (root.row-count - 1) * root.style.spacing;
// header // header
for day[index] in root.header-model : CalendarHeaderDelegate { for day[index] in root.header-model : CalendarHeaderDelegate {
x: root.delegate-x(index); x: root.delegate-x(index);
@ -168,17 +150,19 @@ export component Calendar {
// items // items
for date[index] in root.model : CalendarDelegate { for date[index] in root.model : CalendarDelegate {
property <Date> d: { day: date[0], month: date[1], year: date[2] };
x: root.delegate-x(root.index-on-calendar(index)); x: root.delegate-x(root.index-on-calendar(index));
y: root.delegate-y(root.index-on-calendar(index)); y: root.delegate-y(root.index-on-calendar(index));
width: root.delegate-size; width: root.delegate-size;
height: root.delegate-size; height: root.delegate-size;
text: date.day; text: date[0];
style: root.style.delegate-style; style: root.style.delegate-style;
selected: root.selected-date == date; selected: root.selected-date == self.d;
today: root.today == date; today: root.today == self.d;
clicked => { clicked => {
root.select-date(date); root.select-date(self.d);
} }
} }
@ -204,81 +188,321 @@ export component Calendar {
} }
} }
component YearSelection {
in property <[int]> model;
in property <length> spacing;
in property <int> visible-row-count;
in property <int> column-count;
in property <length> delegate-width;
in property <length> delegate-height;
in property <CalendarDelegateStyle> delegate-style;
in property <int> selected-year;
in property <int> today-year;
callback select-year(/* year */ int);
property <length> row-height: root.height / root.visible-row-count;
property <int> row-count: root.model.length / root.column-count;
property <length> viewport-height: root.row-count * root.row-height;
property <length> start-x: root.width / (root.column-count + 1);
property <length> start-y: root.height / (root.visible-row-count + 1);
ScrollView {
width: 100%;
height: 100%;
viewport-width: root.width;
viewport-height: root.viewport-height;
for year[index] in root.model: CalendarDelegate {
x: root.delegate-center-x(index) - self.width / 2;
y: root.delegate-center-y(index) - self.height / 2;
width: root.delegate-width;
height: root.delegate-height;
text: year;
style: root.delegate-style;
selected: year == root.selected-year;
today: year == root.today-year;
clicked => {
root.select-year(year);
}
}
}
function delegate-center-x(index: int) -> length {
root.start-x * (root.column-for-index(index) + 1)
}
function delegate-center-y(index: int) -> length {
root.start-y * (root.row-for-index(index) + 1)
}
function row-for-index(index: int) -> int {
floor(index / root.column-count)
}
function column-for-index(index: int) -> int {
mod(index, root.column-count)
}
}
export struct DatePickerStyle { export struct DatePickerStyle {
border-brush: brush,
padding: length,
calendar-style: CalendarStyle, calendar-style: CalendarStyle,
icon-button-style: IconButtonStyle,
selection-button-style: SelectionButtonStyle,
current-day-style: TextStyle,
title-style: TextStyle,
next-icon: image,
previous-icon: image,
drop-down-icon: image,
input-icon: image,
calendar-icon: image,
} }
export component DatePickerBase { export component DatePickerBase {
property <Date> current-date;
in property <Date> date; in property <Date> date;
in property <DatePickerStyle> style; in property <DatePickerStyle> style;
in property <string> title;
in property <string> input-title;
in property <string> input-placeholder-text;
in property <string> input-format;
// this is used for the navigation between months
property <Date> display-date: root.date;
property <Date> current-date: root.date;
property <length> delegate-size: 40px;
property <length> year-delegate-width: 72px;
property <int> calendar-column-count: 7;
property <int> calendar-row-count: 6;
property <length> calendar-min-width: root.delegate-size * root.calendar-column-count + (root.calendar-column-count - 1) * root.style.calendar-style.spacing;
property <length> calendar-min-height: root.delegate-size *(root.calendar-row-count + 1) + (root.calendar-row-count - 1) * root.style.calendar-style.spacing;
property <int> year-selection-column-count: 3;
property <int> year-selection-row-count: 5;
property <bool> year-selection;
property <bool> selection-mode: true;
property <string> current-input;
property <[[int]]> calendar-model: SlintInternal.month_for_date(root.display-date.month, root.display-date.year);
property <[string]> calendar-header-model: SlintInternal.week_days_short();
property <[int]> today: SlintInternal.date_now();
property <int> start-column: SlintInternal.month_offset(root.display-date.month, root.display-date.year);
property <string> current-month: SlintInternal.format_date("%B %Y", root.display-date.day, root.display-date.month, root.display-date.year);
property <[int]> year-model: [2024, 2025, 2026, 2027, 2028, 2029, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043];
property <int> selected-year: root.display-date.year;
property <int> today-year: root.today[2];
property <string> current-day: SlintInternal.format_date("%a, %b %d", root.current-date.day, root.current-date.month, root.current-date.year);
property <[int]> input-formatted: SlintInternal.parse_date(root.current-input, root.input-format);
min-width: content-layer.min-width; min-width: content-layer.min-width;
min-height: content-layer.min-height; min-height: content-layer.min-height;
content-layer := VerticalLayout { content-layer := VerticalLayout {
calendar := Calendar { spacing: root.style.padding;
style: root.style.calendar-style;
// FIXME: replace this after SlintInternal helper is ready HorizontalLayout {
header-model: DummyGenerator.calendar-header-model; padding-left: root.style.padding;
model: DummyGenerator.calendar-model; padding-right: root.style.padding;
today: DummyGenerator.today;
selected-date <=> DummyGenerator.selected-date; Text {
start-column: DummyGenerator.start-column; text: root.title;
horizontal-alignment: left;
overflow: elide;
font-size: root.style.title-style.font-size;
font-weight: root.style.title-style.font-weight;
color: root.style.title-style.foreground;
}
}
header := HorizontalLayout {
padding-left: root.style.padding;
padding-right: root.style.padding;
Text {
text: root.selection-mode ? root.current-day : root.input-title;
horizontal-alignment: left;
vertical-alignment: center;
font-size: root.style.current-day-style.font-size;
font-weight: root.style.current-day-style.font-weight;
color: root.style.current-day-style.foreground;
}
IconButton {
icon: root.selection-mode ? root.style.input-icon : root.style.calendar-icon;
style: root.style.icon-button-style;
accessible-label: "Toggle selection mode";
clicked => {
root.toggle-selection-mode();
}
}
}
Rectangle {
width: 100%;
height: 1px;
background: root.style.border-brush;
}
if root.selection-mode : HorizontalLayout {
padding-left: root.style.padding;
padding-right: root.style.padding;
VerticalLayout {
horizontal-stretch: 0;
alignment: center;
SelectionButton {
text: root.current-month;
style: root.style.selection-button-style;
icon: root.style.drop-down-icon;
checked <=> root.year-selection;
}
}
Rectangle {}
IconButton {
icon: root.style.previous-icon;
style: root.style.icon-button-style;
accessible-label: "Previous month";
clicked => {
root.show-previous();
}
}
IconButton {
icon: root.style.next-icon;
style: root.style.icon-button-style;
accessible-label: "Next month";
clicked => {
root.show-next();
}
}
}
if root.selection-mode : VerticalLayout {
padding-left: root.style.padding;
padding-right: root.style.padding;
if !root.year-selection : Calendar {
min-width: root.calendar-min-width;
min-height: root.calendar-min-height;
column-count: root.calendar-column-count;
row-count: root.calendar-row-count;
delegate-size: root.delegate-size;
style: root.style.calendar-style;
header-model: root.calendar-header-model;
model: root.calendar-model;
today: { day: root.today[0], month: root.today[1], year: root.today[2] };
selected-date <=> root.current-date;
start-column: root.start-column;
select-date(date) => { select-date(date) => {
DummyGenerator.selected-date = date; root.select-date(date);
} }
} }
if root.year-selection : YearSelection {
min-width: root.calendar-min-width;
min-height: root.calendar-min-height;
spacing: root.style.calendar-style.spacing;
column-count: root.year-selection-column-count;
visible-row-count: root.year-selection-row-count;
delegate-width: root.year-delegate-width;
delegate-height: root.delegate-size;
model: root.year-model;
delegate-style: root.style.calendar-style.delegate-style;
selected-year: root.selected-year;
today-year: root.today-year;
select-year(year) => {
root.select-year(year);
}
}
}
Rectangle {
width: 100%;
height: 1px;
background: root.style.border-brush;
visible: root.year-selection;
}
if !root.selection-mode : HorizontalLayout {
padding-left: root.style.padding;
padding-right: root.style.padding;
padding-bottom: root.style.padding;
LineEdit {
text <=> root.current-input;
placeholder-text: root.input-placeholder-text;
}
}
}
changed date => {
root.display-date = root.date;
root.current-date = root.date;
}
changed selection-mode => {
// check switch from input mode if input is valid
if root.ok-enabled() {
root.current-date = root.input-as-date();
}
} }
pure public function ok-enabled() -> bool { pure public function ok-enabled() -> bool {
true root.selection-mode || SlintInternal.valid_date(root.current-input, root.input-format)
} }
public function get-current-date() -> Date { public function get-current-date() -> Date {
root.current-date if root.selection-mode {
} return root.current-date;
} }
global DummyGenerator { root.input-as-date()
out property <int> start-column: 3; }
out property <Date> today: { year: 2024, month: 5, day: 17 };
in-out property <Date> selected-date: { year: 2024, month: 5, day: 2 }; pure function input-as-date() -> Date {
out property <[string]> calendar-header-model: ["S", "M", "T", "W", "T", "F", "S"];
out property <[Date]> calendar-model : [ { day: root.input-formatted[0], month: root.input-formatted[1], year: root.input-formatted[2] }
{ year: 2024, month: 5, day: 1 }, }
{ year: 2024, month: 5, day: 2 },
{ year: 2024, month: 5, day: 3 }, function select-date(date: Date) {
{ year: 2024, month: 5, day: 4 }, root.current-date = date;
{ year: 2024, month: 5, day: 5 }, }
{ year: 2024, month: 5, day: 6 },
{ year: 2024, month: 5, day: 7 }, function select-year(year: int) {
{ year: 2024, month: 5, day: 8 }, root.current-date = { day: 1, month: 1, year: year };
{ year: 2024, month: 5, day: 9 }, root.display-date = root.current-date;
{ year: 2024, month: 5, day: 10 }, root.year-selection = false;
{ year: 2024, month: 5, day: 11 }, }
{ year: 2024, month: 5, day: 12 },
{ year: 2024, month: 5, day: 13 }, function show-next() {
{ year: 2024, month: 5, day: 14 }, if root.display-date.month >= 12 {
{ year: 2024, month: 5, day: 15 }, root.display-date = { day: 1, month: 1, year: root.display-date.year + 1 };
{ year: 2024, month: 5, day: 16 }, return;
{ year: 2024, month: 5, day: 17 }, }
{ year: 2024, month: 5, day: 18 },
{ year: 2024, month: 5, day: 19 }, root.display-date = { day: 1, month: root.display-date.month + 1, year: root.display-date.year };
{ year: 2024, month: 5, day: 20 }, }
{ year: 2024, month: 5, day: 21 },
{ year: 2024, month: 5, day: 22 }, function show-previous() {
{ year: 2024, month: 5, day: 23 }, if root.display-date.month <= 1 {
{ year: 2024, month: 5, day: 24 }, root.display-date = { day: 1, month: 12, year: root.display-date.year - 1 };
{ year: 2024, month: 5, day: 25 }, return;
{ year: 2024, month: 5, day: 26 }, }
{ year: 2024, month: 5, day: 27 },
{ year: 2024, month: 5, day: 28 }, root.display-date = { day: 1, month: root.display-date.month - 1, year: root.display-date.year };
{ year: 2024, month: 5, day: 29 }, }
{ year: 2024, month: 5, day: 30 },
{ year: 2024, month: 5, day: 31 }, function toggle-selection-mode() {
]; root.selection-mode = !root.selection-mode;
}
} }

View file

@ -1,6 +1,180 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
export component StateLayer inherits Rectangle {
in property <bool> pressed;
in property <bool> has-hover;
in property <bool> has-focus;
in property <bool> enabled;
in property <brush> state-brush;
states [
highlighted when root.enabled && (root.pressed || root.has-focus) : {
root.background: root.state-brush.with_alpha(0.12);
}
hovered when root.enabled && root.has-hover : {
root.background: root.state-brush.with_alpha(0.08);
}
]
}
export struct IconButtonStyle {
foreground: brush,
icon-size: length,
state-brush: brush,
}
export component FocusTouchArea {
in property <bool> enabled;
out property <bool> pressed <=> touch-area.pressed;
out property <bool> has-hover <=> touch-area.has-hover;
out property <bool> has-focus <=> focus-scope.has-focus;
callback clicked <=> touch-area.clicked;
forward-focus: focus-scope;
touch-area := TouchArea {
enabled: root.enabled;
}
focus-scope := FocusScope {
width: 0px;
enabled: root.enabled;
key-pressed(event) => {
if (event.text == " " || event.text == "\n") {
touch-area.clicked();
return accept;
}
return reject;
}
}
}
export component IconButton {
in property <image> icon <=> icon-image.source;
in property <IconButtonStyle> style;
in property <bool> enabled: true;
callback clicked <=> touch-area.clicked;
min-width: max(48px, content-layer.min-width);
min-height: max(48px, content-layer.min-height);
accessible-role: button;
accessible-action-default => { touch-area.clicked(); }
forward-focus: touch-area;
touch-area := FocusTouchArea {
width: 100%;
height: 100%;
enabled: root.enabled;
}
state-layer := StateLayer {
enabled: root.enabled;
pressed: touch-area.pressed;
has-hover: touch-area.has-hover;
has-focus: touch-area.has-focus;
state-brush: root.style.state-brush;
border-radius: max(self.width, self.height) / 2;
}
content-layer := VerticalLayout {
alignment: center;
icon-image := Image {
x: (parent.width - self.width) / 2;
width: root.style.icon-size;
colorize: root.style.foreground;
}
}
states [
disabled when !root.enabled : {
root.opacity: 0.38;
}
]
}
export struct SelectionButtonStyle {
state-brush: brush,
foreground: brush,
font-size: length,
font-weight: float,
icon-size: length,
}
export component SelectionButton {
in property <string> text <=> text-label.text;
in property <image> icon <=> icon-image.source;
in property <SelectionButtonStyle> style;
in property <bool> enabled: true;
in-out property <bool> checked;
callback clicked();
min-width: content-layer.min-width;
min-height: max(40px, content-layer.min-height);
accessible-label: root.text;
accessible-role: button;
accessible-checkable: true;
accessible-checked: root.checked;
accessible-action-default => { touch-area.clicked(); }
forward-focus: touch-area;
touch-area := FocusTouchArea {
width: 100%;
height: 100%;
enabled: root.enabled;
clicked => {
root.checked = !root.checked;
root.clicked();
}
}
state-layer := StateLayer {
enabled: root.enabled;
pressed: touch-area.pressed;
has-hover: touch-area.has-hover;
has-focus: touch-area.has-focus;
state-brush: root.style.state-brush;
}
content-layer := HorizontalLayout {
alignment: center;
padding-left: 8px;
padding-right: 8px;
spacing: 8px;
text-label := Text {
font-size: root.style.font-size;
font-weight: root.style.font-weight;
color: root.style.foreground;
vertical-alignment: center;
}
icon-image := Image {
y: (parent.height - self.height) / 2;
width: root.style.icon-size;
colorize: root.style.foreground;
rotation-angle: root.checked ? 180deg : 0;
rotation-origin-x: self.width / 2;
rotation-origin-y: self.height / 2;
animate rotation-angle { duration: 250ms; }
}
}
states [
disabled when !root.enabled : {
root.opacity: 0.38;
}
]
}
export struct TextStyle { export struct TextStyle {
font-size: length, font-size: length,
font-weight: int, font-weight: int,

View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.06005 1.93997L1.99805 8.00397L8.06005 14.067C9.49805 15.504 10.748 14.004 9.68505 12.942L4.74805 8.00297L9.68505 3.06597C10.498 2.25297 9.24805 0.752973 8.06005 1.94097V1.93997Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 311 B

View file

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_409_3673)">
<path d="M7.9399 1.94L14.0019 8.003L7.9399 14.066C6.5019 15.503 5.2519 14.003 6.3149 12.941L11.2519 8.003L6.3149 3.066C5.5019 2.253 6.7519 0.753004 7.9399 1.94Z" fill="#232323"/>
</g>
<defs>
<clipPath id="clip0_409_3673">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 426 B

View file

@ -0,0 +1,17 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1527_4642)">
<path d="M0.0350342 0.0300293H16.035V16.03H0.0350342V0.0300293Z" fill="#808080" fill-opacity="0.01"/>
<path d="M3.03503 1.03003C1.92703 1.03003 1.03503 1.92203 1.03503 3.03003V13.03C1.03503 14.138 1.92703 15.03 3.03503 15.03H13.035C14.143 15.03 15.035 14.138 15.035 13.03V3.03003C15.035 1.92203 14.143 1.03003 13.035 1.03003H3.03503ZM3.03503 5.03003H13.035V13.03H3.03503V5.03003Z" fill="#232323"/>
<path d="M6.03503 4.53003C6.03503 4.25389 5.81118 4.03003 5.53503 4.03003C5.25889 4.03003 5.03503 4.25389 5.03503 4.53003V13.28C5.03503 13.5562 5.25889 13.78 5.53503 13.78C5.81118 13.78 6.03503 13.5562 6.03503 13.28V4.53003Z" fill="#232323"/>
<path d="M9.03503 5.03003C9.03503 4.75389 8.81118 4.53003 8.53503 4.53003C8.25889 4.53003 8.03503 4.75389 8.03503 5.03003V13.28C8.03503 13.5562 8.25889 13.78 8.53503 13.78C8.81118 13.78 9.03503 13.5562 9.03503 13.28V5.03003Z" fill="#232323"/>
<path d="M12.035 5.03003C12.035 4.75389 11.8112 4.53003 11.535 4.53003C11.2589 4.53003 11.035 4.75389 11.035 5.03003V14.03C11.035 14.3062 11.2589 14.53 11.535 14.53C11.8112 14.53 12.035 14.3062 12.035 14.03V5.03003Z" fill="#232323"/>
<path d="M13.535 7.03003H2.53503C2.25889 7.03003 2.03503 7.25389 2.03503 7.53003C2.03503 7.80617 2.25889 8.03003 2.53503 8.03003H13.535C13.8112 8.03003 14.035 7.80617 14.035 7.53003C14.035 7.25389 13.8112 7.03003 13.535 7.03003Z" fill="#232323"/>
<path d="M13.785 10.03H2.53503C2.25889 10.03 2.03503 10.2539 2.03503 10.53C2.03503 10.8062 2.25889 11.03 2.53503 11.03H13.785C14.0612 11.03 14.285 10.8062 14.285 10.53C14.285 10.2539 14.0612 10.03 13.785 10.03Z" fill="#232323"/>
<path opacity="0.5" d="M9.03503 8.03003H11.035V10.03H9.03503V8.03003Z" fill="#232323"/>
</g>
<defs>
<clipPath id="clip0_1527_4642">
<rect width="16" height="16" fill="white" transform="translate(0.0350342 0.0300293)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.990234 11.887V15.007H4.11023L11.9902 7.127L8.87023 4.007L0.990234 11.887ZM14.7502 4.377C15.0802 4.047 15.0802 3.527 14.7502 3.197L12.8002 1.247C12.7233 1.16863 12.6314 1.10638 12.5301 1.06389C12.4288 1.0214 12.3201 0.999512 12.2102 0.999512C12.1004 0.999512 11.9916 1.0214 11.8903 1.06389C11.789 1.10638 11.6972 1.16863 11.6202 1.247L9.99023 2.887L13.1102 6.007L14.7502 4.377Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 512 B

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { VerticalBox } from "./layouts.slint"; import { VerticalBox } from "./layouts.slint";
import { Button } from "./button.slint"; import { Button } from "./button.slint";
@ -14,6 +14,9 @@ export component DatePicker {
in property <string> cancel-text: "Cancel"; in property <string> cancel-text: "Cancel";
in property <string> ok-text: "Ok"; in property <string> ok-text: "Ok";
in property <Date> date <=> base.date; in property <Date> date <=> base.date;
in property <string> input-title: "Enter date";
in property <string> input-placeholder-text: "mm/dd/yyyy";
in property <string> input-format: "%m/%d/%Y";
callback canceled(); callback canceled();
callback accepted(/* current-date */ Date); callback accepted(/* current-date */ Date);
@ -24,17 +27,17 @@ export component DatePicker {
background-layer := MenuBorder { } background-layer := MenuBorder { }
content-layer := VerticalBox { content-layer := VerticalBox {
Text { padding-left: 0px;
text: root.title; padding-right: 0px;
horizontal-alignment: left;
overflow: elide;
font-size: CosmicFontSettings.body.font-size;
font-weight: CosmicFontSettings.body.font-weight;
color: CosmicPalette.foreground;
}
base := DatePickerBase { base := DatePickerBase {
title: root.title;
input-title: root.input-title;
input-placeholder-text: root.input-placeholder-text;
input-format: root.input-format;
style: { style: {
border-brush: CosmicPalette.border,
padding: 8px,
calendar-style: { calendar-style: {
spacing: 8px, spacing: 8px,
delegate-style: { delegate-style: {
@ -49,12 +52,41 @@ export component DatePicker {
foreground-today: CosmicPalette.accent-background, foreground-today: CosmicPalette.accent-background,
state-brush-today: CosmicPalette.state, state-brush-today: CosmicPalette.state,
} }
},
icon-button-style: {
foreground: CosmicPalette.foreground,
state-brush: CosmicPalette.state,
icon-size: 12px,
},
current-day-style: {
font-size: CosmicFontSettings.title.font-size,
font-weight: CosmicFontSettings.title.font-weight,
foreground: CosmicPalette.foreground,
},
title-style: {
font-size: CosmicFontSettings.body.font-size,
font-weight: CosmicFontSettings.body.font-weight,
foreground: CosmicPalette.foreground,
},
previous-icon: Icons.arrow-back,
next-icon: Icons.arrow-forward,
drop-down-icon: Icons.dropdown,
input-icon: Icons.edit,
calendar-icon: Icons.calendar,
selection-button-style: {
foreground: CosmicPalette.foreground,
state-brush: CosmicPalette.state,
icon-size: 8px,
font-size: CosmicFontSettings.body.font-size,
font-weight: CosmicFontSettings.body.font-weight
} }
}; };
} }
HorizontalLayout { HorizontalLayout {
spacing: 8px; spacing: 8px;
padding-left: 8px;
padding-right: 8px;
Rectangle { } Rectangle { }

View file

@ -12,6 +12,9 @@ export { ScrollView }
import { ListItem } from "components.slint"; import { ListItem } from "components.slint";
export { ListItem } export { ListItem }
import { LineEdit } from "lineedit.slint";
export { LineEdit }
import { CosmicPalette, CosmicFontSettings } from "styling.slint"; import { CosmicPalette, CosmicFontSettings } from "styling.slint";
export global StyleMetrics { export global StyleMetrics {

View file

@ -20,6 +20,10 @@ export global CosmicFontSettings {
font-size: 14 * 0.0769rem, font-size: 14 * 0.0769rem,
font-weight: semibold-font-weight font-weight: semibold-font-weight
}; };
out property <TextStyle> title: {
font-size: 24 * 0.0769rem,
font-weight: light-font-weight
};
} }
export global CosmicPalette { export global CosmicPalette {
@ -72,4 +76,8 @@ export global Icons {
out property <image> dropdown: @image-url("_pane_down.svg"); out property <image> dropdown: @image-url("_pane_down.svg");
out property <image> keyboard: @image-url("_keyboard.svg"); out property <image> keyboard: @image-url("_keyboard.svg");
out property <image> clock: @image-url("_clock.svg"); out property <image> clock: @image-url("_clock.svg");
out property <image> arrow-back: @image-url("_arrow_back.svg");
out property <image> arrow-forward: @image-url("_arrow_forward.svg");
out property <image> edit: @image-url("_edit.svg");
out property <image> calendar: @image-url("_calendar.svg");
} }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cosmic-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M400-80 0-480l400-400 71 71-329 329 329 329-71 71Z"/>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="m321-80-71-71 329-329-329-329 71-71 400 400L321-80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 181 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M360-300q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { VerticalBox } from "./layouts.slint"; import { VerticalBox } from "./layouts.slint";
import { Button } from "./button.slint"; import { Button } from "./button.slint";
@ -14,6 +14,9 @@ export component DatePicker {
in property <string> cancel-text: "Cancel"; in property <string> cancel-text: "Cancel";
in property <string> ok-text: "Ok"; in property <string> ok-text: "Ok";
in property <Date> date <=> base.date; in property <Date> date <=> base.date;
in property <string> input-title: "Enter date";
in property <string> input-placeholder-text: "mm/dd/yyyy";
in property <string> input-format: "%m/%d/%Y";
callback canceled(); callback canceled();
callback accepted(/* current-date */ Date); callback accepted(/* current-date */ Date);
@ -24,17 +27,17 @@ export component DatePicker {
background-layer := MenuBorder { } background-layer := MenuBorder { }
content-layer := VerticalBox { content-layer := VerticalBox {
Text { padding-left: 0;
text: root.title; padding-right: 0;
horizontal-alignment: left;
overflow: elide;
font-size: CupertinoFontSettings.body.font-size;
font-weight: CupertinoFontSettings.body.font-weight;
color: CupertinoPalette.foreground;
}
base := DatePickerBase { base := DatePickerBase {
title: root.title;
input-title: root.input-title;
input-placeholder-text: root.input-placeholder-text;
input-format: root.input-format;
style: { style: {
border-brush: CupertinoPalette.border,
padding: 8px,
calendar-style: { calendar-style: {
spacing: 8px, spacing: 8px,
delegate-style: { delegate-style: {
@ -49,12 +52,41 @@ export component DatePicker {
foreground-today: CupertinoPalette.accent-background, foreground-today: CupertinoPalette.accent-background,
state-brush-today: CupertinoPalette.state, state-brush-today: CupertinoPalette.state,
} }
},
icon-button-style: {
foreground: CupertinoPalette.foreground,
state-brush: CupertinoPalette.state,
icon-size: 12px,
},
current-day-style: {
foreground: CupertinoPalette.foreground,
font-size: CupertinoFontSettings.title.font-size,
font-weight: CupertinoFontSettings.title.font-weight,
},
title-style: {
font-size: CupertinoFontSettings.body.font-size,
font-weight: CupertinoFontSettings.body.font-weight,
foreground: CupertinoPalette.foreground,
},
previous-icon: Icons.arrow-back,
next-icon: Icons.arrow-forward,
drop-down-icon: Icons.dropdown,
input-icon: Icons.edit,
calendar-icon: Icons.calendar,
selection-button-style: {
foreground: CupertinoPalette.foreground,
state-brush: CupertinoPalette.state,
icon-size: 8px,
font-size: CupertinoFontSettings.body.font-size,
font-weight: CupertinoFontSettings.body.font-weight
} }
}; };
} }
HorizontalLayout { HorizontalLayout {
spacing: 8px; spacing: 8px;
padding-left: 8px;
padding-right: 8px;
Rectangle { } Rectangle { }

View file

@ -12,6 +12,9 @@ export { ScrollView }
import { ListItem } from "components.slint"; import { ListItem } from "components.slint";
export { ListItem } export { ListItem }
import { LineEdit } from "lineedit.slint";
export { LineEdit }
import { CupertinoPalette, CupertinoFontSettings } from "styling.slint"; import { CupertinoPalette, CupertinoFontSettings } from "styling.slint";
export global StyleMetrics { export global StyleMetrics {

View file

@ -18,6 +18,12 @@ export global CupertinoFontSettings {
font-weight: regular-font-weight font-weight: regular-font-weight
}; };
out property <TextStyle> title: {
font-size: 28 * 0.0769rem,
font-weight: light-font-weight
};
// needed? // needed?
out property <TextStyle> body-strong: { out property <TextStyle> body-strong: {
font-size: 14 * 0.0769rem, font-size: 14 * 0.0769rem,
@ -89,4 +95,8 @@ export global Icons {
out property <image> up: @image-url("_up.svg"); out property <image> up: @image-url("_up.svg");
out property <image> keyboard: @image-url("_keyboard.svg"); out property <image> keyboard: @image-url("_keyboard.svg");
out property <image> clock: @image-url("_clock.svg"); out property <image> clock: @image-url("_clock.svg");
out property <image> arrow-back: @image-url("_arrow_back.svg");
out property <image> arrow-forward: @image-url("_arrow_forward.svg");
out property <image> edit: @image-url("_edit.svg");
out property <image> calendar: @image-url("_calendar.svg");
} }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../cupertino-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M400-80 0-480l400-400 71 71-329 329 329 329-71 71Z"/>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="m321-80-71-71 329-329-329-329 71-71 400 400L321-80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 181 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M360-300q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { VerticalBox } from "./layouts.slint"; import { VerticalBox } from "./layouts.slint";
import { Button } from "./button.slint"; import { Button } from "./button.slint";
@ -14,6 +14,9 @@ export component DatePicker {
in property <string> cancel-text: "Cancel"; in property <string> cancel-text: "Cancel";
in property <string> ok-text: "Ok"; in property <string> ok-text: "Ok";
in property <Date> date <=> base.date; in property <Date> date <=> base.date;
in property <string> input-title: "Enter date";
in property <string> input-placeholder-text: "mm/dd/yyyy";
in property <string> input-format: "%m/%d/%Y";
callback canceled(); callback canceled();
callback accepted(/* current-date */ Date); callback accepted(/* current-date */ Date);
@ -24,17 +27,17 @@ export component DatePicker {
background-layer := MenuBorder { } background-layer := MenuBorder { }
content-layer := VerticalBox { content-layer := VerticalBox {
Text { padding-left: 0;
text: root.title; padding-right: 0;
horizontal-alignment: left;
overflow: elide;
font-size: FluentFontSettings.body.font-size;
font-weight: FluentFontSettings.body.font-weight;
color: FluentPalette.foreground;
}
base := DatePickerBase { base := DatePickerBase {
title: root.title;
input-title: root.input-title;
input-placeholder-text: root.input-placeholder-text;
input-format: root.input-format;
style: { style: {
border-brush: FluentPalette.border,
padding: 8px,
calendar-style: { calendar-style: {
spacing: 8px, spacing: 8px,
delegate-style: { delegate-style: {
@ -49,12 +52,41 @@ export component DatePicker {
foreground-today: FluentPalette.accent-background, foreground-today: FluentPalette.accent-background,
state-brush-today: FluentPalette.state, state-brush-today: FluentPalette.state,
} }
},
icon-button-style: {
foreground: FluentPalette.foreground,
state-brush: FluentPalette.state,
icon-size: 12px,
},
current-day-style: {
font-size: FluentFontSettings.title.font-size,
font-weight: FluentFontSettings.title.font-weight,
foreground: FluentPalette.foreground,
},
title-style: {
font-size: FluentFontSettings.body.font-size,
font-weight: FluentFontSettings.body.font-weight,
foreground: FluentPalette.foreground,
},
previous-icon: Icons.arrow-back,
next-icon: Icons.arrow-forward,
drop-down-icon: Icons.dropdown,
input-icon: Icons.edit,
calendar-icon: Icons.calendar,
selection-button-style: {
foreground: FluentPalette.foreground,
state-brush: FluentPalette.state,
icon-size: 8px,
font-size: FluentFontSettings.body.font-size,
font-weight: FluentFontSettings.body.font-weight
} }
}; };
} }
HorizontalLayout { HorizontalLayout {
spacing: 8px; spacing: 8px;
padding-left: 8px;
padding-right: 8px;
Rectangle { } Rectangle { }

View file

@ -12,6 +12,9 @@ export { ScrollView }
import { ListItem } from "components.slint"; import { ListItem } from "components.slint";
export { ListItem } export { ListItem }
import { LineEdit } from "lineedit.slint";
export { LineEdit }
import { FluentPalette, FluentFontSettings } from "styling.slint"; import { FluentPalette, FluentFontSettings } from "styling.slint";
export global StyleMetrics { export global StyleMetrics {

View file

@ -20,6 +20,10 @@ export global FluentFontSettings {
font-size: 14 * 0.0769rem, font-size: 14 * 0.0769rem,
font-weight: semibold-font-weight font-weight: semibold-font-weight
}; };
out property <TextStyle> title: {
font-size: 28 * 0.0769rem,
font-weight: semibold-font-weight
};
} }
export global FluentPalette { export global FluentPalette {
@ -102,4 +106,8 @@ export global Icons {
out property <image> up: @image-url("_up.svg"); out property <image> up: @image-url("_up.svg");
out property <image> keyboard: @image-url("_keyboard.svg"); out property <image> keyboard: @image-url("_keyboard.svg");
out property <image> clock: @image-url("_clock.svg"); out property <image> clock: @image-url("_clock.svg");
out property <image> arrow-back: @image-url("_arrow_back.svg");
out property <image> arrow-forward: @image-url("_arrow_forward.svg");
out property <image> edit: @image-url("_edit.svg");
out property <image> calendar: @image-url("_calendar.svg");
} }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, LineEdit, Button, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, LineEdit, Button, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, LineEdit, Button, ListItem, Palette } from "../fluent-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, LineEdit, Button, ListItem, Palette }

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M400-80 0-480l400-400 71 71-329 329 329 329-71 71Z"/>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="m321-80-71-71 329-329-329-329 71-71 400 400L321-80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 181 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M360-300q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M360-300q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { VerticalBox } from "./layouts.slint"; import { VerticalBox } from "./layouts.slint";
import { Button } from "./button.slint"; import { Button } from "./button.slint";
@ -13,6 +13,9 @@ export component DatePicker {
in property <string> cancel-text: "Cancel"; in property <string> cancel-text: "Cancel";
in property <string> ok-text: "Ok"; in property <string> ok-text: "Ok";
in property <Date> date <=> base.date; in property <Date> date <=> base.date;
in property <string> input-title: "Enter date";
in property <string> input-placeholder-text: "mm/dd/yyyy";
in property <string> input-format: "%m/%d/%Y";
callback canceled(); callback canceled();
callback accepted(/* current-date */ Date); callback accepted(/* current-date */ Date);
@ -26,17 +29,17 @@ export component DatePicker {
} }
content-layer := VerticalBox { content-layer := VerticalBox {
Text { padding-left: 0px;
text: root.title; padding-right: 0px;
horizontal-alignment: left;
overflow: elide;
font-size: MaterialFontSettings.label-medium.font-size;
font-weight: MaterialFontSettings.label-medium.font-weight;
color: MaterialPalette.foreground;
}
base := DatePickerBase { base := DatePickerBase {
title: root.title;
input-title: root.input-title;
input-placeholder-text: root.input-placeholder-text;
input-format: root.input-format;
style: { style: {
border-brush: MaterialPalette.border,
padding: 8px,
calendar-style: { calendar-style: {
spacing: 8px, spacing: 8px,
delegate-style: { delegate-style: {
@ -51,12 +54,41 @@ export component DatePicker {
foreground-today: MaterialPalette.accent-background, foreground-today: MaterialPalette.accent-background,
state-brush-today: MaterialPalette.state-tertiary, state-brush-today: MaterialPalette.state-tertiary,
} }
},
icon-button-style: {
foreground: MaterialPalette.foreground,
state-brush: MaterialPalette.state-default,
icon-size: 12px,
},
current-day-style: {
font-size: MaterialFontSettings.headline-large.font-size,
font-weight: MaterialFontSettings.headline-large.font-weight,
foreground: MaterialPalette.foreground,
},
title-style: {
font-size: MaterialFontSettings.label-medium.font-size,
font-weight: MaterialFontSettings.label-medium.font-weight,
foreground: MaterialPalette.foreground,
},
previous-icon: Icons.arrow-back,
next-icon: Icons.arrow-forward,
drop-down-icon: Icons.arrow-drop-down,
input-icon: Icons.edit,
calendar-icon: Icons.calendar,
selection-button-style: {
foreground: MaterialPalette.foreground,
state-brush: MaterialPalette.state-default,
icon-size: 10px,
font-size: MaterialFontSettings.label-large.font-size,
font-weight: MaterialFontSettings.label-large.font-weight
} }
}; };
} }
HorizontalLayout { HorizontalLayout {
spacing: 8px; spacing: 8px;
padding-left: 8px;
padding-right: 8px;
Rectangle { } Rectangle { }

View file

@ -10,39 +10,39 @@ component ScrollBar inherits Rectangle {
in-out property <length> page-size; in-out property <length> page-size;
// this is always negative and bigger than -maximum // this is always negative and bigger than -maximum
in-out property <length> value; in-out property <length> value;
in-out property <bool> enabled <=> i-touch-area.enabled; in-out property <bool> enabled <=> touch-area.enabled;
states [ states [
disabled when !i-touch-area.enabled : { disabled when !touch-area.enabled : {
i-background.border-color: MaterialPalette.control-foreground; background.border-color: MaterialPalette.control-foreground;
i-handle.opacity: 0.12; handle.opacity: 0.12;
} }
hover when i-touch-area.has-hover : { hover when touch-area.has-hover : {
i-state-layer.opacity: 0.08; state-layer.opacity: 0.08;
} }
pressed when i-touch-area.has-hover : { pressed when touch-area.has-hover : {
i-state-layer.opacity: 0.12; state-layer.opacity: 0.12;
} }
] ]
i-state-layer := Rectangle { state-layer := Rectangle {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: MaterialPalette.accent-background; background: MaterialPalette.accent-background;
border-radius: 4px; border-radius: 4px;
opacity: 0; opacity: 0;
visible: i-handle.width > 0 && i-handle.height > 0; visible: handle.width > 0 && handle.height > 0;
animate opacity { duration: 250ms; easing: ease; } animate opacity { duration: 250ms; easing: ease; }
} }
i-handle := Rectangle { handle := Rectangle {
x: !root.horizontal ? 0phx : (root.width - i-handle.width) * (-root.value / root.maximum); x: !root.horizontal ? 0phx : (root.width - handle.width) * (-root.value / root.maximum);
y: root.horizontal ? 0phx : (root.height - i-handle.height) * (-root.value / root.maximum); y: root.horizontal ? 0phx : (root.height - handle.height) * (-root.value / root.maximum);
width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(32px, parent.width * max(root.page-size / (root.maximum + root.page-size))); width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(32px, parent.width * max(root.page-size / (root.maximum + root.page-size)));
height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(32px, parent.height * (root.page-size / (root.maximum + root.page-size))); height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(32px, parent.height * (root.page-size / (root.maximum + root.page-size)));
i-background := Rectangle { background := Rectangle {
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 4px; border-radius: 4px;
@ -51,7 +51,7 @@ component ScrollBar inherits Rectangle {
} }
} }
i-touch-area := TouchArea { touch-area := TouchArea {
property <length> pressed-value; property <length> pressed-value;
width: parent.width; width: parent.width;
@ -66,8 +66,8 @@ component ScrollBar inherits Rectangle {
moved => { moved => {
if (self.enabled && self.pressed) { if (self.enabled && self.pressed) {
root.value = -max(0px, min(root.maximum, self.pressed-value + ( root.value = -max(0px, min(root.maximum, self.pressed-value + (
root.horizontal ? (i-touch-area.mouse-x - i-touch-area.pressed-x) * (root.maximum / (root.width - i-handle.width)) root.horizontal ? (touch-area.mouse-x - touch-area.pressed-x) * (root.maximum / (root.width - handle.width))
: (i-touch-area.mouse-y - i-touch-area.pressed-y) * (root.maximum / (root.height - i-handle.height)) : (touch-area.mouse-y - touch-area.pressed-y) * (root.maximum / (root.height - handle.height))
))); )));
} }
} }
@ -88,13 +88,13 @@ component ScrollBar inherits Rectangle {
// Scrollview contains a viewport that is bigger than the view and can be scrolled. // Scrollview contains a viewport that is bigger than the view and can be scrolled.
export component ScrollView { export component ScrollView {
in property <bool> enabled: true; in property <bool> enabled: true;
out property <length> visible-width <=> i-flickable.width; out property <length> visible-width <=> flickable.width;
out property <length> visible-height <=> i-flickable.height; out property <length> visible-height <=> flickable.height;
in-out property <bool> has-focus; in-out property <bool> has-focus;
in-out property <length> viewport-width <=> i-flickable.viewport-width; in-out property <length> viewport-width <=> flickable.viewport-width;
in-out property <length> viewport-height <=> i-flickable.viewport-height; in-out property <length> viewport-height <=> flickable.viewport-height;
in-out property <length> viewport-x <=> i-flickable.viewport-x; in-out property <length> viewport-x <=> flickable.viewport-x;
in-out property <length> viewport-y <=> i-flickable.viewport-y; in-out property <length> viewport-y <=> flickable.viewport-y;
min-height: 50px; min-height: 50px;
min-width: 50px; min-width: 50px;
@ -103,39 +103,38 @@ export component ScrollView {
preferred-height: 100%; preferred-height: 100%;
preferred-width: 100%; preferred-width: 100%;
Rectangle { flickable := Flickable {
background: MaterialPalette.alternate-background; x: 0;
} y: 0;
viewport-y <=> vertical-bar.value;
i-flickable := Flickable { viewport-x <=> horizontal-bar.value;
x:0;y:0; width: parent.width - vertical-bar.width - 4px;
viewport-y <=> i-vertical-bar.value; height: parent.height - horizontal-bar.height - 4px;
viewport-x <=> i-horizontal-bar.value;
width: parent.width - i-vertical-bar.width - 4px;
height: parent.height - i-horizontal-bar.height - 4px;
@children @children
} }
i-vertical-bar := ScrollBar { vertical-bar := ScrollBar {
width: 8px; width: 8px;
x: i-flickable.width + i-flickable.x; x: flickable.width + flickable.x;
y: i-flickable.y; y: flickable.y;
height: i-flickable.height; height: flickable.height;
horizontal: false; horizontal: false;
maximum: i-flickable.viewport-height - i-flickable.height; maximum: flickable.viewport-height - flickable.height;
page-size: i-flickable.height; page-size: flickable.height;
enabled: root.enabled; enabled: root.enabled;
visible: flickable.viewport-height > flickable.height;
} }
i-horizontal-bar := ScrollBar { horizontal-bar := ScrollBar {
height: 8px; height: 8px;
y: i-flickable.height + i-flickable.y; y: flickable.height + flickable.y;
x: i-flickable.x; x: flickable.x;
width: i-flickable.width; width: flickable.width;
horizontal: true; horizontal: true;
maximum: i-flickable.viewport-width - i-flickable.width; maximum: flickable.viewport-width - flickable.width;
page-size: i-flickable.width; page-size: flickable.width;
enabled: root.enabled; enabled: root.enabled;
visible: flickable.viewport-width > flickable.width;
} }
} }

View file

@ -13,6 +13,9 @@ export { Button, CheckBox, ScrollView, Switch }
import { ListItem } from "components.slint"; import { ListItem } from "components.slint";
export { ListItem } export { ListItem }
import { LineEdit } from "lineedit.slint";
export { LineEdit }
export global StyleMetrics { export global StyleMetrics {
out property <length> layout-spacing: 16px; out property <length> layout-spacing: 16px;
out property <length> layout-padding: 16px; out property <length> layout-padding: 16px;

View file

@ -15,6 +15,10 @@ export global MaterialFontSettings {
out property <TextStyle> body-large: { font-size: 16 * 0.0625rem, font-weight: 400 }; out property <TextStyle> body-large: { font-size: 16 * 0.0625rem, font-weight: 400 };
out property <TextStyle> body-small: { font-size: 12 * 0.0625rem, font-weight: 400 }; out property <TextStyle> body-small: { font-size: 12 * 0.0625rem, font-weight: 400 };
out property <TextStyle> title-small: { font-size: 14 * 0.0625rem, font-weight: 500 }; out property <TextStyle> title-small: { font-size: 14 * 0.0625rem, font-weight: 500 };
out property <TextStyle> headline-large: {
font-size: 32 * 0.0625rem,
font-weight: 500
};
} }
export global Elevation { export global Elevation {
@ -74,4 +78,8 @@ export global Icons {
out property <image> expand-more: @image-url("_expand-more.svg"); out property <image> expand-more: @image-url("_expand-more.svg");
out property <image> keyboard: @image-url("_keyboard.svg"); out property <image> keyboard: @image-url("_keyboard.svg");
out property <image> clock: @image-url("_clock.svg"); out property <image> clock: @image-url("_clock.svg");
out property <image> arrow-back: @image-url("_arrow_back.svg");
out property <image> arrow-forward: @image-url("_arrow_forward.svg");
out property <image> edit: @image-url("_edit.svg");
out property <image> calendar: @image-url("_calendar.svg");
} }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../material-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../material-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, ListItem, Palette } from "../material-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette } from "../material-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, ListItem, Palette }

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { StyleMetrics, ScrollView, Button, Switch, ListItem, Palette } from "../material-base/std-widgets-impl.slint"; import { StyleMetrics, ScrollView, Button, LineEdit, Switch, ListItem, Palette } from "../material-base/std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, Switch, ListItem, Palette } export { StyleMetrics, ScrollView, Button, LineEdit, Switch, ListItem, Palette }

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M400-80 0-480l400-400 71 71-329 329 329 329-71 71Z"/>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="m321-80-71-71 329-329-329-329 71-71 400 400L321-80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 181 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M360-300q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 10l5 5l5-5z"/></svg>

After

Width:  |  Height:  |  Size: 115 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
<path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/>
</svg>

After

Width:  |  Height:  |  Size: 334 B

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { VerticalBox } from "./layouts.slint"; import { VerticalBox } from "./layouts.slint";
import { Button } from "./button.slint"; import { Button } from "./button.slint";
@ -13,6 +13,9 @@ export component DatePicker {
in property <string> cancel-text: "Cancel"; in property <string> cancel-text: "Cancel";
in property <string> ok-text: "Ok"; in property <string> ok-text: "Ok";
in property <Date> date <=> base.date; in property <Date> date <=> base.date;
in property <string> input-title: "Enter date";
in property <string> input-placeholder-text: "mm/dd/yyyy";
in property <string> input-format: "%m/%d/%Y";
property <brush> state: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000; property <brush> state: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;
property <brush> state-secondary: Palette.color-scheme == ColorScheme.dark ? #000000 : #ffffff; property <brush> state-secondary: Palette.color-scheme == ColorScheme.dark ? #000000 : #ffffff;
@ -30,17 +33,19 @@ export component DatePicker {
content-layer := VerticalBox { content-layer := VerticalBox {
spacing: 8px; spacing: 8px;
padding-left: 0;
Text { padding-right: 0;
text: root.title;
horizontal-alignment: left;
overflow: elide;
color: Palette.foreground;
}
base := DatePickerBase { base := DatePickerBase {
title: root.title;
input-title: root.input-title;
input-placeholder-text: root.input-placeholder-text;
input-format: root.input-format;
style: { style: {
border-brush: Palette.border,
padding: 8px,
calendar-style: { calendar-style: {
spacing: 8px,
delegate-style: { delegate-style: {
font-size: 14px, font-size: 14px,
font-weight: 500, font-weight: 500,
@ -53,12 +58,41 @@ export component DatePicker {
foreground-today: Palette.accent-background, foreground-today: Palette.accent-background,
state-brush-today: root.state, state-brush-today: root.state,
} }
},
icon-button-style: {
foreground: Palette.foreground,
state-brush: root.state,
icon-size: 12px,
},
current-day-style: {
foreground: Palette.foreground,
font-weight: 300,
font-size: 28px,
},
title-style: {
font-size: 14px,
font-weight: 500,
foreground: Palette.foreground,
},
previous-icon: @image-url("./_arrow_back.svg"),
next-icon: @image-url("./_arrow_forward.svg"),
drop-down-icon: @image-url("./_dropdown.svg"),
input-icon: @image-url("./_edit.svg"),
calendar-icon: @image-url("./_calendar.svg"),
selection-button-style: {
foreground: Palette.foreground,
state-brush: root.state,
icon-size: 8px,
font-size: 14px,
font-weight: 500
} }
}; };
} }
HorizontalLayout { HorizontalLayout {
spacing: 8px; spacing: 8px;
padding-left: 8px;
padding-right: 8px;
Rectangle { } Rectangle { }

View file

@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { LineEditBase} from "../common/lineedit-base.slint"; import { LineEditBase} from "../common/lineedit-base.slint";
import { StyleMetrics } from "std-widgets-impl.slint";
export component LineEdit { export component LineEdit {
in property <length> font-size <=> inner.font-size; in property <length> font-size <=> inner.font-size;
@ -65,8 +64,8 @@ export component LineEdit {
padding-bottom: native.native-padding-bottom; padding-bottom: native.native-padding-bottom;
inner := LineEditBase { inner := LineEditBase {
placeholder-color: self.enabled ? StyleMetrics.placeholder-color : StyleMetrics.placeholder-color-disabled; placeholder-color: self.enabled ? NativeStyleMetrics.placeholder-color : NativeStyleMetrics.placeholder-color-disabled;
text-color: self.enabled ? StyleMetrics.textedit-text-color : StyleMetrics.textedit-text-color-disabled; text-color: self.enabled ? NativeStyleMetrics.textedit-text-color : NativeStyleMetrics.textedit-text-color-disabled;
enabled: root.enabled; enabled: root.enabled;
margin: layout.padding-left + layout.padding-right; margin: layout.padding-left + layout.padding-right;
} }

View file

@ -7,4 +7,7 @@ export { NativePalette as Palette }
import { ScrollView } from "scrollview.slint"; import { ScrollView } from "scrollview.slint";
export { ScrollView } export { ScrollView }
import { LineEdit } from "lineedit.slint";
export { LineEdit }
export component ListItem inherits NativeStandardListViewItem {} export component ListItem inherits NativeStandardListViewItem {}

View file

@ -25,7 +25,7 @@ libm = ["num-traits/libm", "euclid/libm"]
# Allow the viewer to query at runtime information about item types # Allow the viewer to query at runtime information about item types
rtti = [] rtti = []
# Use the standard library # Use the standard library
std = ["euclid/std", "once_cell/std", "scoped-tls-hkt", "lyon_path", "lyon_algorithms", "lyon_geom", "lyon_extra", "dep:web-time", "image-decoders", "svg", "raw-window-handle-06?/std"] std = ["euclid/std", "once_cell/std", "scoped-tls-hkt", "lyon_path", "lyon_algorithms", "lyon_geom", "lyon_extra", "dep:web-time", "image-decoders", "svg", "raw-window-handle-06?/std", "chrono/std", "chrono/wasmbind", "chrono/clock"]
# Unsafe feature meaning that there is only one core running and all thread_local are static. # Unsafe feature meaning that there is only one core running and all thread_local are static.
# You can only enable this feature if you are sure that any API of this crate is only called # You can only enable this feature if you are sure that any API of this crate is only called
# from a single core, and not in a interrupt or signal handler. # from a single core, and not in a interrupt or signal handler.
@ -92,6 +92,8 @@ serde = { workspace = true, optional = true }
raw-window-handle-06 = { workspace = true, optional = true } raw-window-handle-06 = { workspace = true, optional = true }
bitflags = { version = "2.4.2"} bitflags = { version = "2.4.2"}
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
gettext-rs = { version = "0.7", optional = true, features = ["gettext-system"] } gettext-rs = { version = "0.7", optional = true, features = ["gettext-system"] }

View file

@ -1,10 +1,124 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
use alloc::rc::Rc;
use alloc::string::ToString;
use chrono::{Datelike, NaiveDate};
#[cfg(feature = "std")]
use chrono::Local;
use crate::{
model::{ModelRc, VecModel},
SharedString,
};
pub fn use_24_hour_format() -> bool { pub fn use_24_hour_format() -> bool {
true true
} }
fn month_day_count(year: i32, month: u32) -> Option<i64> {
Some(
NaiveDate::from_ymd_opt(
match month {
12 => year + 1,
_ => year,
},
match month {
12 => 1,
_ => month + 1,
},
1,
)?
.signed_duration_since(NaiveDate::from_ymd_opt(year, month, 1)?)
.num_days(),
)
}
pub fn month_for_date(month: u32, year: i32) -> ModelRc<ModelRc<i32>> {
let days = Rc::new(VecModel::default());
// The result is only None if month == 0, it should not happen because the function is only
// used internal and not directly by the user. So it is ok to return an empty list if it
// is none
if let Some(count) = month_day_count(year, month) {
for d in 1..(count + 1) {
let day = Rc::new(VecModel::from_slice(&[d as i32, month as i32, year]));
days.push(day.into());
}
}
days.into()
}
pub fn month_offset(month: u32, year: i32) -> i32 {
if let Some(date) = NaiveDate::from_ymd_opt(year, month, 1) {
let offset = date.weekday().number_from_monday() as i32;
// sunday
if offset >= 7 {
return 0;
}
return offset;
}
// The result is only None if month == 0, it should not happen because the function is only
// used internal and not directly by the user. So it is ok to return 0 on a None result
0
}
pub fn format_date(format: &SharedString, day: u32, month: u32, year: i32) -> SharedString {
if let Some(date) = NaiveDate::from_ymd_opt(year, month, day) {
return date.format(format.as_str()).to_string().into();
}
// Don't panic, this function is used only internal
SharedString::default()
}
pub fn valid_date(date: &str, format: &str) -> bool {
NaiveDate::parse_from_str(date, format).is_ok()
}
pub fn parse_date(date: &str, format: &str) -> ModelRc<i32> {
let date_model = Rc::new(VecModel::default());
if let Ok(date) = NaiveDate::parse_from_str(date, format) {
date_model.push(date.day() as i32);
date_model.push(date.month() as i32);
date_model.push(date.year());
}
date_model.into()
}
#[cfg(feature = "std")]
pub fn date_now() -> ModelRc<i32> {
let now = Local::now().date_naive();
Rc::new(VecModel::from_slice(&[now.day() as i32, now.month() as i32, now.year()])).into()
}
// display the today date is currently not implemented for no_std
#[cfg(not(feature = "std"))]
pub fn date_now() -> ModelRc<i32> {
Rc::new(VecModel::from_slice(&[-1, -1, -1])).into()
}
pub fn week_days_short() -> ModelRc<SharedString> {
let format = SharedString::from("%a");
Rc::new(VecModel::from_slice(&[
SharedString::from(&format_date(&format, 26, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 27, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 28, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 29, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 30, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 31, 5, 2024).as_str()[0..1]),
SharedString::from(&format_date(&format, 1, 6, 2024).as_str()[0..1]),
]))
.into()
}
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
mod ffi { mod ffi {
#![allow(unsafe_code)] #![allow(unsafe_code)]

View file

@ -6,7 +6,7 @@ use crate::dynamic_item_tree::InstanceRef;
use core::pin::Pin; use core::pin::Pin;
use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush}; use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush};
use corelib::items::{ColorScheme, ItemRef, PropertyAnimation}; use corelib::items::{ColorScheme, ItemRef, PropertyAnimation};
use corelib::model::{Model, ModelExt, ModelRc}; use corelib::model::{Model, ModelExt, ModelRc, VecModel};
use corelib::rtti::AnimatedBindingKind; use corelib::rtti::AnimatedBindingKind;
use corelib::{Brush, Color, PathData, SharedString, SharedVector}; use corelib::{Brush, Color, PathData, SharedString, SharedVector};
use i_slint_compiler::expression_tree::{ use i_slint_compiler::expression_tree::{
@ -955,6 +955,80 @@ fn call_builtin_function(
panic!("Cannot get the window from a global component") panic!("Cannot get the window from a global component")
} }
}, },
BuiltinFunction::MonthForDate => {
let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
let month = i_slint_core::date_time::month_for_date(m, y);
let month_model = Rc::new(VecModel::default());
for i in 0..month.row_count() {
let current_month = Rc::new(VecModel::default());
for j in 0..month.row_data(i).unwrap().row_count() {
current_month.push(Value::Number(
month.row_data(i).unwrap().row_data(j).unwrap() as f64,
));
}
month_model.push(Value::Model(ModelRc::new(current_month)));
}
Value::Model(ModelRc::new(month_model))
}
BuiltinFunction::MonthOffset => {
let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
Value::Number(i_slint_core::date_time::month_offset(m, y) as f64)
}
BuiltinFunction::FormatDate => {
let f: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
let d: u32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
let m: u32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
let y: i32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
Value::String(i_slint_core::date_time::format_date(&f, d, m, y))
}
BuiltinFunction::WeekDaysShort => {
let weekdays = i_slint_core::date_time::week_days_short();
let model = Rc::new(VecModel::default());
for i in 0..weekdays.row_count() {
model.push(Value::String(weekdays.row_data(i).unwrap()));
}
Value::Model(ModelRc::new(model))
}
BuiltinFunction::DateNow => {
let date = i_slint_core::date_time::date_now();
let model = Rc::new(VecModel::default());
for i in 0..date.row_count() {
model.push(Value::Number(date.row_data(i).unwrap() as f64));
}
Value::Model(ModelRc::new(model))
}
BuiltinFunction::ValidDate => {
let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
Value::Bool(i_slint_core::date_time::valid_date(d.as_str(), f.as_str()))
}
BuiltinFunction::ParseDate => {
let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
let date = i_slint_core::date_time::parse_date(d.as_str(), f.as_str());
let model = Rc::new(VecModel::default());
for i in 0..date.row_count() {
model.push(Value::Number(date.row_data(i).unwrap() as f64));
}
Value::Model(ModelRc::new(model))
}
BuiltinFunction::TextInputFocused => match local_context.component_instance { BuiltinFunction::TextInputFocused => match local_context.component_instance {
ComponentInstance::InstanceRef(component) => { ComponentInstance::InstanceRef(component) => {
Value::Bool(component.access_window(|window| window.text_input_focused()) as _) Value::Bool(component.access_window(|window| window.text_input_focused()) as _)

View file

@ -1,5 +1,5 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { DatePicker, Date, Button } from "std-widgets.slint"; import { DatePicker, Date, Button } from "std-widgets.slint";
export { Date } export { Date }
@ -8,12 +8,18 @@ export component TestCase inherits Window {
width: 600px; width: 600px;
height: 600px; height: 600px;
date-picker := datePicker { date-picker := DatePicker {
ok-text: "OK-BUTTON";
x: 0; x: 0;
y: 0; y: 0;
accepted(date) => {
root.result-date = date;
}
} }
in property <Date> date <=> date-picker.date; in property <Date> date <=> date-picker.date;
out property <Date> result-date;
} }
/* /*
@ -23,9 +29,12 @@ use i_slint_backend_testing::mock_elapsed_time;
let instance = TestCase::new().unwrap(); let instance = TestCase::new().unwrap();
instance.set_time(Date{ day: 17, month: 5, year: 2024}); instance.set_date(Date{ day: 17, month: 5, year: 2024});
mock_elapsed_time(500); let mut ok_button_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, "OK-BUTTON");
let ok_button = ok_button_search.next().unwrap();
ok_button.invoke_accessible_action_default();
assert_eq!(instance-result-date, Date { day: 17, month: 5; year: 2024});
*/ */