Skip to content

Commit 46e977d

Browse files
committed
TextInput: Add focus-policy
ChangeLog: TextInput: Added `focus-policy` property.
1 parent bd6bcf7 commit 46e977d

File tree

5 files changed

+284
-20
lines changed

5 files changed

+284
-20
lines changed

docs/astro/src/content/docs/reference/keyboard-input/focusscope.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Is `true` when the element has keyboard focus.
6262

6363
### focus-policy
6464
<SlintProperty propName="focus-policy" typeName="enum" enumName="FocusPolicy">
65-
The focus policy of the scope.
65+
The focus policy of the scope. Use this to control if the `TextInput` should claim focus on click or tab navigation.
6666
</SlintProperty>
6767

6868
## Functions

docs/astro/src/content/docs/reference/keyboard-input/textinput.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ The design metrics of the font scaled to the font pixel size used by the element
7878
`TextInput` sets this to `true` when it's focused. Only then it receives <Link type="KeyEvent"/>s.
7979
</SlintProperty>
8080

81+
### focus-policy
82+
<SlintProperty propName="focus-policy" typeName="enum" enumName="FocusPolicy">
83+
The focus policy of the `TextInput`. Use this to control if the `TextInput` should claim focus on click or tab navigation.
84+
</SlintProperty>
85+
8186
### horizontal-alignment
8287
<SlintProperty propName="horizontal-alignment" typeName="enum" enumName="TextHorizontalAlignment">
8388
The horizontal alignment of the text.

internal/compiler/builtins.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ export component TextInput {
323323
// Internal, undocumented property, only exposed for tests.
324324
out property <int> anchor-position-byte-offset;
325325
out property <bool> has-focus;
326+
in property <FocusPolicy> focus-policy;
326327
callback accepted;
327328
callback edited;
328329
callback cursor_position_changed(position: Point);

internal/core/items/text.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::input::{
1919
KeyEvent, KeyboardModifiers, MouseEvent, StandardShortcut, TextShortcut,
2020
};
2121
use crate::item_rendering::{CachedRenderingData, ItemRenderer, RenderText};
22+
use crate::items::FocusPolicy;
2223
use crate::layout::{LayoutInfo, Orientation};
2324
use crate::lengths::{
2425
LogicalLength, LogicalPoint, LogicalRect, LogicalSize, ScaleFactor, SizeLengths,
@@ -520,6 +521,7 @@ pub struct TextInput {
520521
pub single_line: Property<bool>,
521522
pub read_only: Property<bool>,
522523
pub preedit_text: Property<SharedString>,
524+
pub focus_policy: Property<FocusPolicy>,
523525
/// A selection within the preedit (cursor and anchor)
524526
preedit_selection: Property<PreEditSelection>,
525527
pub cached_rendering_data: CachedRenderingData,
@@ -610,6 +612,11 @@ impl Item for TextInput {
610612
}
611613
match event {
612614
MouseEvent::Pressed { position, button: PointerEventButton::Left, click_count } => {
615+
#[cfg(not(target_os = "android"))]
616+
if !self.ensure_click_focus_and_ime(window_adapter, self_rc) {
617+
return InputEventResult::EventIgnored;
618+
}
619+
613620
let clicked_offset =
614621
self.byte_offset_for_position(*position, window_adapter, self_rc) as i32;
615622
self.as_ref().pressed.set((click_count % 3) + 1);
@@ -618,9 +625,6 @@ impl Item for TextInput {
618625
self.as_ref().anchor_position_byte_offset.set(clicked_offset);
619626
}
620627

621-
#[cfg(not(target_os = "android"))]
622-
self.ensure_focus_and_ime(window_adapter, self_rc);
623-
624628
match click_count % 3 {
625629
0 => self.set_cursor_position(
626630
clicked_offset,
@@ -638,13 +642,17 @@ impl Item for TextInput {
638642
}
639643
MouseEvent::Pressed { button: PointerEventButton::Middle, .. } => {
640644
#[cfg(not(target_os = "android"))]
641-
self.ensure_focus_and_ime(window_adapter, self_rc);
645+
if !self.ensure_click_focus_and_ime(window_adapter, self_rc) {
646+
return InputEventResult::EventIgnored;
647+
}
642648
}
643649
MouseEvent::Released { button: PointerEventButton::Left, .. } => {
644650
self.as_ref().pressed.set(0);
645651
self.copy_clipboard(window_adapter, Clipboard::SelectionClipboard);
646652
#[cfg(target_os = "android")]
647-
self.ensure_focus_and_ime(window_adapter, self_rc);
653+
if !self.ensure_click_focus_and_ime(window_adapter, self_rc) {
654+
return InputEventResult::EventIgnored;
655+
}
648656
}
649657
MouseEvent::Released { position, button: PointerEventButton::Middle, .. } => {
650658
let clicked_offset =
@@ -936,6 +944,20 @@ impl Item for TextInput {
936944
window_adapter: &Rc<dyn WindowAdapter>,
937945
self_rc: &ItemRc,
938946
) -> FocusEventResult {
947+
let reason = match event {
948+
FocusEvent::FocusIn(reason) | FocusEvent::FocusOut(reason) => *reason,
949+
};
950+
951+
match (reason, self.focus_policy()) {
952+
(FocusReason::TabNavigation, FocusPolicy::ClickOnly) => {
953+
return FocusEventResult::FocusIgnored
954+
}
955+
(FocusReason::PointerClick, FocusPolicy::TabOnly) => {
956+
return FocusEventResult::FocusIgnored
957+
}
958+
_ => (),
959+
}
960+
939961
match event {
940962
FocusEvent::FocusIn(_reason) => {
941963
if !self.enabled() {
@@ -1827,12 +1849,16 @@ impl TextInput {
18271849

18281850
/// When pressing the mouse (or releasing the finger, on android) we should take the focus if we don't have it already.
18291851
/// Setting the focus will show the virtual keyboard, otherwise we should make sure that the keyboard is shown if it was hidden by the user
1830-
fn ensure_focus_and_ime(
1852+
/// Returns true if the focus was set, false if the focus policy is configured to not focus on click.
1853+
fn ensure_click_focus_and_ime(
18311854
self: Pin<&Self>,
18321855
window_adapter: &Rc<dyn WindowAdapter>,
18331856
self_rc: &ItemRc,
1834-
) {
1857+
) -> bool {
18351858
if !self.has_focus() {
1859+
if self.focus_policy() == FocusPolicy::TabOnly {
1860+
return false;
1861+
}
18361862
WindowInner::from_pub(window_adapter.window()).set_focus_item(
18371863
self_rc,
18381864
true,
@@ -1845,6 +1871,7 @@ impl TextInput {
18451871
));
18461872
}
18471873
}
1874+
true
18481875
}
18491876

18501877
fn add_undo_item(self: Pin<&Self>, item: UndoItem) {

0 commit comments

Comments
 (0)