27 template <
typename Base>
30 service<i_scrollbar_container_updater>().unqueue(*
this);
33 template <
typename Base>
36 return iScrollbarStyle;
39 template <
typename Base>
45 template <
typename Base>
52 template <
typename Base>
55 base_type::layout_items_started();
58 template <
typename Base>
61 base_type::layout_items_completed();
62 if (!base_type::as_widget().layout_items_in_progress() && !iIgnoreScrollbarUpdates && !iMovingWidgets)
66 update_scrollbar_visibility();
70 template <
typename Base>
74 if (!base_type::as_widget().layout_items_in_progress() && !iIgnoreScrollbarUpdates)
78 update_scrollbar_visibility();
82 template <
typename Base>
85 rect result = base_type::client_rect(aExtendIntoPadding);
86 if (vertical_scrollbar().visible())
89 result.
cx -= vertical_scrollbar().width();
92 result.
y += vertical_scrollbar().width();
93 result.
cy -= vertical_scrollbar().width() * 2.0;
96 result.
cy -= vertical_scrollbar().width() * 2.0;
98 if (horizontal_scrollbar().visible())
101 result.
cy -= horizontal_scrollbar().width();
104 result.
x += horizontal_scrollbar().width();
105 result.
cx -= horizontal_scrollbar().width() * 2.0;
108 result.
cx -= horizontal_scrollbar().width() * 2.0;
113 template <
typename Base>
116 if (vertical_scrollbar().visible() &&
120 else if (horizontal_scrollbar().visible() &&
125 return base_type::part(aPosition);
128 template <
typename Base>
131 base_type::paint_non_client_after(aGc);
132 if (vertical_scrollbar().visible() && !vertical_scrollbar().auto_hidden())
133 vertical_scrollbar().render(aGc);
134 if (horizontal_scrollbar().visible() && !horizontal_scrollbar().auto_hidden())
135 horizontal_scrollbar().render(aGc);
136 if (vertical_scrollbar().visible() && horizontal_scrollbar().visible() &&
137 !vertical_scrollbar().auto_hidden() && !horizontal_scrollbar().auto_hidden() &&
138 vertical_scrollbar().type() == horizontal_scrollbar().type() && vertical_scrollbar().type() ==
scrollbar_style::Normal)
141 point{ scrollbar_geometry(horizontal_scrollbar()).right(), scrollbar_geometry(vertical_scrollbar()).bottom() },
142 size{ scrollbar_geometry(vertical_scrollbar()).width(), scrollbar_geometry(horizontal_scrollbar()).height() } };
143 aGc.
fill_rect(spareSquare, scrollbar_color(vertical_scrollbar()));
147 template <
typename Base>
152 bool handledVertical =
false;
153 bool handledHorizontal =
false;
158 auto const maxSteps = 6.0;
159 auto const maxDeltaY = std::max(vertical_scrollbar().page() - vertical_scrollbar().step(), vertical_scrollbar().step());
160 auto const maxDeltaX = std::max(horizontal_scrollbar().page() - horizontal_scrollbar().step(), horizontal_scrollbar().step());
162 handledVertical = vertical_scrollbar().set_position(
163 vertical_scrollbar().position() +
164 std::min(std::max(((verticalSense ==
mouse_wheel::Vertical ? aDelta.
dy : aDelta.dx) >= 0.0 ? -maxSteps : maxSteps) * vertical_scrollbar().step(), -maxDeltaY), maxDeltaY));
165 if ((aWheel & horizontalSense) !=
mouse_wheel::None && horizontal_scrollbar().visible())
166 handledHorizontal = horizontal_scrollbar().set_position(
167 horizontal_scrollbar().position() +
168 std::min(std::max(((horizontalSense ==
mouse_wheel::Horizontal ? aDelta.
dx : aDelta.dx) >= 0.0 ? -maxSteps : maxSteps) * horizontal_scrollbar().step(), -maxDeltaX), maxDeltaX));
170 aWheel & ((handledVertical ? ~verticalSense : verticalSense) | (handledHorizontal ? ~horizontalSense : horizontalSense)));
172 return base_type::mouse_wheel_scrolled(passOn, aPosition, aDelta, aKeyModifiers);
177 template <
typename Base>
182 bool handled =
false;
183 if (vertical_scrollbar().visible())
185 vertical_scrollbar().track();
188 if (horizontal_scrollbar().visible())
190 horizontal_scrollbar().track();
194 base_type::as_widget().set_capture();
196 base_type::mouse_button_pressed(aButton, aPosition, aKeyModifiers);
200 base_type::mouse_button_pressed(aButton, aPosition, aKeyModifiers);
207 base_type::as_widget().update(
true);
208 vertical_scrollbar().click_element(vertical_scrollbar().element_at(aPosition));
210 else if (horizontal_scrollbar().visible() && horizontal_scrollbar().element_at(aPosition) !=
scrollbar_element::None)
212 base_type::as_widget().update(
true);
213 horizontal_scrollbar().click_element(horizontal_scrollbar().element_at(aPosition));
220 template <
typename Base>
223 base_type::mouse_button_double_clicked(aButton, aPosition, aKeyModifiers);
230 base_type::as_widget().update(
true);
231 vertical_scrollbar().click_element(vertical_scrollbar().element_at(aPosition));
233 else if (horizontal_scrollbar().visible() && horizontal_scrollbar().element_at(aPosition) !=
scrollbar_element::None)
235 base_type::as_widget().update(
true);
236 horizontal_scrollbar().click_element(horizontal_scrollbar().element_at(aPosition));
242 template <
typename Base>
245 base_type::mouse_button_released(aButton, aPosition);
250 base_type::as_widget().update(
true);
251 vertical_scrollbar().unclick_element();
255 base_type::as_widget().update(
true);
256 horizontal_scrollbar().unclick_element();
261 vertical_scrollbar().untrack();
262 horizontal_scrollbar().untrack();
266 template <
typename Base>
269 base_type::mouse_moved(aPosition, aKeyModifiers);
270 vertical_scrollbar().update(aPosition);
271 horizontal_scrollbar().update(aPosition);
274 template <
typename Base>
277 base_type::mouse_entered(aPosition);
278 vertical_scrollbar().update();
279 horizontal_scrollbar().update();
282 template <
typename Base>
285 base_type::mouse_left();
286 vertical_scrollbar().update();
287 horizontal_scrollbar().update();
290 template <
typename Base>
297 horizontal_scrollbar().set_position(horizontal_scrollbar().position() - horizontal_scrollbar().step());
300 horizontal_scrollbar().set_position(horizontal_scrollbar().position() + horizontal_scrollbar().step());
303 vertical_scrollbar().set_position(vertical_scrollbar().position() - vertical_scrollbar().step());
306 vertical_scrollbar().set_position(vertical_scrollbar().position() + vertical_scrollbar().step());
309 vertical_scrollbar().set_position(vertical_scrollbar().position() - vertical_scrollbar().page());
312 vertical_scrollbar().set_position(vertical_scrollbar().position() + vertical_scrollbar().page());
315 if (horizontal_scrollbar().visible() && !(aKeyModifiers &
KeyModifier_CTRL))
316 horizontal_scrollbar().set_position(horizontal_scrollbar().minimum());
318 vertical_scrollbar().set_position(vertical_scrollbar().minimum());
321 if (horizontal_scrollbar().visible() && !(aKeyModifiers &
KeyModifier_CTRL))
322 horizontal_scrollbar().set_position(horizontal_scrollbar().maximum());
324 vertical_scrollbar().set_position(vertical_scrollbar().maximum());
327 handled = base_type::key_pressed(aScanCode, aKeyCode, aKeyModifiers);
333 template <
typename Base>
336 return iVerticalScrollbar;
339 template <
typename Base>
342 return iVerticalScrollbar;
345 template <
typename Base>
348 return iHorizontalScrollbar;
351 template <
typename Base>
354 return iHorizontalScrollbar;
357 template <
typename Base>
360 if (base_type::device_metrics_available())
362 vertical_scrollbar().
set_step(std::ceil(1.0_cm));
363 horizontal_scrollbar().set_step(std::ceil(1.0_cm));
367 template <
typename Base>
370 auto async_update = [&]()
372 if (!iScrollbarUpdater && !iSuppressScrollbarVisibilityUpdates)
375 update_scrollbar_visibility();
376 }, std::chrono::seconds{});
378 iSink += base_type::ChildAdded([&, async_update](i_widget& aWidget)
382 iSink += base_type::ChildRemoved([&, async_update](i_widget& aWidget)
389 template <
typename Base>
395 template <
typename Base>
401 template <
typename Base>
406 auto const cr = client_rect();
410 if (iUpdatingScrollbarVisibility)
412 auto& self = base_type::as_widget();
417 for (
auto& c : self.children())
419 if (c->hidden() || c->extents().cx == 0.0 || c->extents().cy == 0.0)
422 min.
emplace(std::numeric_limits<scalar>::infinity(), std::numeric_limits<scalar>::infinity());
424 max.
emplace(-std::numeric_limits<scalar>::infinity(), -std::numeric_limits<scalar>::infinity());
429 min->x = std::min(min->x, childTopLeftPos.x);
430 max->x = std::max(max->x, childBottomRightPos.x);
434 min->y = std::min(min->y, childTopLeftPos.y);
435 max->y = std::max(max->y, childBottomRightPos.y);
444 if (self.has_layout())
446 auto const& ourLayout = self.layout();
448 max->x += ourLayout.internal_spacing().right;
450 max->y += ourLayout.internal_spacing().bottom;
453 if (max->x > cr.right() - 1.0 - self.internal_spacing().right)
454 max->x += self.internal_spacing().right;
455 if (max->y > cr.bottom() - 1.0 - self.internal_spacing().bottom)
456 max->y += self.internal_spacing().bottom;
458 min = min->min(cr.top_left());
459 max = max->max(cr.bottom_right()) -
point{ 1.0, 1.0 };
461 result =
rect{ *min, *max };
465 if (horizontal_scrollbar().visible())
467 result.
x = horizontal_scrollbar().minimum();
468 result.
cx = horizontal_scrollbar().maximum() - result.
x;
470 if (vertical_scrollbar().visible())
472 result.
y = vertical_scrollbar().minimum();
473 result.
cy = vertical_scrollbar().maximum() - result.
y;
477 return to_units(*
this, su.saved_units(), result);
479 template <
typename Base>
482 return client_rect().extents();
485 template <
typename Base>
488 auto const sbrect = client_rect();
512 template <
typename Base>
515 if (!iIgnoreScrollbarUpdates)
517 point scrollPosition = scroll_position();
518 if (iOldScrollPosition != scrollPosition)
521 for (
auto& c : base_type::as_widget().children())
523 point delta = -(scrollPosition - iOldScrollPosition);
528 c->move(c->position() +
delta);
532 iOldScrollPosition.y = scrollPosition.
y;
536 iOldScrollPosition.x = scrollPosition.
x;
540 base_type::as_widget().update(
true);
543 template <
typename Base>
549 template <
typename Base>
555 template <
typename Base>
561 template <
typename Base>
567 template <
typename Base>
570 if (!base_type::device_metrics_available())
573 if (iUpdatingScrollbarVisibility)
577 if (debug::layoutItem ==
this)
585 if (use_scrollbar_container_updater())
587 auto& updater = service<i_scrollbar_container_updater>();
588 if (!updater.processing())
591 update_scrollbar_visibility(UsvStageInit);
592 updater.queue(*
this);
595 else if (&updater.current() !=
this)
601 iScrollbarUpdater = {};
603 vertical_scrollbar().lock(0.0);
605 horizontal_scrollbar().lock(0.0);
608 update_scrollbar_visibility(UsvStageInit);
609 auto const& cr = base_type::as_widget().client_rect();
610 if (cr.cx > vertical_scrollbar().width() &&
611 cr.cy > horizontal_scrollbar().width())
613 update_scrollbar_visibility(UsvStageCheckVertical1);
614 update_scrollbar_visibility(UsvStageCheckHorizontal);
615 update_scrollbar_visibility(UsvStageCheckVertical2);
617 update_scrollbar_visibility(UsvStageDone);
620 vertical_scrollbar().unlock();
622 horizontal_scrollbar().unlock();
628 if (debug::layoutItem ==
this)
630 auto const scrollArea = scroll_area();
631 auto const scrollPage = scroll_page();
632 service<debug::logger>() <<
neolib::logger::severity::Debug <<
"widget:layout_items: update_scrollbar_visibility: scroll_area: " << scrollArea <<
", scroll_page: " << scrollPage << endl;
637 template <
typename Base>
640 bool updatePage =
false;
645 if (vertical_scrollbar().visible())
647 vertical_scrollbar().hide();
650 if (horizontal_scrollbar().visible())
652 horizontal_scrollbar().hide();
656 case UsvStageCheckVertical1:
657 case UsvStageCheckVertical2:
658 if (scroll_area().cy > scroll_page().cy)
660 if (!vertical_scrollbar().visible())
662 vertical_scrollbar().show();
667 case UsvStageCheckHorizontal:
668 if (scroll_area().cx > scroll_page().cx)
670 if (!horizontal_scrollbar().visible())
672 horizontal_scrollbar().show();
683 vertical_scrollbar().set_minimum(sa.top());
684 vertical_scrollbar().set_maximum(sa.bottom());
685 vertical_scrollbar().set_page(sp.cy);
686 horizontal_scrollbar().set_minimum(sa.left());
687 horizontal_scrollbar().set_maximum(sa.right());
688 horizontal_scrollbar().set_page(sp.cx);
689 iOldScrollPosition = scroll_position();
697 scroll_page_updated();
702 template <
typename Base>
705 base_type::as_widget().layout_items();
point_type top_right() const
point_type bottom_left() const
void fill_rect(const rect &aRect, const brush &aFill) const
vector2 to_device_units(const vector2 &aValue) const
vector2 from_device_units(const vector2 &aValue) const
reference & emplace(Args &&... args)
T to_units(i_units_context const &aSourceUnitsContext, units aNewUnits, const T &aValue)
bool contains(item_selection const &aSelection, item_presentation_model_index aIndex)
basic_delta< coordinate > delta
default_geometry_value_type coordinate
basic_point< coordinate > point
@ ScrollChildWidgetHorizontally
@ ScrollChildWidgetVertically
basic_scoped_units< units > scoped_units
void swap(plf::hive< element_type, allocator_type > &a, plf::hive< element_type, allocator_type > &b) noexcept(std::allocator_traits< allocator_type >::propagate_on_container_swap::value||std::allocator_traits< allocator_type >::is_always_equal::value)