21#include <unordered_map>
36 template <
typename Interface>
40 iAddingChild{ false },
41 iLinkBefore{ nullptr },
42 iLinkAfter{ nullptr },
43 iParentLayout{ nullptr },
45 iLayoutPending{ false },
46 iLayoutInProgress{ 0 },
49 base_type::Position.Changed([
this](
const point&) {
moved(); });
50 base_type::Size.Changed([
this](
const size&) {
resized(); });
51 base_type::set_alive();
54 template <
typename Interface>
58 iAddingChild{ false },
59 iLinkBefore{ nullptr },
60 iLinkAfter{ nullptr },
61 iParentLayout{ nullptr },
63 iLayoutPending{ false },
64 iLayoutInProgress{ 0 },
67 base_type::Position.Changed([
this](
const point&) {
moved(); });
68 base_type::Size.Changed([
this](
const size&) {
resized(); });
70 base_type::set_alive();
73 template <
typename Interface>
77 iAddingChild{ false },
78 iLinkBefore{ nullptr },
79 iLinkAfter{ nullptr },
80 iParentLayout{ nullptr },
82 iLayoutPending{ false },
83 iLayoutInProgress{ 0 },
86 base_type::Position.Changed([
this](
const point&) { moved(); });
87 base_type::Size.Changed([
this](
const size&) { resized(); });
89 base_type::set_alive();
92 template <
typename Interface>
96 if (service<i_keyboard>().is_keyboard_grabbed_by(*
this))
97 service<i_keyboard>().ungrab_keyboard(*
this);
105 if (has_parent_layout())
106 parent_layout().remove(*
this);
109 template <
typename Interface>
114 self.update_layout();
120 static auto invalidate_window_canvas = [](
i_widget& self)
122 self.root().as_widget().update(
true);
125 static const std::unordered_map<std::type_index, std::function<void(
i_widget&)>> sActions =
127 { std::type_index{
typeid(property_category::hard_geometry) }, invalidate_layout },
128 { std::type_index{
typeid(property_category::soft_geometry) }, invalidate_window_canvas },
129 { std::type_index{
typeid(property_category::font) }, invalidate_layout },
130 { std::type_index{
typeid(property_category::color) }, invalidate_canvas },
131 { std::type_index{
typeid(property_category::other_appearance) }, invalidate_canvas },
132 { std::type_index{
typeid(property_category::other) }, ignore }
134 auto iterAction = sActions.find(std::type_index{ aProperty.
category() });
135 if (iterAction != sActions.end())
136 iterAction->second(*
this);
139 template <
typename Interface>
142 if (iDeviceMetrics == std::nullopt)
144 if (self_type::has_root() && self_type::root().has_native_window())
146 iDeviceMetrics = &self_type::surface();
147 DeviceMetricsUpdated.trigger(*
this);
150 return iDeviceMetrics != std::nullopt;
153 template <
typename Interface>
156 if (self_type::device_metrics_available())
157 return **iDeviceMetrics;
158 return service<i_surface_manager>().display().metrics();
161 template <
typename Interface>
167 template <
typename Interface>
170 if (iSingular != aSingular)
172 iSingular = aSingular;
180 template <
typename Interface>
183 if constexpr (std::is_base_of_v<i_window, Interface>)
184 return iRoot ==
this;
189 template <
typename Interface>
192 if (iRoot == std::nullopt)
200 return iRoot != std::nullopt;
203 template <
typename Interface>
206 if constexpr (std::is_base_of_v<i_window, Interface>)
210 if (self_type::has_root())
216 template <
typename Interface>
219 return const_cast<i_window&
>(to_const(*this).self_type::root());
222 template <
typename Interface>
228 template <
typename Interface>
234 template <
typename Interface>
237 return self_type::is_root() && self_type::root().is_surface();
240 template <
typename Interface>
243 return self_type::root().surface();
246 template <
typename Interface>
249 return self_type::root().surface();
252 template <
typename Interface>
255 return self_type::root().real_surface();
258 template <
typename Interface>
261 return self_type::root().real_surface();
264 template <
typename Interface>
267 return iParent !=
nullptr;
270 template <
typename Interface>
278 template <
typename Interface>
281 return const_cast<i_widget&
>(to_const(*this).parent());
284 template <
typename Interface>
287 if (iParent != &aParent)
289 if (!self_type::is_root() && aParent.
has_root())
290 self_type::set_root(aParent.
root());
291 if ((self_type::is_root() && !self_type::root().is_nested()) || aParent.
adding_child())
298 if (self_type::use_count())
306 template <
typename Interface>
309 auto& self = base_type::as_widget();
311 if (!self_type::is_root())
314 if (self.has_parent_layout())
315 self.update_layout();
319 template <
typename Interface>
325 template <
typename Interface>
331 template <
typename Interface>
334 if (aChild->has_parent() && &aChild->parent() ==
this)
337 i_widget* oldParent = aChild->has_parent() ? &aChild->parent() :
nullptr;
339 if (oldParent !=
nullptr)
340 oldParent->
remove(*child,
true);
341 iChildren.push_back(child);
342 child->set_parent(*
this);
343 child->set_singular(
false);
344 if (self_type::has_root())
345 self_type::root().widget_added(*child);
346 ChildAdded.trigger(*child);
350 template <
typename Interface>
353 auto existing = find(aChild,
false);
354 if (existing == iChildren.end())
356 destroyed_flag childDestroyed{ aChild };
358 iChildren.erase(existing);
362 keep->set_singular(
true);
367 if (self_type::has_root())
368 self_type::root().widget_removed(aChild);
371 ChildRemoved.trigger(*keep);
375 template <
typename Interface>
378 while (!iChildren.empty())
379 remove(*iChildren.back(),
true);
382 template <
typename Interface>
385 return !iChildren.empty();
388 template <
typename Interface>
394 template <
typename Interface>
400 return parent().
find(*
this);
405 return iChildren.back()->last();
408 template <
typename Interface>
414 return parent().
find(*
this);
419 return iChildren.back()->last();
422 template <
typename Interface>
425 for (
auto i = iChildren.begin(); i != iChildren.end(); ++i)
428 if (aThrowIfNotFound)
431 return iChildren.end();
434 template <
typename Interface>
437 for (
auto i = iChildren.begin(); i != iChildren.end(); ++i)
440 if (aThrowIfNotFound)
443 return iChildren.end();
446 template <
typename Interface>
449 auto existing = std::find_if(iChildren.begin(), iChildren.end(), [&](
auto&& c) { return &*c == &aChild; });
450 if (existing != iChildren.end())
453 iChildren.erase(existing);
454 iChildren.insert(iChildren.begin(), child);
458 template <
typename Interface>
461 auto existing = std::find_if(iChildren.begin(), iChildren.end(), [&](
auto&& c) { return &*c == &aChild; });
462 if (existing != iChildren.end())
465 iChildren.erase(existing);
466 iChildren.insert(iChildren.end(), child);
470 template <
typename Interface>
476 template <
typename Interface>
479 if (iLayer != aLayer)
486 template <
typename Interface>
489 if (iLinkBefore !=
nullptr)
493 auto me = parent().
find(*
this);
494 if (me != parent().children().begin())
495 return **(*(me - 1))->last();
499 else if (has_children())
505 template <
typename Interface>
508 return const_cast<i_widget&
>(to_const(*this).before());
511 template <
typename Interface>
514 if (iLinkAfter !=
nullptr)
517 return *iChildren.front();
520 auto me = parent().
find(*
this);
521 if (me + 1 != parent().children().end())
523 else if (parent().has_parent())
525 auto myParent = parent().parent().find(parent());
526 while ((*myParent)->has_parent() && (*myParent)->parent().has_parent() &&
527 myParent + 1 == (*myParent)->parent().children().end())
528 myParent = (*myParent)->parent().parent().find((*myParent)->parent());
529 if ((*myParent)->has_parent() && myParent + 1 != (*myParent)->parent().children().end())
530 return **(myParent + 1);
531 else if ((*(myParent))->has_parent())
532 return (*(myParent))->parent();
543 template <
typename Interface>
546 return const_cast<i_widget&
>(to_const(*this).after());
549 template <
typename Interface>
552 iLinkBefore = aPreviousWidget;
555 template <
typename Interface>
558 iLinkAfter = aNextWidget;
561 template <
typename Interface>
564 if (iLinkBefore !=
nullptr)
566 if (iLinkAfter !=
nullptr)
567 iLinkAfter->link_before(iLinkBefore);
568 iLinkBefore =
nullptr;
569 iLinkAfter =
nullptr;
572 template <
typename Interface>
575 return iLayout !=
nullptr;
578 template <
typename Interface>
584 template <
typename Interface>
587 if (iLayout == aLayout)
588 throw layout_already_set();
589 auto oldLayout = iLayout;
591 if (iLayout !=
nullptr)
593 if (has_parent_layout())
594 iLayout->set_parent_layout(&parent_layout());
595 iLayout->set_parent_widget(
this);
596 if (aMoveExistingItems)
598 if (oldLayout ==
nullptr)
600 for (
auto& child : iChildren)
601 if (child->has_parent_layout() && &child->parent_layout() ==
nullptr)
605 oldLayout->move_all_to(*iLayout);
610 template <
typename Interface>
618 template <
typename Interface>
626 template <
typename Interface>
629 return is_managing_layout();
632 template <
typename Interface>
638 template <
typename Interface>
641 return client_rect();
644 template <
typename Interface>
647 return iParentLayout !=
nullptr;
650 template <
typename Interface>
653 if (has_parent_layout())
654 return *iParentLayout;
658 template <
typename Interface>
661 return const_cast<i_layout&
>(to_const(*this).parent_layout());
664 template <
typename Interface>
667 if (has_layout() &&
layout().has_parent_layout() && &
layout().parent_layout() == iParentLayout)
669 iParentLayout = aParentLayout;
672 template <
typename Interface>
678 template <
typename Interface>
684 template <
typename Interface>
690 template <
typename Interface>
693 if (aParentWidget !=
nullptr)
694 set_parent(*aParentWidget);
695 else if (has_parent())
698 parent().remove(*
this,
true, keep);
704 template <
typename Interface>
707 return iLayoutReason;
710 template <
typename Interface>
713 auto& self = base_type::as_widget();
715 if (layout_items_in_progress())
721 if (debug::layoutItem ==
this)
729 iLayoutPending =
false;
730 service<i_async_layout>().validate(*
this);
733 layout_items_started();
736 size desiredSize = self.extents();
737 switch (size_policy().horizontal_constraint())
740 desiredSize.
cx = self.has_fixed_size() ? self.fixed_size().cx : minimum_size(self.extents()).cx;
743 desiredSize.
cx = minimum_size(self.extents()).cx;
746 desiredSize.
cx = maximum_size(self.extents()).cx;
751 switch (size_policy().vertical_constraint())
754 desiredSize.
cy = self.has_fixed_size() ? self.fixed_size().cy : minimum_size(self.extents()).cy;
757 desiredSize.
cy = minimum_size(self.extents()).cy;
760 desiredSize.
cy = maximum_size(self.extents()).cy;
767 auto const& cr = client_rect(
false);
768 layout().layout_items(cr.top_left(), cr.extents());
769 layout_items_completed();
772 else if (can_defer_layout())
777 if (debug::layoutItem ==
this)
780 iLayoutPending = service<i_async_layout>().defer_layout(*
this);
783 else if (self.has_layout_manager())
785 throw widget_cannot_defer_layout();
789 template <
typename Interface>
793 if (debug::layoutItem ==
this)
799 template <
typename Interface>
802 return iLayoutInProgress != 0;
805 template <
typename Interface>
809 if (debug::layoutItem ==
this)
812 if (--iLayoutInProgress == 0)
814 LayoutCompleted.trigger();
819 template <
typename Interface>
822 return LogicalCoordinateSystem != std::nullopt;
825 template <
typename Interface>
828 if (has_logical_coordinate_system())
829 return *LogicalCoordinateSystem;
833 template <
typename Interface>
836 LogicalCoordinateSystem = aLogicalCoordinateSystem;
839 template <
typename Interface>
842 auto& self = base_type::as_widget();
845 if (debug::layoutItem ==
this)
848 self.set_position(aPosition);
851 template <
typename Interface>
854 auto& self = base_type::as_widget();
856 if (!self_type::is_root() || self_type::root().is_nested())
861 for (
auto& child : iChildren)
862 child->parent_moved();
865 parent().layout_items_started();
866 parent().layout_items_completed();
870 if (self_type::is_root())
871 self_type::root().surface().move_surface(self.position());
872 PositionChanged.trigger();
875 template <
typename Interface>
878 auto& self = base_type::as_widget();
881 for (
auto& child : iChildren)
882 child->parent_moved();
883 ParentPositionChanged.trigger();
886 template <
typename Interface>
892 template <
typename Interface>
895 auto& self = base_type::as_widget();
900 if (debug::layoutItem ==
this)
907 self.set_extents(aSize);
911 template <
typename Interface>
914 auto& self = base_type::as_widget();
916 if (self_type::is_root())
917 self_type::root().surface().resize_surface(self.extents());
921 SizeChanged.trigger();
929 parent().layout_items_started();
930 parent().layout_items_completed();
935 template <
typename Interface>
938 auto& self = base_type::as_widget();
942 template <
typename Interface>
945 auto& self = base_type::as_widget();
946 auto const& internalSpacing = self.internal_spacing(!aExtendIntoPadding);
947 auto const& topLeft = internalSpacing.top_left();
948 auto const& extents = self.extents();
949 auto const& adjustedExtents = (extents - internalSpacing.size()).max(
size{});
950 rect const result{ topLeft, adjustedExtents };
954 template <
typename Interface>
959 if (client_rect().
contains(aPosition))
961 i_widget const* hitWidget =
nullptr;
962 for (
auto const& child : children())
963 if (child->visible() && to_client_coordinates(child->non_client_rect()).contains(aPosition))
965 if (hitWidget ==
nullptr || child->
layer() > hitWidget->
layer())
969 return hitWidget->
get_widget_at(aPosition - hitWidget->position());
974 template <
typename Interface>
977 return const_cast<i_widget&
>(to_const(*this).get_widget_at(aPosition));
980 template <
typename Interface>
986 template <
typename Interface>
992 template <
typename Interface>
995 if (client_rect().
contains(aPosition))
997 else if (to_client_coordinates(non_client_rect()).
contains(aPosition))
1003 template <
typename Interface>
1006 return part(aPosition);
1009 template <
typename Interface>
1012 auto& self = base_type::as_widget();
1015 if (debug::layoutItem ==
this)
1018 if (self.has_size_policy())
1019 return base_type::size_policy();
1020 else if (self.has_fixed_size())
1026 template <
typename Interface>
1029 auto& self = base_type::as_widget();
1032 if (debug::layoutItem ==
this)
1037 result = base_type::ideal_size(aAvailableSpace);
1038 else if (self.has_minimum_size() || (base_type::Anchor_MinimumSize.active() && !base_type::Anchor_MinimumSize.calculating()))
1039 result = base_type::minimum_size(aAvailableSpace);
1040 else if (has_layout())
1042 auto const is = self.internal_spacing();
1043 result =
layout().
minimum_size(aAvailableSpace != std::nullopt ? *aAvailableSpace - is.size() : aAvailableSpace);
1044 if (result.
cx != 0.0)
1045 result.
cx += is.size().cx;
1046 if (result.
cy != 0.0)
1047 result.
cy += is.size().cy;
1050 result = self.internal_spacing().size();
1052 if (debug::layoutItem ==
this)
1053 service<debug::logger>() <<
neolib::logger::severity::Debug <<
typeid(*this).name() <<
"::minimum_size(" << aAvailableSpace <<
") --> " << result << endl;
1058 template <
typename Interface>
1061 auto& self = base_type::as_widget();
1064 if (debug::layoutItem ==
this)
1068 if (self.has_maximum_size() || (base_type::Anchor_MaximumSize.active() && !base_type::Anchor_MaximumSize.calculating()))
1069 result = base_type::maximum_size(aAvailableSpace);
1071 result = minimum_size(aAvailableSpace);
1072 else if (has_layout())
1074 auto const is = self.internal_spacing();
1075 result =
layout().
maximum_size(aAvailableSpace != std::nullopt ? *aAvailableSpace - is.size() : aAvailableSpace);
1076 if (result.
cx != 0.0)
1077 result.
cx += is.size().cx;
1078 if (result.
cy != 0.0)
1079 result.
cy += is.size().cy;
1088 if (debug::layoutItem ==
this)
1089 service<debug::logger>() <<
neolib::logger::severity::Debug <<
typeid(*this).name() <<
"::maximum_size(" << aAvailableSpace <<
") --> " << result << endl;
1094 template <
typename Interface>
1097 auto& self = base_type::as_widget();
1098 auto const& adjustedPadding = (self.has_padding() ?
1103 template <
typename Interface>
1106 auto& self = base_type::as_widget();
1109 if (debug::layoutItem ==
this)
1113 if (self.extents() != aSize)
1115 else if (has_layout() &&
layout().invalidated())
1122 template <
typename Interface>
1128 template <
typename Interface>
1134 template <
typename Interface>
1137 if (iRenderLayer != std::nullopt)
1138 return *iRenderLayer;
1142 template <
typename Interface>
1145 if (iRenderLayer != aLayer)
1147 iRenderLayer = aLayer;
1152 template <
typename Interface>
1155 return self_type::has_root() && self_type::root().has_native_surface() && !effectively_hidden() && !layout_items_in_progress();
1158 template <
typename Interface>
1163 return update(aIncludeNonClient ? to_client_coordinates(non_client_rect()) : client_rect());
1166 template <
typename Interface>
1170 if (debug::renderItem ==
this)
1175 if (aUpdateRect.
empty())
1177 surface().invalidate_surface(to_window_coordinates(aUpdateRect));
1181 template <
typename Interface>
1184 return surface().has_invalidated_area() && !surface().invalidated_area().intersection(non_client_rect()).empty();
1187 template <
typename Interface>
1190 if (!requires_update())
1191 throw no_update_rect();
1192 return to_client_coordinates(surface().invalidated_area().intersection(non_client_rect()));
1195 template <
typename Interface>
1198 auto& cachedRect = (aIncludeNonClient ? iDefaultClipRect.first : iDefaultClipRect.second);
1199 if (cachedRect != std::nullopt)
1201 rect clipRect = to_client_coordinates(non_client_rect());
1202 if (!aIncludeNonClient)
1204 if (!self_type::is_root())
1206 return *(cachedRect = clipRect);
1209 template <
typename Interface>
1212 return !iLayoutPending;
1215 template <
typename Interface>
1218 auto& self = base_type::as_widget();
1220 if (effectively_hidden())
1222 if (!requires_update())
1227 iDefaultClipRect = std::make_pair(std::nullopt, std::nullopt);
1229 const rect updateRect = update_rect();
1230 const rect nonClientClipRect = default_clip_rect(
true).
intersection(updateRect);
1233 if (debug::renderItem ==
this)
1234 service<debug::logger>() <<
neolib::logger::severity::Debug <<
typeid(*this).name() <<
"::render(...), updateRect: " << updateRect <<
", nonClientClipRect: " << nonClientClipRect << endl;
1243 scoped_opacity sc{ aGc, effectively_enabled() ? opacity() : opacity() * 0.75 };
1247 paint_non_client(aGc);
1249 for (
auto iterChild = iChildren.rbegin(); iterChild != iChildren.rend(); ++iterChild)
1251 auto const& childWidget = **iterChild;
1254 rect intersection = nonClientClipRect.
intersection(childWidget.non_client_rect() - self.origin());
1255 if (intersection.
empty() && !childWidget.is_root())
1257 childWidget.render(aGc);
1268 if (debug::renderItem ==
this)
1269 service<debug::logger>() <<
neolib::logger::severity::Debug <<
typeid(*this).name() <<
"::render(...): client_rect: " << client_rect() <<
", origin: " << self.origin() << endl;
1276 Painting.trigger(aGc);
1282 PaintingChildren.trigger(aGc);
1284 typedef std::map<int32_t, std::vector<i_widget const*>> widget_layers_t;
1289 if (widgetLayersStack.size() < stack)
1290 widgetLayersStack.push_back(std::make_unique<widget_layers_t>());
1292 widget_layers_t& widgetLayers = *widgetLayersStack[stack - 1];
1294 for (
auto& layer : widgetLayers)
1295 layer.second.clear();
1297 for (
auto iterChild = iChildren.rbegin(); iterChild != iChildren.rend(); ++iterChild)
1299 auto const& childWidget = **iterChild;
1302 rect intersection = clipRect.
intersection(to_client_coordinates(childWidget.non_client_rect()));
1303 if (intersection.
empty() && !childWidget.is_root())
1305 widgetLayers[childWidget.render_layer()].push_back(&childWidget);
1308 for (
auto const& layer : widgetLayers)
1310 for (
auto const& childWidgetPtr : layer.second)
1312 auto const& childWidget = *childWidgetPtr;
1313 childWidget.render(aGc);
1322 Painted.trigger(aGc);
1329 paint_non_client_after(aGc);
1333 template <
typename Interface>
1336 auto& self = base_type::as_widget();
1338 auto const& updateRect = update_rect();
1341 if (debug::renderItem ==
this)
1348 if (self.has_background_color() || !self.background_is_transparent())
1349 aGc.
fill_rect(updateRect, self.background_color().with_combined_alpha(has_background_opacity() ? background_opacity() : 1.0));
1352 template <
typename Interface>
1355 auto& self = base_type::as_widget();
1359 if (debug::renderItem ==
this || debug::layoutItem ==
this || (debug::layoutItem !=
nullptr && has_layout() && debug::layoutItem->is_layout() &&
1360 (debug::layoutItem == &
layout() ||
static_cast<i_layout const*
>(debug::layoutItem)->is_descendent_of(
layout()))))
1362 neogfx::font debugFont1 = service<i_app>().current_style().font().with_size(16);
1363 neogfx::font debugFont2 = service<i_app>().current_style().font().with_size(8);
1364 if (debug::renderGeometryText)
1366 if (debug::layoutItem ==
this)
1368 aGc.
draw_text(self.position(),
typeid(*this).name(), debugFont1, text_format{ color::Yellow.with_alpha(0.75), text_effect{ text_effect_type::Outline, color::Black.with_alpha(0.75), 2.0 } });
1369 std::ostringstream oss;
1370 oss <<
"sizepol: " << size_policy();
1371 oss <<
" minsize: " << minimum_size() <<
" maxsize: " << maximum_size();
1372 oss <<
" fixsize: " << (self.has_fixed_size() ? self.fixed_size() :
optional_size{}) <<
" weight: " << self.weight() <<
" extents: " << self.extents();
1376 rect const nonClientRect = to_client_coordinates(non_client_rect());
1381 if (nonClientRect != client_rect(
false))
1388 if (debug::layoutItem !=
nullptr && (debug::layoutItem !=
this || has_layout()))
1390 i_layout const& debugLayout = (debug::layoutItem ==
this ?
layout() : *
static_cast<i_layout const*
>(debug::layoutItem));
1391 if (debug::renderGeometryText)
1393 if (debug::layoutItem !=
this)
1396 std::ostringstream oss;
1397 oss <<
"sizepol: " << debugLayout.size_policy();
1398 oss <<
" minsize: " << debugLayout.minimum_size() <<
" maxsize: " << debugLayout.maximum_size();
1399 oss <<
" fixsize: " << (debugLayout.has_fixed_size() ? debugLayout.fixed_size() :
optional_size{}) <<
" weight: " << debugLayout.weight() <<
" extents: " << debugLayout.extents();
1405 auto const& item = debugLayout.
item_at(itemIndex);
1406 if (debug::renderGeometryText)
1408 std::string text =
typeid(item).name();
1410 while (l->has_parent_layout())
1413 text =
typeid(*l).name() +
" > "_s + text;
1417 rect const itemRect{ item.
position(), item.extents() };
1423 rect const layoutRect{ debugLayout.position(), debugLayout.extents() };
1433 template <
typename Interface>
1439 template <
typename Interface>
1445 template <
typename Interface>
1448 if (Opacity != aOpacity)
1455 template <
typename Interface>
1458 return BackgroundOpacity != std::nullopt;
1461 template <
typename Interface>
1464 if (has_background_opacity())
1465 return *BackgroundOpacity.value();
1469 template <
typename Interface>
1472 if (BackgroundOpacity != aOpacity)
1474 BackgroundOpacity = aOpacity;
1479 template <
typename Interface>
1482 return Palette != std::nullopt;
1485 template <
typename Interface>
1489 return *Palette.value();
1490 return service<i_app>().current_style().
palette();
1493 template <
typename Interface>
1496 if (Palette != aPalette)
1503 template <
typename Interface>
1509 template <
typename Interface>
1515 template <
typename Interface>
1518 if (Palette == std::nullopt)
1520 if (palette_color(aColorRole) != aColor)
1529 template <
typename Interface>
1538 return service<i_app>().current_style().palette().color(color_role::Theme);
1541 template <
typename Interface>
1544 return FontRole != std::nullopt;
1547 template <
typename Interface>
1550 if (has_font_role())
1551 return *FontRole.value();
1555 template <
typename Interface>
1558 if (FontRole != aFontRole)
1560 FontRole = aFontRole;
1565 template <
typename Interface>
1568 return Font != std::nullopt;
1571 template <
typename Interface>
1577 return service<i_app>().current_style().font(
font_role());
1580 template <
typename Interface>
1583 auto& self = base_type::as_widget();
1588 self.update_layout();
1593 template <
typename Interface>
1596 return Visible && (base_type::MaximumSize == std::nullopt || (base_type::MaximumSize->cx != 0.0 && base_type::MaximumSize->cy != 0.0));
1599 template <
typename Interface>
1602 return visible() && (self_type::is_root() || !has_parent() || parent().effectively_visible());
1605 template <
typename Interface>
1611 template <
typename Interface>
1614 return !effectively_visible();
1617 template <
typename Interface>
1620 if (Visible != aVisible)
1622 bool isEntered = entered();
1624 if (!visible() && isEntered)
1626 if (!self_type::is_root())
1627 self_type::root().as_widget().mouse_entered(self_type::root().mouse_position());
1631 VisibilityChanged.trigger();
1632 if (effectively_hidden())
1634 base_type::as_widget().update_layout(
true,
true);
1640 template <
typename Interface>
1646 template <
typename Interface>
1649 return enabled() && (self_type::is_root() || !has_parent() || parent().effectively_enabled());
1652 template <
typename Interface>
1658 template <
typename Interface>
1661 return !effectively_enabled();
1664 template <
typename Interface>
1669 bool isEntered = entered();
1671 if (!enabled() && isEntered)
1673 if (!self_type::is_root())
1674 self_type::root().as_widget().mouse_entered(self_type::root().mouse_position());
1684 template <
typename Interface>
1687 return self_type::has_root() && self_type::root().has_entered_widget() && (&self_type::root().entered_widget() ==
this || (aChildEntered && self_type::root().entered_widget().is_descendent_of(*
this)));
1690 template <
typename Interface>
1696 template <
typename Interface>
1699 return surface().as_surface_window().has_capturing_widget() && &surface().as_surface_window().capturing_widget() ==
this;
1702 template <
typename Interface>
1705 return iCapturePosition;
1708 template <
typename Interface>
1711 auto& self = base_type::as_widget();
1717 case capture_reason::MouseEvent:
1718 if (!self.mouse_event_is_non_client())
1719 surface().as_surface_window().set_capture(*
this);
1721 surface().as_surface_window().non_client_set_capture(*
this);
1724 surface().as_surface_window().set_capture(*
this);
1727 iCapturePosition = aPosition;
1730 throw widget_cannot_capture();
1733 template <
typename Interface>
1736 auto& self = base_type::as_widget();
1740 case capture_reason::MouseEvent:
1741 if (!self.mouse_event_is_non_client())
1742 surface().as_surface_window().release_capture(*
this);
1744 surface().as_surface_window().non_client_release_capture(*
this);
1747 surface().as_surface_window().release_capture(*
this);
1750 iCapturePosition = std::nullopt;
1753 template <
typename Interface>
1759 throw widget_cannot_capture();
1762 template <
typename Interface>
1768 template <
typename Interface>
1773 template <
typename Interface>
1778 template <
typename Interface>
1781 return FocusPolicy != std::nullopt;
1784 template <
typename Interface>
1787 if (has_focus_policy())
1788 return *FocusPolicy;
1792 template <
typename Interface>
1795 FocusPolicy = aFocusPolicy;
1798 template <
typename Interface>
1801 if (effectively_hidden() || effectively_disabled())
1803 switch (aFocusReason)
1805 case focus_reason::ClickNonClient:
1807 case focus_reason::ClickClient:
1809 case focus_reason::Tab:
1811 case focus_reason::Wheel:
1813 case focus_reason::Pointer:
1815 case focus_reason::WindowActivation:
1816 case focus_reason::Other:
1822 template <
typename Interface>
1825 return self_type::has_root() && self_type::root().is_active() && self_type::root().has_focused_widget() && &self_type::root().focused_widget() ==
this;
1828 template <
typename Interface>
1831 return self_type::has_root() && self_type::root().is_active() && self_type::root().has_focused_widget() && self_type::root().focused_widget().is_descendent_of(*
this);
1834 template <
typename Interface>
1839 self_type::root().set_focused_widget(*
this, aFocusReason);
1845 template <
typename Interface>
1848 if (has_focus() || child_has_focus())
1850 self_type::root().release_focused_widget(self_type::root().focused_widget());
1856 template <
typename Interface>
1860 Focus.trigger(focus_event::FocusGained, aReason);
1863 template <
typename Interface>
1867 Focus.trigger(focus_event::FocusLost, aReason);
1870 template <
typename Interface>
1873 return ConsiderAncestorsForMouseEvents;
1876 template <
typename Interface>
1879 ConsiderAncestorsForMouseEvents = aConsiderAncestors;
1882 template <
typename Interface>
1885 return IgnoreMouseEvents || (aConsiderAncestors && consider_ancestors_for_mouse_events() &&
1886 has_parent() && parent().ignore_mouse_events());
1889 template <
typename Interface>
1892 IgnoreMouseEvents = aIgnoreMouseEvents;
1895 template <
typename Interface>
1898 return IgnoreNonClientMouseEvents || (aConsiderAncestors && consider_ancestors_for_mouse_events() &&
1899 has_parent() && parent().ignore_non_client_mouse_events());
1902 template <
typename Interface>
1905 IgnoreNonClientMouseEvents = aIgnoreNonClientMouseEvents;
1908 template <
typename Interface>
1911 if (self_type::has_root() && self_type::root().has_native_surface())
1912 return surface().as_surface_window().current_mouse_event_location();
1917 template <
typename Interface>
1920 auto& self = base_type::as_widget();
1922 if (has_parent() && same_surface(parent()))
1923 return parent().mouse_wheel_scrolled(aWheel, aPosition + self.position(), aDelta, aKeyModifiers);
1928 template <
typename Interface>
1931 auto& self = base_type::as_widget();
1933 if (aButton == mouse_button::Middle && has_parent())
1934 parent().mouse_button_pressed(aButton, aPosition + self.position(), aKeyModifiers);
1935 else if (aButton == mouse_button::Left &&
capture_ok(hit_test(aPosition)) && can_capture())
1936 set_capture(capture_reason::MouseEvent, aPosition);
1939 template <
typename Interface>
1942 auto& self = base_type::as_widget();
1944 if (aButton == mouse_button::Middle && has_parent())
1945 parent().mouse_button_double_clicked(aButton, aPosition + self.position(), aKeyModifiers);
1946 else if (aButton == mouse_button::Left &&
capture_ok(hit_test(aPosition)) && can_capture())
1947 set_capture(capture_reason::MouseEvent, aPosition);
1950 template <
typename Interface>
1953 auto& self = base_type::as_widget();
1955 if (aButton == mouse_button::Middle && has_parent())
1956 parent().mouse_button_released(aButton, aPosition + self.position());
1957 else if (capturing())
1958 release_capture(capture_reason::MouseEvent);
1961 template <
typename Interface>
1967 template <
typename Interface>
1973 template <
typename Interface>
1979 template <
typename Interface>
1982 auto& self = base_type::as_widget();
1984 auto const rootMousePosition = self_type::root().mouse_position();
1985 if (self_type::is_root())
1986 return rootMousePosition;
1988 return rootMousePosition + self_type::root().origin() - self.origin();
1991 template <
typename Interface>
1994 std::optional<neogfx::mouse_cursor> mouseCursor;
1995 auto const mousePosition = mouse_position();
1996 auto const partUnderMouse = part(mousePosition);
1997 if (part_active(partUnderMouse))
1999 switch (partUnderMouse.part)
2001 case widget_part::BorderLeft:
2002 mouseCursor = mouse_system_cursor::SizeWE;
2004 case widget_part::BorderTopLeft:
2005 mouseCursor = mouse_system_cursor::SizeNWSE;
2007 case widget_part::BorderTop:
2008 mouseCursor = mouse_system_cursor::SizeNS;
2010 case widget_part::BorderTopRight:
2011 mouseCursor = mouse_system_cursor::SizeNESW;
2013 case widget_part::BorderRight:
2014 mouseCursor = mouse_system_cursor::SizeWE;
2016 case widget_part::BorderBottomRight:
2017 mouseCursor = mouse_system_cursor::SizeNWSE;
2019 case widget_part::BorderBottom:
2020 mouseCursor = mouse_system_cursor::SizeNS;
2022 case widget_part::BorderBottomLeft:
2023 mouseCursor = mouse_system_cursor::SizeNESW;
2025 case widget_part::GrowBox:
2026 mouseCursor = mouse_system_cursor::SizeNWSE;
2028 case widget_part::VerticalScrollbar:
2029 mouseCursor = mouse_system_cursor::Arrow;
2031 case widget_part::HorizontalScrollbar:
2032 mouseCursor = mouse_system_cursor::Arrow;
2036 if (!mouseCursor && has_parent())
2037 mouseCursor = parent().mouse_cursor();
2039 mouseCursor = mouse_system_cursor::Arrow;
2040 QueryMouseCursor.trigger(*mouseCursor);
2041 return mouseCursor.value();
2044 template <
typename Interface>
2050 template <
typename Interface>
2056 template <
typename Interface>
2062 template <
typename Interface>
2068 template <
typename Interface>
2071 auto& self = base_type::as_widget();
2075 auto const clientPosition = aPosition - self.origin();
2077 if (self_type::is_root() && (self_type::root().
style() & window_style::Resize) == window_style::Resize)
2079 auto const outerRect = to_client_coordinates(non_client_rect());
2080 auto const innerRect = outerRect.deflated(self_type::root().window_border());
2081 if (outerRect.contains(clientPosition) && !innerRect.contains(clientPosition))
2084 if (!result && non_client_rect().
contains(aPosition))
2087 const i_widget* w = &get_widget_at(clientPosition);
2088 for (; w != this ; w = &w->
parent())
2090 auto const widgetClientPosition = aPosition - w->origin();
2093 switch (w->
part(widgetClientPosition).
part)
2095 case widget_part::Nowhere:
2097 case widget_part::TitleBar:
2098 case widget_part::BorderBottomRight:
2122 template <
typename Interface>
2125 return const_cast<i_widget&
>(to_const(*this).widget_for_mouse_event(aPosition, aForHitTest));
self_type intersection(const self_type &other) const
const point_type & position() const
self_type deflated(Args &&... aArgs) const
bool contains(const point_type &point) const
const size_type & extents() const
return_type with_alpha(view_component aAlpha) const
static constexpr basic_size max_size()
virtual void line_stipple_off() const =0
virtual point origin() const =0
virtual void flush() const =0
virtual void draw_text(const point &aPoint, std::string const &aText, const text_format &aTextFormat) const =0
virtual void line_stipple_on(scalar aFactor, uint16_t aPattern, scalar aPosition=0.0) const =0
void fill_rect(const rect &aRect, const brush &aFill) const
virtual void set_origin(const point &aOrigin) const =0
virtual void set_extents(const size &aExtents) const =0
virtual void draw_rect(const rect &aRect, const pen &aPen, const brush &aFill=brush{}) const =0
virtual void set_default_font(const font &aDefaultFont) const =0
virtual const i_layout & parent_layout() const =0
virtual layout_item_index count() const =0
virtual i_layout_item & add(i_layout_item &aItem)=0
virtual const i_layout_item & item_at(layout_item_index aIndex) const =0
virtual const std::type_info & category() const =0
virtual bool has_surface() const =0
virtual bool is_nested() const =0
size maximum_size(optional_size const &aAvailableSpace={}) const override
size minimum_size(optional_size const &aAvailableSpace={}) const override
void set_parent_layout(i_layout *aParentLayout) final
bool remove(i_layout_item &aItem) override
neogfx::color color(color_role aRole) const override
bool has_color(color_role aRole) const override
void set_color(color_role aRole, const optional_color &aColor) override
static const sRGB_color Yellow
static const sRGB_color Orange
static const sRGB_color White
static const sRGB_color Red
static const sRGB_color Blue
static const sRGB_color Purple
static const sRGB_color Black
static const sRGB_color Green
vector2 to_device_units(const vector2 &aValue) const
vector2 from_device_units(const vector2 &aValue) const
#define shared_thread_local(VariableType, VariableScope, VariableName,...)
logical_coordinate_system
bool contains(item_selection const &aSelection, item_presentation_model_index aIndex)
bool querying_ideal_size()
layer_t constexpr LayerWidget
bool capture_ok(widget_part aWidgetPart)
uint32_t layout_item_index
bool has_font(glyph_char const &g)
basic_scoped_units< units > scoped_units
const current_style_palette_proxy_t current_style_palette_proxy()