diff --git a/api/cpp/cbindgen.rs b/api/cpp/cbindgen.rs index f8c6463eaab..7729c8bbb01 100644 --- a/api/cpp/cbindgen.rs +++ b/api/cpp/cbindgen.rs @@ -327,6 +327,7 @@ fn gen_corelib( "FillRule", "MouseCursor", "InputType", + "CapsMode", "StandardButtonKind", "DialogButtonRole", "FocusReason", diff --git a/internal/backends/android-activity/javahelper.rs b/internal/backends/android-activity/javahelper.rs index 12733f4cc08..c0ba5643b02 100644 --- a/internal/backends/android-activity/javahelper.rs +++ b/internal/backends/android-activity/javahelper.rs @@ -4,7 +4,7 @@ use super::*; use i_slint_core::api::{PhysicalPosition, PhysicalSize}; use i_slint_core::graphics::{euclid, Color}; -use i_slint_core::items::{ColorScheme, InputType}; +use i_slint_core::items::{CapsMode, ColorScheme, InputType}; use i_slint_core::platform::WindowAdapter; use i_slint_core::SharedString; use jni::objects::{JClass, JObject, JString, JValue}; @@ -178,7 +178,21 @@ impl JavaHelper { let class_it = env.find_class("android/text/InputType")?; let input_type = match data.input_type { - InputType::Text => env.get_static_field(&class_it, "TYPE_CLASS_TEXT", "I")?.i()?, + InputType::Text => { + let caps_mode = match data.caps_mode { + CapsMode::None => 0 as jint, + CapsMode::Sentences => env + .get_static_field(&class_it, "TYPE_TEXT_FLAG_CAP_SENTENCES", "I")? + .i()?, + CapsMode::Words => { + env.get_static_field(&class_it, "TYPE_TEXT_FLAG_CAP_WORDS", "I")?.i()? + } + CapsMode::All => env + .get_static_field(&class_it, "TYPE_TEXT_FLAG_CAP_CHARACTERS", "I")? + .i()?, + }; + env.get_static_field(&class_it, "TYPE_CLASS_TEXT", "I")?.i()? | caps_mode + } InputType::Password => { env.get_static_field(&class_it, "TYPE_TEXT_VARIATION_PASSWORD", "I")?.i()? | env.get_static_field(&class_it, "TYPE_CLASS_TEXT", "I")?.i()? diff --git a/internal/backends/qt/qt_widgets/lineedit.rs b/internal/backends/qt/qt_widgets/lineedit.rs index 7fa1835eef4..69c8f10b0d4 100644 --- a/internal/backends/qt/qt_widgets/lineedit.rs +++ b/internal/backends/qt/qt_widgets/lineedit.rs @@ -3,7 +3,7 @@ use i_slint_core::graphics::{Image, Rgba8Pixel, SharedPixelBuffer}; use i_slint_core::input::FocusEventResult; -use i_slint_core::items::InputType; +use i_slint_core::items::{CapsMode, InputType}; use super::*; @@ -20,6 +20,7 @@ pub struct NativeLineEdit { pub enabled: Property, pub input_type: Property, pub clear_icon: Property, + pub caps_mode: Property, widget_ptr: std::cell::Cell, animation_tracker: Property, } diff --git a/internal/common/enums.rs b/internal/common/enums.rs index cc7dbe03c86..c057e95a206 100644 --- a/internal/common/enums.rs +++ b/internal/common/enums.rs @@ -66,6 +66,19 @@ macro_rules! for_each_enums { Center, } + /// This enum describes the how the soft-keyboard auto-capitalization should work for `TextInput`s. + /// Currently only supported on Android. + enum CapsMode { + /// No auto-capitalization + None, + /// Capitalize the first character of each sentence + Sentences, + /// capitalize the first character of each word + Words, + /// Capitalize all characters + All, + } + /// This enum describes whether an event was rejected or accepted by an event handler. enum EventResult { /// The event is rejected by this event handler and may then be handled by the parent item diff --git a/internal/compiler/builtins.slint b/internal/compiler/builtins.slint index 6e3c12098f5..928fbf0ed60 100644 --- a/internal/compiler/builtins.slint +++ b/internal/compiler/builtins.slint @@ -316,6 +316,7 @@ export component TextInput { in property page-height; in property text-cursor-width; // StyleMetrics.text-cursor-width set in apply_default_properties_from_style in property input-type; + in property caps-mode; // Internal, undocumented property, only exposed for tests. out property cursor-position_byte-offset; // Internal, undocumented property, only exposed for tests. diff --git a/internal/compiler/widgets/common/lineedit-base.slint b/internal/compiler/widgets/common/lineedit-base.slint index 3ae49abbdc4..fb43113827e 100644 --- a/internal/compiler/widgets/common/lineedit-base.slint +++ b/internal/compiler/widgets/common/lineedit-base.slint @@ -9,6 +9,7 @@ export component LineEditBase inherits Rectangle { in property enabled <=> text-input.enabled; out property has-focus: text-input.has-focus; in property input-type <=> text-input.input-type; + in property caps-mode <=> text-input.caps-mode; in property horizontal-alignment <=> text-input.horizontal-alignment; in property read-only <=> text-input.read-only; in property font-weight <=> text-input.font-weight; diff --git a/internal/compiler/widgets/cosmic/lineedit.slint b/internal/compiler/widgets/cosmic/lineedit.slint index d6d5b04d9b5..52fbec0915b 100644 --- a/internal/compiler/widgets/cosmic/lineedit.slint +++ b/internal/compiler/widgets/cosmic/lineedit.slint @@ -7,6 +7,7 @@ import { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from "../common export component LineEdit { in property enabled <=> base.enabled; in property input-type; + in property caps-mode <=> base.caps-mode; in property horizontal-alignment <=> base.horizontal-alignment; in property read-only <=> base.read-only; in property font-size <=> base.font-size; diff --git a/internal/compiler/widgets/cupertino/lineedit.slint b/internal/compiler/widgets/cupertino/lineedit.slint index febe20b0787..1201f258d81 100644 --- a/internal/compiler/widgets/cupertino/lineedit.slint +++ b/internal/compiler/widgets/cupertino/lineedit.slint @@ -8,6 +8,7 @@ import { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from "../common export component LineEdit { in property enabled <=> base.enabled; in property input-type; + in property caps-mode <=> base.caps-mode; in property horizontal-alignment <=> base.horizontal-alignment; in property read-only <=> base.read-only; in property font-size <=> base.font-size; diff --git a/internal/compiler/widgets/fluent/lineedit.slint b/internal/compiler/widgets/fluent/lineedit.slint index 1c0aca460b8..a2f33c09615 100644 --- a/internal/compiler/widgets/fluent/lineedit.slint +++ b/internal/compiler/widgets/fluent/lineedit.slint @@ -7,6 +7,7 @@ import { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from "../common export component LineEdit { in property enabled <=> base.enabled; in property input-type; + in property caps-mode <=> base.caps-mode; in property horizontal-alignment <=> base.horizontal-alignment; in property read-only <=> base.read-only; in property font-size <=> base.font-size; diff --git a/internal/compiler/widgets/material/lineedit.slint b/internal/compiler/widgets/material/lineedit.slint index 0900cae84b9..e0c89599667 100644 --- a/internal/compiler/widgets/material/lineedit.slint +++ b/internal/compiler/widgets/material/lineedit.slint @@ -10,6 +10,7 @@ export component LineEdit { in property placeholder-text <=> base.placeholder-text; in property enabled <=> base.enabled; in property input-type; + in property caps-mode <=> base.caps-mode; in property horizontal-alignment <=> base.horizontal-alignment; in property read-only <=> base.read-only; out property has-focus: base.has-focus; diff --git a/internal/compiler/widgets/qt/lineedit.slint b/internal/compiler/widgets/qt/lineedit.slint index b3bd4c4c559..a16f32b4fd8 100644 --- a/internal/compiler/widgets/qt/lineedit.slint +++ b/internal/compiler/widgets/qt/lineedit.slint @@ -7,6 +7,7 @@ export component LineEdit { in property font-size <=> inner.font-size; in property placeholder-text <=> inner.placeholder-text; in property input-type <=> inner.input-type; + in property caps-mode <=> inner.caps-mode; in property horizontal-alignment <=> inner.horizontal-alignment; in property read-only <=> inner.read-only; in property enabled: true; diff --git a/internal/core/items/text.rs b/internal/core/items/text.rs index 0f2b445806d..75d54defb8b 100644 --- a/internal/core/items/text.rs +++ b/internal/core/items/text.rs @@ -8,7 +8,7 @@ When adding an item or a property, it needs to be kept in sync with different pl Lookup the [`crate::items`] module documentation. */ use super::{ - EventResult, FontMetrics, InputType, Item, ItemConsts, ItemRc, ItemRef, KeyEventArg, + CapsMode, EventResult, FontMetrics, InputType, Item, ItemConsts, ItemRc, ItemRef, KeyEventArg, KeyEventResult, KeyEventType, PointArg, PointerEventButton, RenderingResult, TextHorizontalAlignment, TextOverflow, TextStrokeStyle, TextVerticalAlignment, TextWrap, VoidArg, WindowItem, @@ -484,6 +484,7 @@ pub struct TextInput { pub vertical_alignment: Property, pub wrap: Property, pub input_type: Property, + pub caps_mode: Property, pub letter_spacing: Property, pub width: Property, pub height: Property, @@ -1498,6 +1499,7 @@ impl TextInput { cursor_rect_size, anchor_point, input_type: self.input_type(), + caps_mode: self.caps_mode(), } } diff --git a/internal/core/window.rs b/internal/core/window.rs index 81a8e0e0fe0..53eed35739d 100644 --- a/internal/core/window.rs +++ b/internal/core/window.rs @@ -18,7 +18,7 @@ use crate::item_tree::{ ItemRc, ItemTreeRc, ItemTreeRef, ItemTreeVTable, ItemTreeWeak, ItemWeak, ParentItemTraversalMode, }; -use crate::items::{ColorScheme, InputType, ItemRef, MouseCursor, PopupClosePolicy}; +use crate::items::{CapsMode, ColorScheme, InputType, ItemRef, MouseCursor, PopupClosePolicy}; use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, SizeLengths}; use crate::menus::MenuVTable; use crate::properties::{Property, PropertyTracker}; @@ -293,6 +293,8 @@ pub struct InputMethodProperties { pub anchor_point: LogicalPosition, /// The type of input for the text edit. pub input_type: InputType, + /// The caps mode for the text edit + pub caps_mode: CapsMode, } /// This struct describes layout constraints of a resizable element, such as a window. @@ -915,6 +917,11 @@ impl WindowInner { } } + /// Unfocus the currently focused item, if any. + pub fn unfocus_current(&self) { + self.take_focus_item(&FocusEvent::FocusOut(FocusReason::Programmatic)); + } + /// Publish the new focus_item to this Window and return the FocusEventResult /// /// This sends a FocusIn event!