1use super::{ItemSelectionEventTriggers, TemplateAppliedEventArgs, TemplatedControlImpl, TemplatedControlImplExt, TextSearch};
2use crate::assigned_binding::AssignedBinding;
3use crate::items_source::{items_equal, ItemsChangedEventArgs};
4use crate::navigable_containers::as_navigable_container;
5use crate::selection::{
6 ISelectionModel, InternalSelectionModel, SelectionModelExtensions, SelectionModelSelectionChangedEventArgs,
7};
8use crate::utils::BindingEvaluator;
9use crate::{
10 Control, ControlImpl, ItemsControl, ItemsControlImpl, ItemsControlImplExt, SelectionChangedEventArgs,
11 SelectionMode,
12};
13use ferroui_base::collections::{FerroList, NotifyCollectionChangedAction};
14use ferroui_base::data::BindingMode;
15use ferroui_base::input::{
16 FocusChangedEventArgs, FocusManager, InputElement, InputElementImpl, InputElementImplExt, KeyEventArgs,
17 KeyboardNavigation, NavigationDirection, PointerEventArgs, TextInputEventArgs,
18};
19use ferroui_base::interactivity::{
20 IRoutedEventArgs, Interactive, InteractiveImpl, RoutedEvent, RoutedEventArgs, RoutedEventHandlerToken,
21 RoutingStrategies,
22};
23use ferroui_base::layout::LayoutableImpl;
24use ferroui_base::reactive::IDisposable;
25use ferroui_base::threading::DispatcherTimer;
26use ferroui_base::{
27 ferro_class, ferro_impl_classes, ferro_property, ferro_routed_event, instantiate, AnyValue, AttachedProperty,
28 BoxedValue, DirectProperty, DirectPropertyMetadata, FerroObjectImpl, FerroObjectImplExt, FerroProperty,
29 FerroPropertyChangedEventArgs, Ref, StyledElementImpl, StyledElementImplExt, StyledProperty,
30 StyledPropertyOptions, Visual, VisualImpl, VisualImplExt, VisualTreeAttachmentEventArgs,
31};
32use std::cell::{Cell, RefCell};
33use std::ops::Deref;
34use std::rc::Rc;
35use std::time::Duration;
36
37#[derive(Clone)]
40pub struct SelectedItemsList(pub Rc<FerroList<Option<BoxedValue>>>);
41
42impl SelectedItemsList {
43 pub fn new() -> Self {
45 Self(Rc::new(FerroList::new()))
46 }
47
48 pub fn from_items(items: impl IntoIterator<Item = Option<BoxedValue>>) -> Self {
50 Self(Rc::new(FerroList::from_items(items)))
51 }
52}
53
54impl Default for SelectedItemsList {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60impl PartialEq for SelectedItemsList {
61 fn eq(&self, other: &Self) -> bool {
62 Rc::ptr_eq(&self.0, &other.0)
63 }
64}
65
66impl Deref for SelectedItemsList {
67 type Target = FerroList<Option<BoxedValue>>;
68
69 fn deref(&self) -> &Self::Target {
70 &self.0
71 }
72}
73
74#[derive(Default)]
95struct UpdateState {
96 update_count: i32,
97 selection: Option<Rc<dyn ISelectionModel>>,
98 selected_items: Option<Option<SelectedItemsList>>,
99 selected_index: Option<i32>,
100 selected_item: Option<Option<BoxedValue>>,
101 selected_value: Option<Option<BoxedValue>>,
102}
103
104struct Reset<'a>(&'a Cell<bool>);
106
107impl Drop for Reset<'_> {
108 fn drop(&mut self) {
109 self.0.set(false);
110 }
111}
112
113#[repr(C)]
128pub struct SelectingItemsControl {
129 base: ItemsControl,
130 text_search_term: RefCell<String>,
131 text_search_timer: RefCell<Option<(Rc<DispatcherTimer>, Rc<dyn IDisposable>)>>,
132 selection: RefCell<Option<Rc<dyn ISelectionModel>>>,
133 selection_property_changed_token: Cell<u64>,
134 selection_changed_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
135 old_selected_index: Cell<i32>,
136 old_selected_item: RefCell<Option<BoxedValue>>,
137 old_selected_items: RefCell<Option<SelectedItemsList>>,
138 selected_items_snapshot: RefCell<Vec<Option<BoxedValue>>>,
139 selected_items_before_reset: RefCell<Option<Vec<Option<BoxedValue>>>>,
140 ignore_container_selection_changed: Cell<bool>,
141 update_state: RefCell<Option<UpdateState>>,
142 has_scrolled_to_selected_item: Cell<bool>,
143 selected_value_binding_evaluator: RefCell<Option<Ref<BindingEvaluator>>>,
144 is_selection_change_active: Cell<bool>,
145 unverified_selected_index: Cell<i32>,
146 auto_scroll_requested_index: Cell<i32>,
147}
148
149ferro_class! {
150 SelectingItemsControl: ItemsControl, virtuals SelectingItemsControlImpl: ItemsControlImpl {
151 fn should_trigger_selection(this, selectable: &Visual, event_args: &PointerEventArgs) -> bool;
154 fn should_trigger_selection_key(this, selectable: &Visual, event_args: &KeyEventArgs) -> bool;
157 fn update_selection_from_event(this, container: &Ref<Control>, event_args: &dyn IRoutedEventArgs) -> bool;
163 }
164}
165ferroui_base::ferro_class_info!(SelectingItemsControl { new: SelectingItemsControl::new });
166
167ferro_impl_classes!(SelectingItemsControl: LayoutableImpl, InteractiveImpl, ControlImpl);
168
169impl FerroObjectImpl for SelectingItemsControl {
170 fn constructed(this: &Self) {
171 Self::parent_constructed(this);
172
173 let weak = this.to_ref().downgrade();
174 this.items().add_source_changed(Rc::new(move || {
175 if let Some(this) = weak.upgrade() {
176 this.on_items_view_source_changed();
177 }
178 }));
179
180 let weak = this.to_ref().downgrade();
181 this.items().add_pre_collection_changed(Rc::new(move |e: &ItemsChangedEventArgs<'_>| {
182 if let Some(this) = weak.upgrade() {
183 this.on_items_view_pre_collection_changed(e);
184 }
185 }));
186 }
187
188 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
189 Self::parent_on_property_changed(this, change);
190
191 if change.property() == Self::auto_scroll_to_selected_item_property().as_property() {
192 this.auto_scroll_to_selected_item_if_necessary(this.get_anchor_index());
193 } else if change.property() == Visual::is_visible_property().as_property() {
194 if change.get_new_value::<bool>() {
195 this.auto_scroll_to_selected_item_if_necessary(this.get_anchor_index());
196 }
197 } else if change.property() == Self::selection_mode_property().as_property() {
198 let selection = this.selection.borrow().clone();
199 if let Some(selection) = selection {
200 let new_value = change.get_new_value::<SelectionMode>();
201 selection.set_single_select(!new_value.contains(SelectionMode::MULTIPLE));
202 }
203 } else if change.property() == Self::wrap_selection_property().as_property() {
204 this.set_wrap_focus(this.wrap_selection());
205 } else if change.property() == Self::selected_value_property().as_property() {
206 if this.is_selection_change_active.get() {
207 return;
208 }
209
210 let new_value = change.get_new_value::<Option<BoxedValue>>();
211
212 if let Some(state) = this.update_state.borrow_mut().as_mut() {
213 state.selected_value = Some(new_value);
214 return;
215 }
216
217 this.select_item_with_value(&new_value);
218 } else if change.property() == Self::selected_value_binding_property().as_property() {
219 let idx = this.selected_index();
220
221 if idx == -1 {
224 return;
225 }
226
227 let Some(value) = change.get_new_value::<Option<AssignedBinding>>() else {
228 this.set_current_value(Self::selected_value_property(), this.selected_item());
231 return;
232 };
233
234 let selected_item = this.selected_item();
235
236 this.is_selection_change_active.set(true);
237 let _reset = Reset(&this.is_selection_change_active);
238
239 let binding_evaluator = this.get_selected_value_binding_evaluator(&value);
240
241 this.set_current_value(Self::selected_value_property(), binding_evaluator.evaluate(&selected_item));
243 }
244 }
245}
246
247impl StyledElementImpl for SelectingItemsControl {
248 fn begin_init(this: &Self) {
249 Self::parent_begin_init(this);
250 this.begin_updating();
251 }
252
253 fn try_end_init(this: &Self) -> Result<(), ferroui_base::InitializationError> {
254 Self::parent_try_end_init(this)?;
255 this.end_updating();
256 Ok(())
257 }
258
259 fn on_data_context_begin_update(this: &Self) {
260 Self::parent_on_data_context_begin_update(this);
261 this.begin_updating();
262 }
263
264 fn on_data_context_end_update(this: &Self) {
265 Self::parent_on_data_context_end_update(this);
266 this.end_updating();
267 }
268
269 fn on_initialized(this: &Self) {
270 Self::parent_on_initialized(this);
271
272 let selection = this.selection.borrow().clone();
273 this.try_initialize_selection_source(selection.as_ref(), this.update_state.borrow().is_none());
274 this.select_inline_items_marked_as_selected();
275 }
276}
277
278impl VisualImpl for SelectingItemsControl {
279 fn on_attached_to_visual_tree(this: &Self, e: &VisualTreeAttachmentEventArgs) {
280 Self::parent_on_attached_to_visual_tree(this, e);
281
282 this.auto_scroll_to_selected_item_if_necessary(this.get_anchor_index());
283 }
284}
285
286impl InputElementImpl for SelectingItemsControl {
287 fn on_text_input(this: &Self, e: &TextInputEventArgs) {
288 if !e.handled() {
289 if !this.is_text_search_enabled() {
290 return;
291 }
292
293 this.stop_text_search_timer();
294
295 if let Some(text) = &e.text {
296 this.text_search_term.borrow_mut().push_str(text);
297 }
298
299 let term = this.text_search_term.borrow().clone();
300 let new_index = this.get_index_from_text_search(&term);
301 if new_index >= 0 {
302 this.set_selected_index(new_index);
303 }
304
305 this.start_text_search_timer();
306
307 e.set_handled(true);
308 }
309
310 Self::parent_on_text_input(this, e);
311 }
312}
313
314impl TemplatedControlImpl for SelectingItemsControl {
315 fn on_apply_template(this: &Self, e: &TemplateAppliedEventArgs) {
316 Self::parent_on_apply_template(this, e);
317
318 this.auto_scroll_to_selected_item_if_necessary(this.get_anchor_index());
319 }
320}
321
322impl ItemsControlImpl for SelectingItemsControl {
323 fn on_items_view_collection_changed(this: &Self, e: &ItemsChangedEventArgs<'_>) {
324 Self::parent_on_items_view_collection_changed(this, e);
325
326 if this.update_state.borrow().is_some() {
328 return;
329 }
330
331 if this.always_selected() && this.selected_index() == -1 && this.item_count() > 0 {
332 this.set_selected_index(this.choose_first_visible_and_enabled_index());
333 }
334 }
335
336 fn prepare_container_for_item_override(
337 this: &Self,
338 container: &Ref<Control>,
339 item: &Option<BoxedValue>,
340 index: i32,
341 ) {
342 this.get_or_create_selection_model();
347
348 Self::parent_prepare_container_for_item_override(this, container, item, index);
349 }
350
351 fn container_for_item_prepared_override(
352 this: &Self,
353 container: &Ref<Control>,
354 item: &Option<BoxedValue>,
355 index: i32,
356 ) {
357 Self::parent_container_for_item_prepared_override(this, container, item, index);
358
359 if !container.is_set(Self::is_selected_property().as_property()) {
363 this.mark_container_selected(container, this.selection().is_selected(index));
367 } else {
368 let container_is_selected = Self::get_is_selected(container);
373
374 if container_is_selected != this.selection().is_selected(index) {
375 this.update_selection(index, container_is_selected, false, true, false, false);
376 }
377 }
378
379 if this.selection().anchor_index() == index {
380 KeyboardNavigation::set_tab_once_active_element(this, Some(container.clone().upcast()));
381 }
382
383 if this.always_selected() {
384 if this.selected_index() == -1 && container.is_visible() && container.is_enabled() {
385 this.set_selected_index(index);
386 } else if index == this.selected_index() && (!container.is_visible() || !container.is_enabled()) {
387 this.move_selection_to_first_visible_and_enabled_item();
388 }
389 }
390 }
391
392 fn container_index_changed_override(this: &Self, container: &Ref<Control>, old_index: i32, new_index: i32) {
393 Self::parent_container_index_changed_override(this, container, old_index, new_index);
394 this.mark_container_selected(container, this.selection().is_selected(new_index));
395 }
396
397 fn clear_container_for_item_override(this: &Self, element: &Ref<Control>) {
398 Self::parent_clear_container_for_item_override(this, element);
399
400 this.ignore_container_selection_changed.set(true);
401 let _reset = Reset(&this.ignore_container_selection_changed);
402 element.clear_value(Self::is_selected_property());
403 }
404}
405
406impl SelectingItemsControlImpl for SelectingItemsControl {
407 fn should_trigger_selection(_this: &Self, selectable: &Visual, event_args: &PointerEventArgs) -> bool {
408 ItemSelectionEventTriggers::should_trigger_selection(selectable, event_args)
409 }
410
411 fn should_trigger_selection_key(_this: &Self, selectable: &Visual, event_args: &KeyEventArgs) -> bool {
412 ItemSelectionEventTriggers::should_trigger_selection_key(selectable, event_args)
413 }
414
415 fn update_selection_from_event(this: &Self, container: &Ref<Control>, event_args: &dyn IRoutedEventArgs) -> bool {
416 let args = event_args.as_routed_event_args();
417
418 if args.handled() {
419 return false;
420 }
421
422 let container_index = this.index_from_container(container);
423 if container_index == -1 {
424 return false;
425 }
426
427 let pointer_event = event_args.downcast_ref::<PointerEventArgs>();
428 let key_event = event_args.downcast_ref::<KeyEventArgs>();
429 let is_focus_event = event_args.is::<FocusChangedEventArgs>();
430
431 let triggers = match (pointer_event, key_event) {
432 (Some(pointer_event), _) => this.should_trigger_selection(container, pointer_event),
433 (None, Some(key_event)) => this.should_trigger_selection_key(container, key_event),
434 (None, None) => is_focus_event,
435 };
436
437 if !triggers {
438 return false;
439 }
440
441 this.update_selection(
442 container_index,
443 true,
444 ItemSelectionEventTriggers::has_range_selection_modifier(container, event_args),
445 ItemSelectionEventTriggers::has_toggle_selection_modifier(container, event_args),
446 pointer_event.is_some_and(|e| e.properties().is_right_button_pressed),
447 is_focus_event,
448 );
449
450 if pointer_event.is_some() {
451 crate::platform::PlatformFeedbackExtensions::perform_feedback(
452 &**container as &InputElement,
453 crate::platform::FeedbackAction::click(),
454 );
455 }
456
457 args.set_handled(true);
458 true
459 }
460}
461
462ferroui_base::ferro_properties! { impl SelectingItemsControl, also [
463 SelectingItemsControl::wrap_selection_property,
464] {
465 ferro_property!(
466 pub fn auto_scroll_to_selected_item_property() -> StyledProperty<bool> {
468 FerroProperty::register::<SelectingItemsControl, _>("AutoScrollToSelectedItem", true)
469 }
470 );
471
472 ferro_property!(
473 pub fn selected_index_property() -> DirectProperty<SelectingItemsControl, i32> {
475 FerroProperty::register_direct_with::<SelectingItemsControl, _>(
476 "SelectedIndex",
477 |o| o.selected_index(),
478 Some(|o, v| o.set_selected_index(v)),
479 DirectPropertyMetadata::new(Some(-1)).with_default_binding_mode(BindingMode::TwoWay),
480 )
481 }
482 );
483
484 ferro_property!(
485 pub fn selected_item_property() -> DirectProperty<SelectingItemsControl, Option<BoxedValue>> {
487 FerroProperty::register_direct_with::<SelectingItemsControl, _>(
488 "SelectedItem",
489 |o| o.selected_item(),
490 Some(|o, v| o.set_selected_item(v)),
491 DirectPropertyMetadata::new(Some(None))
492 .with_default_binding_mode(BindingMode::TwoWay)
493 .with_enable_data_validation(true),
494 )
495 }
496 );
497
498 ferro_property!(
499 pub fn selected_value_property() -> StyledProperty<Option<BoxedValue>> {
501 FerroProperty::register_with::<SelectingItemsControl, _>(
502 "SelectedValue",
503 StyledPropertyOptions::new(None).default_binding_mode(BindingMode::TwoWay),
504 )
505 }
506 );
507
508 ferro_property!(
509 pub fn selected_value_binding_property() -> StyledProperty<Option<AssignedBinding>> {
511 FerroProperty::register::<SelectingItemsControl, _>("SelectedValueBinding", None)
512 }
513 );
514
515 ferro_property!(
516 pub fn selected_items_property() -> DirectProperty<SelectingItemsControl, Option<SelectedItemsList>> {
518 FerroProperty::register_direct::<SelectingItemsControl, _>(
519 "SelectedItems",
520 |o| o.selected_items(),
521 Some(|o, v| o.set_selected_items(v)),
522 None,
523 )
524 }
525 );
526
527 ferro_property!(
528 pub fn selection_property() -> DirectProperty<SelectingItemsControl, Option<Rc<dyn ISelectionModel>>> {
530 FerroProperty::register_direct::<SelectingItemsControl, _>(
531 "Selection",
532 |o| Some(o.selection()),
533 Some(|o, v| o.set_selection(v)),
534 None,
535 )
536 }
537 );
538
539 ferro_property!(
540 pub fn selection_mode_property() -> StyledProperty<SelectionMode> {
542 FerroProperty::register::<SelectingItemsControl, _>("SelectionMode", SelectionMode::SINGLE)
543 }
544 );
545
546 ferro_property!(
547 pub fn is_selected_property() -> AttachedProperty<bool> {
550 FerroProperty::register_attached_with::<SelectingItemsControl, Control, _>(
551 "IsSelected",
552 StyledPropertyOptions::new(false).default_binding_mode(BindingMode::TwoWay),
553 )
554 }
555 );
556
557 ferro_property!(
558 pub fn is_text_search_enabled_property() -> StyledProperty<bool> {
560 FerroProperty::register::<SelectingItemsControl, _>("IsTextSearchEnabled", false)
561 }
562 );
563} }
564
565impl SelectingItemsControl {
566 ferro_routed_event!(
567 pub fn is_selected_changed_event() -> RoutedEvent<RoutedEventArgs> {
571 RoutedEvent::register::<SelectingItemsControl, _>("IsSelectedChanged", RoutingStrategies::BUBBLE)
572 }
573 );
574
575 ferro_routed_event!(
576 pub fn selection_changed_event() -> RoutedEvent<SelectionChangedEventArgs> {
578 RoutedEvent::register::<SelectingItemsControl, _>("SelectionChanged", RoutingStrategies::BUBBLE)
579 }
580 );
581
582 ferro_property!(for SelectingItemsControl;
583 pub fn wrap_selection_property() -> StyledProperty<bool> {
585 FerroProperty::register::<SelectingItemsControl, _>("WrapSelection", false)
586 }
587 );
588
589 pub(crate) fn static_constructor() {
590 Self::is_selected_changed_event()
591 .add_class_handler::<SelectingItemsControl>(|x, e| x.container_selection_changed(e));
592 }
593
594 pub fn construct() -> Self {
596 Self {
597 base: ItemsControl::construct(),
598 text_search_term: RefCell::new(String::new()),
599 text_search_timer: RefCell::new(None),
600 selection: RefCell::new(None),
601 selection_property_changed_token: Cell::new(0),
602 selection_changed_subscription: RefCell::new(None),
603 old_selected_index: Cell::new(0),
604 old_selected_item: RefCell::new(None),
605 old_selected_items: RefCell::new(None),
606 selected_items_snapshot: RefCell::new(Vec::new()),
607 selected_items_before_reset: RefCell::new(None),
608 ignore_container_selection_changed: Cell::new(false),
609 update_state: RefCell::new(None),
610 has_scrolled_to_selected_item: Cell::new(false),
611 selected_value_binding_evaluator: RefCell::new(None),
612 is_selection_change_active: Cell::new(false),
613 unverified_selected_index: Cell::new(-1),
614 auto_scroll_requested_index: Cell::new(-1),
615 }
616 }
617
618 pub fn new() -> Ref<Self> {
619 instantiate(Self::construct())
620 }
621
622 pub fn selection_changed(
624 &self,
625 handler: impl Fn(&Interactive, &SelectionChangedEventArgs) + 'static,
626 ) -> RoutedEventHandlerToken {
627 self.add_handler(Self::selection_changed_event(), handler)
628 }
629
630 pub fn auto_scroll_to_selected_item(&self) -> bool {
633 self.get_value(Self::auto_scroll_to_selected_item_property())
634 }
635
636 pub fn set_auto_scroll_to_selected_item(&self, value: bool) {
637 self.set_value(Self::auto_scroll_to_selected_item_property(), value)
638 }
639
640 pub fn selected_index(&self) -> i32 {
642 let pending = self.update_state.borrow().as_ref().map(|state| state.selected_index);
649 if let Some(pending) = pending {
650 return match pending {
651 Some(selected_index) => selected_index,
652 None => self.try_get_existing_selection().map_or(-1, |selection| selection.selected_index()),
653 };
654 }
655
656 self.selection().selected_index()
657 }
658
659 pub fn set_selected_index(&self, value: i32) {
660 if let Some(state) = self.update_state.borrow_mut().as_mut() {
661 state.selected_index = Some(value);
662 return;
663 }
664
665 self.selection().set_selected_index(value);
666 }
667
668 pub fn selected_item(&self) -> Option<BoxedValue> {
670 let pending = self.update_state.borrow().as_ref().map(|state| state.selected_item.clone());
672 if let Some(pending) = pending {
673 return match pending {
674 Some(selected_item) => selected_item,
675 None => self.try_get_existing_selection().and_then(|selection| selection.selected_item()),
676 };
677 }
678
679 self.selection().selected_item()
680 }
681
682 pub fn set_selected_item(&self, value: Option<BoxedValue>) {
683 if let Some(state) = self.update_state.borrow_mut().as_mut() {
684 state.selected_item = Some(value);
685 return;
686 }
687
688 self.selection().set_selected_item(value);
689 }
690
691 pub fn selected_value_binding(&self) -> Option<AssignedBinding> {
694 self.get_value(Self::selected_value_binding_property())
695 }
696
697 pub fn set_selected_value_binding(&self, value: Option<AssignedBinding>) {
698 self.set_value(Self::selected_value_binding_property(), value)
699 }
700
701 pub fn selected_value(&self) -> Option<BoxedValue> {
704 self.get_value(Self::selected_value_property())
705 }
706
707 pub fn set_selected_value(&self, value: Option<BoxedValue>) {
708 self.set_value(Self::selected_value_property(), value)
709 }
710
711 pub fn selected_items(&self) -> Option<SelectedItemsList> {
717 let pending = self.update_state.borrow().as_ref().and_then(|state| state.selected_items.clone());
719 if let Some(pending) = pending {
720 return pending;
721 }
722
723 let selection = self.selection();
724 if let Some(ism) = selection.as_internal_selection_model() {
725 let result = SelectedItemsList(ism.writable_selected_items());
726 *self.old_selected_items.borrow_mut() = Some(result.clone());
727 return Some(result);
728 }
729
730 None
731 }
732
733 pub fn set_selected_items(&self, value: Option<SelectedItemsList>) {
734 if let Some(state) = self.update_state.borrow_mut().as_mut() {
735 state.selected_items = Some(value);
736 return;
737 }
738
739 let selection = self.selection();
740 match selection.as_internal_selection_model() {
741 Some(i) => i.set_writable_selected_items(value.map(|v| v.0)),
742 None => panic!("Cannot set both Selection and SelectedItems."),
743 }
744 }
745
746 pub fn selection(&self) -> Rc<dyn ISelectionModel> {
748 let pending = self.update_state.borrow().as_ref().and_then(|state| state.selection.clone());
749 match pending {
750 Some(selection) => selection,
751 None => self.get_or_create_selection_model(),
752 }
753 }
754
755 pub fn set_selection(&self, value: Option<Rc<dyn ISelectionModel>>) {
756 let value = value.unwrap_or_else(|| self.create_default_selection_model());
757
758 if let Some(state) = self.update_state.borrow_mut().as_mut() {
759 state.selection = Some(value);
760 return;
761 }
762
763 let current = self.selection.borrow().clone();
764 if current.as_ref().is_some_and(|current| crate::selection::selection_model_ptr_eq(current, &value)) {
765 return;
766 }
767
768 if let Some(source) = value.source() {
769 if !source.ptr_eq(&self.items_view().source()) {
770 panic!(
771 "The supplied ISelectionModel already has an assigned Source but this \
772 collection is different to the Items on the control."
773 );
774 }
775 }
776
777 let old_selection = current.as_ref().map(|selection| selection.selected_items().to_vec());
778 self.deinitialize_selection_model(current.as_ref());
779 *self.selection.borrow_mut() = Some(value.clone());
780
781 if let Some(old_selection) = old_selection.filter(|items| !items.is_empty()) {
782 self.raise_event(&SelectionChangedEventArgs::new(
783 Some(Self::selection_changed_event()),
784 old_selection,
785 Vec::new(),
786 ));
787 }
788
789 self.initialize_selection_model(&value);
790 let selected_items = self.selected_items();
791 let old_selected_items = self.old_selected_items.borrow().clone();
792 if old_selected_items != selected_items {
793 self.raise_direct_property_changed(Self::selected_items_property(), &old_selected_items, &selected_items);
794 *self.old_selected_items.borrow_mut() = selected_items;
795 }
796 }
797
798 pub fn is_text_search_enabled(&self) -> bool {
801 self.get_value(Self::is_text_search_enabled_property())
802 }
803
804 pub fn set_is_text_search_enabled(&self, value: bool) {
805 self.set_value(Self::is_text_search_enabled_property(), value)
806 }
807
808 pub fn wrap_selection(&self) -> bool {
811 self.get_value(Self::wrap_selection_property())
812 }
813
814 pub fn set_wrap_selection(&self, value: bool) {
815 self.set_value(Self::wrap_selection_property(), value)
816 }
817
818 pub fn selection_mode(&self) -> SelectionMode {
824 self.get_value(Self::selection_mode_property())
825 }
826
827 pub fn set_selection_mode(&self, value: SelectionMode) {
828 self.set_value(Self::selection_mode_property(), value)
829 }
830
831 pub fn always_selected(&self) -> bool {
833 self.selection_mode().contains(SelectionMode::ALWAYS_SELECTED)
834 }
835
836 fn select_inline_items_marked_as_selected(&self) {
840 if self.items_source().is_some() || self.selection().count() > 0 {
841 return;
842 }
843
844 let multiple = self.selection_mode().contains(SelectionMode::MULTIPLE);
845 let items_view = self.items_view().clone();
846
847 for i in 0..items_view.count() {
848 let container = items_view.get_at(i).as_ref().and_then(Control::from_boxed);
849 if let Some(container) = container {
850 if container.is_set(Self::is_selected_property().as_property()) && Self::get_is_selected(&container) {
851 self.selection().select(i as i32);
852
853 if !multiple {
854 break;
855 }
856 }
857 }
858 }
859 }
860
861 pub fn get_is_selected(control: &Control) -> bool {
862 control.get_value(Self::is_selected_property())
863 }
864
865 pub fn set_is_selected(control: &Control, value: bool) {
867 control.set_value(Self::is_selected_property(), value)
868 }
869
870 pub fn get_container_from_event_source(&self, event_source: Option<&Ref<Visual>>) -> Option<Ref<Control>> {
875 let this: Ref<ferroui_base::StyledElement> = self.to_ref().upcast();
876 let mut current = event_source.cloned();
877
878 while let Some(visual) = current {
879 if let Some(control) = visual.cast::<Control>() {
880 if control.parent().as_ref() == Some(&this) && self.index_from_container(&control) != -1 {
881 return Some(control);
882 }
883 }
884
885 current = visual.visual_parent();
886 }
887
888 None
889 }
890
891 pub fn selecting_items_control_from_item_container(container: &Ref<Control>) -> Option<Ref<SelectingItemsControl>> {
894 ItemsControl::items_control_from_item_container(container).and_then(|c| c.cast::<SelectingItemsControl>())
895 }
896
897 fn on_items_view_pre_collection_changed(&self, e: &ItemsChangedEventArgs<'_>) {
898 if e.action == NotifyCollectionChangedAction::Reset && !self.selected_items_snapshot.borrow().is_empty() {
899 let snapshot = self.selected_items_snapshot.borrow().clone();
900 *self.selected_items_before_reset.borrow_mut() = Some(snapshot);
901 }
902 }
903
904 pub(crate) fn get_anchor_index(&self) -> i32 {
905 let selection = if self.update_state.borrow().is_some() {
906 self.try_get_existing_selection()
907 } else {
908 Some(self.selection())
909 };
910 selection.map_or(-1, |selection| selection.anchor_index())
911 }
912
913 fn try_get_existing_selection(&self) -> Option<Rc<dyn ISelectionModel>> {
914 let pending = self.update_state.borrow().as_ref().and_then(|state| state.selection.clone());
915 match pending {
916 Some(selection) => Some(selection),
917 None => self.selection.borrow().clone(),
918 }
919 }
920
921 pub fn move_selection(&self, direction: NavigationDirection, wrap: bool, range_modifier: bool) -> bool {
926 let focused = FocusManager::get_focus_manager(self).and_then(|focus| focus.get_focused_element());
927 let focused: Option<Ref<Visual>> = focused.map(Ref::upcast);
928 let from = self
929 .get_container_from_event_source(focused.as_ref())
930 .or_else(|| self.container_from_index(self.selection().anchor_index()));
931 self.move_selection_from(from.as_ref(), direction, wrap, range_modifier)
932 }
933
934 pub fn move_selection_from(
939 &self,
940 from: Option<&Ref<Control>>,
941 mut direction: NavigationDirection,
942 wrap: bool,
943 range_modifier: bool,
944 ) -> bool {
945 let Some(panel) = self.presenter().and_then(|presenter| presenter.panel()) else { return false };
946 let Some(container) = as_navigable_container(&panel) else { return false };
947
948 if from.is_none() {
949 direction = match direction {
950 NavigationDirection::Down => NavigationDirection::First,
951 NavigationDirection::Up => NavigationDirection::Last,
952 NavigationDirection::Right => NavigationDirection::First,
953 NavigationDirection::Left => NavigationDirection::Last,
954 other => other,
955 };
956 }
957
958 let from: Option<Ref<InputElement>> = from.map(|from| from.clone().upcast());
959 let next = ItemsControl::get_next_control(container, direction, from.as_ref(), wrap);
960
961 if let Some(next) = next.and_then(|next| next.cast::<Control>()) {
962 let index = self.index_from_container(&next);
963
964 if index != -1 {
965 self.update_selection(index, true, range_modifier, false, false, false);
966 next.focus();
967 return true;
968 }
969 }
970
971 false
972 }
973
974 pub fn update_selection(
983 &self,
984 index: i32,
985 select: bool,
986 range_modifier: bool,
987 toggle_modifier: bool,
988 right_button: bool,
989 from_focus: bool,
990 ) {
991 if index < 0 || index >= self.item_count() {
992 return;
993 }
994
995 let mode = self.selection_mode();
996 let multi = mode.contains(SelectionMode::MULTIPLE);
997 let toggle = toggle_modifier || mode.contains(SelectionMode::TOGGLE);
998 let range = multi && range_modifier;
999 let selection = self.selection();
1000
1001 if !select {
1002 selection.deselect(index);
1003 } else if right_button {
1004 if !selection.is_selected(index) {
1005 self.set_selected_index(index);
1006 }
1007 } else if range {
1008 let operation = SelectionModelExtensions::batch_update(&selection);
1009 if !toggle_modifier {
1010 selection.clear();
1011 }
1012 selection.select_range(selection.anchor_index(), index);
1013 operation.dispose();
1014 } else if !from_focus && toggle {
1015 if multi {
1016 if selection.is_selected(index) {
1017 selection.deselect(index);
1018 } else {
1019 selection.select(index);
1020 }
1021 } else {
1022 self.set_selected_index(if self.selected_index() == index { -1 } else { index });
1023 }
1024 } else if !toggle {
1025 let operation = SelectionModelExtensions::batch_update(&selection);
1026 selection.clear();
1027 selection.select(index);
1028 operation.dispose();
1029 }
1030 }
1031
1032 #[deprecated(note = "Call update_selection_from_event instead.")]
1034 pub fn update_selection_for_container(
1035 &self,
1036 container: &Ref<Control>,
1037 select: bool,
1038 range_modifier: bool,
1039 toggle_modifier: bool,
1040 right_button: bool,
1041 from_focus: bool,
1042 ) {
1043 let index = self.index_from_container(container);
1044
1045 if index != -1 {
1046 self.update_selection(index, select, range_modifier, toggle_modifier, right_button, from_focus);
1047 }
1048 }
1049
1050 #[deprecated(note = "Call update_selection_from_event instead.")]
1056 pub fn update_selection_from_event_source(
1057 &self,
1058 event_source: Option<&Ref<Visual>>,
1059 select: bool,
1060 range_modifier: bool,
1061 toggle_modifier: bool,
1062 right_button: bool,
1063 from_focus: bool,
1064 ) -> bool {
1065 let Some(container) = self.get_container_from_event_source(event_source) else { return false };
1066
1067 #[allow(deprecated)]
1068 self.update_selection_for_container(
1069 &container,
1070 select,
1071 range_modifier,
1072 toggle_modifier,
1073 right_button,
1074 from_focus,
1075 );
1076 true
1077 }
1078
1079 fn get_or_create_selection_model(&self) -> Rc<dyn ISelectionModel> {
1080 let existing = self.selection.borrow().clone();
1081 if let Some(existing) = existing {
1082 return existing;
1083 }
1084
1085 let selection = self.create_default_selection_model();
1086 *self.selection.borrow_mut() = Some(selection.clone());
1087 self.initialize_selection_model(&selection);
1088
1089 let current = self.selection.borrow().clone();
1092 current.unwrap_or(selection)
1093 }
1094
1095 fn on_items_view_source_changed(&self) {
1096 if self.update_state.borrow().is_none() {
1097 let selection = self.selection.borrow().clone();
1098 self.try_initialize_selection_source(selection.as_ref(), true);
1099 }
1100 }
1101
1102 fn on_selection_model_property_changed(&self, property_name: &str) {
1104 match property_name {
1105 "AnchorIndex" => {
1106 self.has_scrolled_to_selected_item.set(false);
1107
1108 let anchor_index = self.get_anchor_index();
1109 KeyboardNavigation::set_tab_once_active_element(
1110 self,
1111 self.container_from_index(anchor_index).map(Ref::upcast),
1112 );
1113 self.auto_scroll_to_selected_item_if_necessary(anchor_index);
1114 }
1115 "SelectedIndex" => {
1116 let selected_index = self.selected_index();
1117 let old_selected_index = self.old_selected_index.get();
1118 if old_selected_index != selected_index {
1119 self.raise_direct_property_changed(
1120 Self::selected_index_property(),
1121 &old_selected_index,
1122 &selected_index,
1123 );
1124 self.old_selected_index.set(selected_index);
1125 }
1126 }
1127 "SelectedItem" => {
1128 let selected_item = self.selected_item();
1129 let old_selected_item = self.old_selected_item.borrow().clone();
1130 if !items_equal(&selected_item, &old_selected_item) {
1131 self.raise_direct_property_changed(
1132 Self::selected_item_property(),
1133 &old_selected_item,
1134 &selected_item,
1135 );
1136 *self.old_selected_item.borrow_mut() = selected_item;
1137 }
1138 }
1139 "WritableSelectedItems" => {
1140 let old_selected_items = self.old_selected_items.borrow().clone();
1141 let is_internal = self.selection().as_internal_selection_model().is_some();
1146 if is_internal || old_selected_items.is_some() {
1147 let selected_items = self.selected_items();
1148 self.raise_direct_property_changed(
1149 Self::selected_items_property(),
1150 &old_selected_items,
1151 &selected_items,
1152 );
1153 *self.old_selected_items.borrow_mut() = selected_items;
1154 }
1155 }
1156 "Source" => self.clear_value(Self::selected_value_property()),
1157 _ => {}
1158 }
1159 }
1160
1161 fn on_selection_model_selection_changed(&self, e: &dyn SelectionModelSelectionChangedEventArgs) {
1164 let mark = |index: i32, selected: bool| {
1165 if let Some(container) = self.container_from_index(index) {
1166 self.mark_container_selected(&container, selected);
1167 }
1168 };
1169
1170 let selected_indexes = e.selected_indexes();
1171 for i in 0..selected_indexes.count() {
1172 mark(selected_indexes.get(i), true);
1173 }
1174
1175 let deselected_indexes = e.deselected_indexes();
1176 for i in 0..deselected_indexes.count() {
1177 mark(deselected_indexes.get(i), false);
1178 }
1179
1180 if !self.is_selection_change_active.get() {
1181 self.update_selected_value_from_item();
1182 }
1183
1184 {
1185 let selected_items = self.selection().selected_items();
1186 let mut snapshot = self.selected_items_snapshot.borrow_mut();
1187 snapshot.clear();
1188 snapshot.extend(selected_items.iter());
1189 }
1190 *self.selected_items_before_reset.borrow_mut() = None;
1191
1192 self.raise_selection_changed(
1193 || e.deselected_items().to_vec(),
1194 || e.selected_items().to_vec(),
1195 );
1196
1197 self.verify_selected_index();
1198 }
1199
1200 fn on_selection_model_lost_selection(&self) {
1203 let before_reset = self.selected_items_before_reset.take();
1204 if let Some(before_reset) = before_reset.filter(|items| !items.is_empty()) {
1205 let reported = std::mem::take(&mut *self.selected_items_snapshot.borrow_mut());
1212 drop(reported);
1213 self.update_selected_value_from_item();
1214
1215 self.raise_selection_changed(|| before_reset, Vec::new);
1216 }
1217
1218 if self.always_selected() && self.items_view().count() > 0 {
1219 self.set_selected_index(self.choose_first_visible_and_enabled_index());
1220 }
1221 }
1222
1223 fn raise_selection_changed(
1224 &self,
1225 removed_items: impl FnOnce() -> Vec<Option<BoxedValue>>,
1226 added_items: impl FnOnce() -> Vec<Option<BoxedValue>>,
1227 ) {
1228 let route = self.build_event_route(Self::selection_changed_event());
1229
1230 if route.has_handlers() {
1231 self.raise_event(&SelectionChangedEventArgs::new(
1232 Some(Self::selection_changed_event()),
1233 removed_items(),
1234 added_items(),
1235 ));
1236 }
1237 }
1238
1239 fn select_item_with_value(&self, value: &Option<BoxedValue>) {
1240 if self.item_count() == 0 || self.is_selection_change_active.get() {
1241 return;
1242 }
1243
1244 self.is_selection_change_active.set(true);
1245 let _reset = Reset(&self.is_selection_change_active);
1246
1247 match self.find_item_with_value(value) {
1248 Some(si) => self.set_selected_item(si),
1249 None => self.set_selected_item(None),
1250 }
1251 }
1252
1253 fn find_item_with_value(&self, value: &Option<BoxedValue>) -> Option<Option<BoxedValue>> {
1256 if self.item_count() == 0 || value.is_none() {
1257 return None;
1258 }
1259
1260 let items = self.items_view().clone();
1261
1262 let Some(binding) = self.selected_value_binding() else {
1263 let index = items.index_of(value);
1267
1268 return if index >= 0 { Some(value.clone()) } else { None };
1269 };
1270
1271 let binding_evaluator = self.get_selected_value_binding_evaluator(&binding);
1272
1273 for item in items.iter() {
1276 let item_value = binding_evaluator.evaluate(&item);
1277
1278 if items_equal(&item_value, value) {
1279 binding_evaluator.clear_data_context();
1280 return Some(item);
1281 }
1282 }
1283
1284 binding_evaluator.clear_data_context();
1285
1286 None
1287 }
1288
1289 fn update_selected_value_from_item(&self) {
1290 if self.is_selection_change_active.get() {
1291 return;
1292 }
1293
1294 let binding = self.selected_value_binding();
1295 let item = self.selected_item();
1296
1297 self.is_selection_change_active.set(true);
1298 let _reset = Reset(&self.is_selection_change_active);
1299
1300 match binding {
1301 Some(binding) if item.is_some() => {
1302 let binding_evaluator = self.get_selected_value_binding_evaluator(&binding);
1303 self.set_current_value(Self::selected_value_property(), binding_evaluator.evaluate(&item));
1304 }
1305 _ => {
1306 self.set_current_value(Self::selected_value_property(), item);
1309 }
1310 }
1311 }
1312
1313 fn auto_scroll_to_selected_item_if_necessary(&self, anchor_index: i32) {
1314 if self.auto_scroll_to_selected_item()
1315 && self.presenter().is_some()
1316 && anchor_index >= 0
1317 && self.is_attached_to_visual_tree()
1318 {
1319 if !self.has_scrolled_to_selected_item.get() {
1320 self.scroll_into_view(anchor_index);
1321 self.auto_scroll_requested_index.set(anchor_index);
1322 self.has_scrolled_to_selected_item.set(true);
1323 }
1324 } else if self.auto_scroll_requested_index.get() >= 0 {
1325 if let Some(presenter) = self.presenter() {
1328 presenter.cancel_scroll_into_view(self.auto_scroll_requested_index.get());
1329 }
1330 self.auto_scroll_requested_index.set(-1);
1331 }
1332 }
1333
1334 fn container_selection_changed(&self, e: &RoutedEventArgs) {
1336 if !self.ignore_container_selection_changed.get() {
1337 let this: Ref<ferroui_base::StyledElement> = self.to_ref().upcast();
1338 let control = e.source().and_then(|source| source.cast::<Control>());
1339 if let Some(control) = control.filter(|control| control.parent().as_ref() == Some(&this)) {
1340 let index = self.index_from_container(&control);
1341 if index >= 0 {
1342 if Self::get_is_selected(&control) {
1343 self.selection().select(index);
1344 } else {
1345 self.selection().deselect(index);
1346 }
1347 }
1348 }
1349 }
1350
1351 if !e.is_source(self) {
1352 e.set_handled(true);
1353 }
1354 }
1355
1356 fn mark_container_selected(&self, container: &Control, selected: bool) {
1358 self.ignore_container_selection_changed.set(true);
1359 let _reset = Reset(&self.ignore_container_selection_changed);
1360
1361 container.set_current_value(Self::is_selected_property(), selected);
1362 }
1363
1364 fn get_first_visible_and_enabled_index(&self) -> (i32, bool) {
1370 let count = self.item_count();
1371 if count == 0 {
1372 return (-1, true);
1373 }
1374
1375 for i in 0..count {
1376 if let Some(container) = self.container_from_index(i) {
1377 if container.is_visible() && container.is_enabled() {
1378 return (i, true);
1379 }
1380
1381 continue;
1382 }
1383
1384 let item = self.items_view().get_at(i as usize);
1385 let Some(item) = item else { continue };
1386
1387 let value: &dyn AnyValue = &*item;
1388 let visual = match value.downcast_ref::<Ref<Control>>() {
1390 Some(c) => Some(c.clone().upcast::<Visual>()),
1391 None => match value.downcast_ref::<Ref<Visual>>() {
1392 Some(v) => Some(v.clone()),
1393 None => ferroui_base::data::core::ValueTypes::as_object(value).and_then(|o| o.cast::<Visual>()),
1394 },
1395 };
1396 if let Some(v) = visual {
1397 if v.is_visible() && v.downcast_ref::<Control>().is_none_or(|c| c.is_enabled()) {
1398 return (i, true);
1399 }
1400 } else {
1401 return (i, false);
1404 }
1405 }
1406
1407 (-1, true)
1408 }
1409
1410 fn choose_first_visible_and_enabled_index(&self) -> i32 {
1411 let (index, verified) = self.get_first_visible_and_enabled_index();
1412 self.unverified_selected_index.set(if verified { -1 } else { index });
1413 index
1414 }
1415
1416 fn verify_selected_index(&self) {
1417 if self.unverified_selected_index.get() == -1 {
1418 return;
1419 }
1420
1421 if !self.always_selected() {
1422 self.unverified_selected_index.set(-1);
1423 return;
1424 }
1425
1426 if self.unverified_selected_index.get() != self.selected_index() {
1428 self.unverified_selected_index.set(-1);
1429 return;
1430 }
1431
1432 let Some(container) = self.container_from_index(self.unverified_selected_index.get()) else { return };
1435
1436 self.unverified_selected_index.set(-1);
1437
1438 if !container.is_visible() || !container.is_enabled() {
1439 self.move_selection_to_first_visible_and_enabled_item();
1440 }
1441 }
1442
1443 fn move_selection_to_first_visible_and_enabled_item(&self) {
1444 let index = self.get_first_realized_visible_and_enabled_index();
1445 if index != self.selected_index() {
1446 self.set_selected_index(index);
1447 }
1448 }
1449
1450 fn get_first_realized_visible_and_enabled_index(&self) -> i32 {
1451 let count = self.item_count();
1452 for i in 0..count {
1453 if let Some(container) = self.container_from_index(i) {
1454 if container.is_visible() && container.is_enabled() {
1455 return i;
1456 }
1457 }
1458 }
1459 -1
1460 }
1461
1462 fn update_container_selection(&self) {
1464 if let Some(panel) = self.presenter().and_then(|presenter| presenter.panel()) {
1465 let selection = self.selection();
1466 for container in panel.children().snapshot().iter() {
1467 self.mark_container_selected(container, selection.is_selected(self.index_from_container(&container.clone())));
1468 }
1469 }
1470 }
1471
1472 fn create_default_selection_model(&self) -> Rc<dyn ISelectionModel> {
1473 let model = InternalSelectionModel::new();
1474 model.set_single_select(!self.selection_mode().contains(SelectionMode::MULTIPLE));
1475 model
1476 }
1477
1478 fn initialize_selection_model(&self, model: &Rc<dyn ISelectionModel>) {
1479 if self.update_state.borrow().is_none() {
1480 self.try_initialize_selection_source(Some(model), false);
1481 }
1482
1483 let weak = self.to_ref().downgrade();
1484 let token = model.property_changed().add(Rc::new(move |name: &str| {
1485 if let Some(this) = weak.upgrade() {
1486 this.on_selection_model_property_changed(name);
1487 }
1488 }));
1489 self.selection_property_changed_token.set(token);
1490
1491 let weak = self.to_ref().downgrade();
1492 let subscription = model.selection_changed(Rc::new(move |e: &dyn SelectionModelSelectionChangedEventArgs| {
1493 if let Some(this) = weak.upgrade() {
1494 this.on_selection_model_selection_changed(e);
1495 }
1496 }));
1497 *self.selection_changed_subscription.borrow_mut() = Some(subscription);
1498
1499 let weak = self.to_ref().downgrade();
1500 model.lost_selection(Rc::new(move || {
1501 if let Some(this) = weak.upgrade() {
1502 this.on_selection_model_lost_selection();
1503 }
1504 }));
1505
1506 if model.single_select() {
1507 self.set_selection_mode(self.selection_mode() & !SelectionMode::MULTIPLE);
1508 } else {
1509 self.set_selection_mode(self.selection_mode() | SelectionMode::MULTIPLE);
1510 }
1511
1512 self.old_selected_index.set(model.selected_index());
1513 *self.old_selected_item.borrow_mut() = model.selected_item();
1514 {
1515 let selected_items = model.selected_items();
1516 let mut snapshot = self.selected_items_snapshot.borrow_mut();
1517 snapshot.clear();
1518 snapshot.extend(selected_items.iter());
1519 }
1520
1521 if self.update_state.borrow().is_none() && self.always_selected() && model.count() == 0 {
1522 model.set_selected_index(self.choose_first_visible_and_enabled_index());
1523 }
1524
1525 self.update_container_selection();
1526
1527 if self.selected_index() != -1 {
1528 self.raise_event(&SelectionChangedEventArgs::new(
1529 Some(Self::selection_changed_event()),
1530 Vec::new(),
1531 self.selection().selected_items().to_vec(),
1532 ));
1533 }
1534 }
1535
1536 fn try_initialize_selection_source(
1537 &self,
1538 selection: Option<&Rc<dyn ISelectionModel>>,
1539 should_select_item_from_selected_value: bool,
1540 ) {
1541 let Some(selection) = selection else { return };
1542 let Some(source) = self.items_view().try_get_initialized_source() else { return };
1543
1544 if should_select_item_from_selected_value
1560 && selection.selected_index() == -1
1561 && selection.selected_item().is_none()
1562 {
1563 if let Some(item) = self.find_item_with_value(&self.selected_value()) {
1564 selection.set_selected_item(item);
1565 }
1566 }
1567
1568 selection.set_source(Some(source));
1569 }
1570
1571 fn deinitialize_selection_model(&self, model: Option<&Rc<dyn ISelectionModel>>) {
1572 if let Some(model) = model {
1573 model.property_changed().remove(self.selection_property_changed_token.get());
1574 if let Some(subscription) = self.selection_changed_subscription.take() {
1575 subscription.dispose();
1576 }
1577 }
1578 }
1579
1580 fn begin_updating(&self) {
1581 let mut state = self.update_state.borrow_mut();
1582 let state = state.get_or_insert_with(UpdateState::default);
1583 state.update_count += 1;
1584 }
1585
1586 fn end_updating(&self) {
1587 let finished = {
1588 let mut state = self.update_state.borrow_mut();
1589 match state.as_mut() {
1590 Some(update_state) => {
1591 update_state.update_count -= 1;
1592 update_state.update_count == 0
1593 }
1594 None => false,
1595 }
1596 };
1597
1598 if !finished {
1599 return;
1600 }
1601
1602 let Some(mut state) = self.update_state.take() else { return };
1603
1604 if let Some(selection) = state.selection.take() {
1605 self.set_selection(Some(selection));
1606 }
1607
1608 let current = self.selection.borrow().clone();
1609 if let Some(s) = current.as_ref().and_then(|selection| selection.as_internal_selection_model()) {
1610 s.update(
1611 self.items_view().try_get_initialized_source(),
1612 state.selected_items.clone().map(|items| items.map(|items| items.0)),
1613 );
1614 } else {
1615 if let Some(selected_items) = state.selected_items.clone() {
1616 self.set_selected_items(selected_items);
1617 }
1618
1619 self.try_initialize_selection_source(Some(&self.selection()), false);
1620 }
1621
1622 if let Some(selected_value) = &state.selected_value {
1623 if let Some(item) = self.find_item_with_value(selected_value) {
1624 state.selected_item = Some(item);
1625 }
1626 }
1627
1628 if let Some(selected_index) = state.selected_index {
1634 match state.selected_item.clone() {
1635 Some(selected_item) if selected_index < 0 => self.set_selected_item(selected_item),
1636 _ => self.set_selected_index(selected_index),
1637 }
1638 } else if let Some(selected_item) = state.selected_item.clone() {
1639 self.set_selected_item(selected_item);
1640 }
1641
1642 if self.always_selected() && self.selected_index() == -1 && self.item_count() > 0 {
1643 self.set_selected_index(self.choose_first_visible_and_enabled_index());
1644 }
1645 }
1646
1647 fn start_text_search_timer(&self) {
1648 let timer = DispatcherTimer::new();
1649 timer.set_interval(Duration::from_secs(1));
1650 let weak = self.to_ref().downgrade();
1651 let tick = timer.tick(move |_| {
1652 if let Some(this) = weak.upgrade() {
1653 this.text_search_timer_tick();
1654 }
1655 });
1656 timer.start();
1657 *self.text_search_timer.borrow_mut() = Some((timer, tick));
1658 }
1659
1660 fn stop_text_search_timer(&self) {
1661 let Some((timer, tick)) = self.text_search_timer.take() else { return };
1662
1663 tick.dispose();
1664 timer.stop();
1665 }
1666
1667 fn text_search_timer_tick(&self) {
1668 self.text_search_term.borrow_mut().clear();
1669 self.stop_text_search_timer();
1670 }
1671
1672 fn get_index_from_text_search(&self, text_search_term: &str) -> i32 {
1673 if text_search_term.is_empty() {
1674 return -1;
1675 }
1676
1677 let count = self.items().count();
1678 if count == 0 {
1679 return -1;
1680 }
1681
1682 let text_binding = TextSearch::get_text_binding(self).or_else(|| self.display_member_binding());
1683 let text_binding_evaluator = BindingEvaluator::try_create(text_binding.as_ref());
1684
1685 let mut result = -1;
1686
1687 for i in 0..count {
1688 let text = TextSearch::get_effective_text(&self.items().get_at(i), text_binding_evaluator.as_ref());
1689 if starts_with_ordinal_ignore_case(&text, text_search_term) {
1690 result = i as i32;
1691 break;
1692 }
1693 }
1694
1695 if let Some(evaluator) = text_binding_evaluator {
1696 evaluator.dispose();
1697 }
1698
1699 result
1700 }
1701
1702 fn get_selected_value_binding_evaluator(&self, binding: &AssignedBinding) -> Ref<BindingEvaluator> {
1703 let existing = self.selected_value_binding_evaluator.borrow().clone();
1704 let evaluator = match existing {
1705 Some(evaluator) => evaluator,
1706 None => {
1707 let evaluator = BindingEvaluator::new();
1708 *self.selected_value_binding_evaluator.borrow_mut() = Some(evaluator.clone());
1709 evaluator
1710 }
1711 };
1712 evaluator.update_binding(binding);
1713 evaluator
1714 }
1715}
1716
1717fn starts_with_ordinal_ignore_case(text: &str, prefix: &str) -> bool {
1720 let mut text = text.chars().flat_map(char::to_uppercase);
1721 for expected in prefix.chars().flat_map(char::to_uppercase) {
1722 if text.next() != Some(expected) {
1723 return false;
1724 }
1725 }
1726 true
1727}