1 /* 2 * DQt - D bindings for the Qt Toolkit 3 * 4 * GNU Lesser General Public License Usage 5 * This file may be used under the terms of the GNU Lesser 6 * General Public License version 3 as published by the Free Software 7 * Foundation and appearing in the file LICENSE.LGPL3 included in the 8 * packaging of this file. Please review the following information to 9 * ensure the GNU Lesser General Public License version 3 requirements 10 * will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 11 */ 12 module qt.core.property; 13 extern(C++): 14 15 import qt.config; 16 import qt.core.anystringview; 17 import qt.core.global; 18 import qt.core.metatype; 19 import qt.core.propertyprivate; 20 import qt.core.shareddata; 21 import qt.core.string; 22 import qt.core.taggedpointer; 23 import qt.core.typeinfo; 24 import qt.helpers; 25 26 /+ #if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_CLANG_QDOC) 27 #if defined(__cpp_lib_source_location) 28 #define QT_SOURCE_LOCATION_NAMESPACE std 29 #define QT_PROPERTY_COLLECT_BINDING_LOCATION 30 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current()) 31 #endif 32 #endif +/ 33 34 static if(!defined!"QT_PROPERTY_COLLECT_BINDING_LOCATION") 35 { 36 /+ #if defined(__cpp_lib_experimental_source_location) +/ 37 /+ #define QT_SOURCE_LOCATION_NAMESPACE std::experimental 38 #define QT_PROPERTY_COLLECT_BINDING_LOCATION +/ 39 /+ #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::experimental::source_location::current()) +/ 40 enum QT_PROPERTY_DEFAULT_BINDING_LOCATION = q{QPropertyBindingSourceLocation(current())}; 41 /+ #endif +/ 42 } 43 44 /+ #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION) 45 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation() 46 #endif +/ 47 48 49 extern(C++, "Qt") { 50 /+ Q_CORE_EXPORT +/ void beginPropertyUpdateGroup(); 51 /+ Q_CORE_EXPORT +/ void endPropertyUpdateGroup(); 52 } 53 54 /// Binding for C++ class [QPropertyData](https://doc.qt.io/qt-6/qpropertydata.html). 55 class QPropertyData(T) : QUntypedPropertyData 56 { 57 protected: 58 /+ mutable +/ T val = T(); 59 private: 60 extern(C++, class) struct DisableRValueRefs {} 61 protected: 62 extern(D) static immutable bool UseReferences = !(/+ std:: +/is_arithmetic_v!(T) || /+ std:: +/is_enum_v!(T) || /+ std:: +/is_pointer_v!(T)); 63 public: 64 /* alias value_type = T; 65 alias parameter_type = /+ std:: +/conditional_t!(UseReferences, ref const(T), T); 66 /+ using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>; +/ 67 alias arrow_operator_result = /+ std:: +/conditional_t!(bool, ref const(T), 68 /+ std:: +/conditional_t!(bool, ref const(T), void)); 69 70 /+ QPropertyData() = default; +/ 71 this(parameter_type t) 72 { 73 this.val = t; 74 } 75 this(rvalue_ref t) 76 { 77 this.val = /+ std:: +/move(t); 78 } 79 /+ ~QPropertyData() = default; +/ 80 81 final parameter_type valueBypassingBindings() const { return val; } 82 final void setValueBypassingBindings(parameter_type v) { val = v; } 83 final void setValueBypassingBindings(rvalue_ref v) { val = /+ std:: +/move(v); }*/ 84 } 85 86 struct /+ Q_CORE_EXPORT +/ QPropertyBindingSourceLocation 87 { 88 const(char)* fileName = null; 89 const(char)* functionName = null; 90 quint32 line = 0; 91 quint32 column = 0; 92 /+ QPropertyBindingSourceLocation() = default; +/ 93 /+ #ifdef QT_PROPERTY_COLLECT_BINDING_LOCATION +/ 94 /+ this(ref UnknownType!q{/+ QT_SOURCE_LOCATION_NAMESPACE:: +/source_location source_location} cppLocation) 95 { 96 fileName = cppLocation.file_name(); 97 functionName = cppLocation.function_name(); 98 line = cppLocation.line(); 99 column = cppLocation.column(); 100 }+/ 101 /+ #endif +/ 102 mixin(CREATE_CONVENIENCE_WRAPPERS); 103 } 104 105 extern(C++, class) struct QPropertyBindingErrorPrivate; 106 107 /// Binding for C++ class [QPropertyBindingError](https://doc.qt.io/qt-6/qpropertybindingerror.html). 108 extern(C++, class) struct /+ Q_CORE_EXPORT +/ QPropertyBindingError 109 { 110 public: 111 enum Type { 112 NoError, 113 BindingLoop, 114 EvaluationError, 115 UnknownError 116 } 117 118 @disable this(); 119 pragma(mangle, defaultConstructorMangling(__traits(identifier, typeof(this)))) 120 ref typeof(this) rawConstructor(); 121 static typeof(this) create() 122 { 123 typeof(this) r = typeof(this).init; 124 r.rawConstructor(); 125 return r; 126 } 127 128 this(Type type, ref const(QString) description = globalInitVar!QString); 129 130 @disable this(this); 131 this(ref const(QPropertyBindingError) other); 132 /+ref QPropertyBindingError operator =(ref const(QPropertyBindingError) other);+/ 133 /+ QPropertyBindingError(QPropertyBindingError &&other); +/ 134 /+ QPropertyBindingError &operator=(QPropertyBindingError &&other); +/ 135 ~this(); 136 137 bool hasError() const { return d.get() !is null; } 138 Type type() const; 139 QString description() const; 140 141 private: 142 QSharedDataPointer!(QPropertyBindingErrorPrivate) d; 143 mixin(CREATE_CONVENIENCE_WRAPPERS); 144 } 145 146 extern(C++, class) struct /+ Q_CORE_EXPORT +/ QUntypedPropertyBinding 147 { 148 public: 149 // writes binding result into dataPtr 150 alias BindingFunctionVTable = /+ QtPrivate:: +/qt.core.propertyprivate.BindingFunctionVTable; 151 152 @disable this(); 153 pragma(mangle, defaultConstructorMangling(__traits(identifier, typeof(this)))) 154 ref typeof(this) rawConstructor(); 155 static typeof(this) create() 156 { 157 typeof(this) r = typeof(this).init; 158 r.rawConstructor(); 159 return r; 160 } 161 162 this(QMetaType metaType, const(BindingFunctionVTable)* vtable, void* function_, ref const(QPropertyBindingSourceLocation) location); 163 164 /+ template<typename Functor> +/ 165 /+ QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location) 166 : QUntypedPropertyBinding(metaType, &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>>, &f, location) 167 {} +/ 168 169 /+ QUntypedPropertyBinding(QUntypedPropertyBinding &&other); +/ 170 @disable this(this); 171 this(ref const(QUntypedPropertyBinding) other); 172 /+ref QUntypedPropertyBinding operator =(ref const(QUntypedPropertyBinding) other);+/ 173 /+ QUntypedPropertyBinding &operator=(QUntypedPropertyBinding &&other); +/ 174 ~this(); 175 176 bool isNull() const; 177 178 QPropertyBindingError error() const; 179 180 QMetaType valueMetaType() const; 181 182 /+ explicit +/this(QPropertyBindingPrivate* priv); 183 private: 184 /+ friend class QtPrivate::QPropertyBindingData; +/ 185 /+ friend class QPropertyBindingPrivate; +/ 186 /+ template <typename> +/ /+ friend class QPropertyBinding; +/ 187 QPropertyBindingPrivatePtr d; 188 mixin(CREATE_CONVENIENCE_WRAPPERS); 189 } 190 191 extern(C++, class) struct QPropertyBinding(PropertyType) 192 { 193 public QUntypedPropertyBinding base0; 194 alias base0 this; 195 196 public: 197 /+ QPropertyBinding() = default; +/ 198 199 /+ template<typename Functor> +/ 200 /+ QPropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location) 201 : QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>, PropertyType>, &f, location) 202 {} +/ 203 204 205 // Internal 206 /+ explicit +/this(ref const(QUntypedPropertyBinding) binding) 207 { 208 this.base0 = QUntypedPropertyBinding(binding); 209 } 210 } 211 212 /+ namespace Qt { 213 template <typename Functor> 214 auto makePropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 215 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr) 216 { 217 return QPropertyBinding<std::invoke_result_t<Functor>>(std::forward<Functor>(f), location); 218 } 219 } +/ 220 221 struct QPropertyObserverPrivate; 222 struct QPropertyObserverPointer; 223 224 extern(C++, class) struct QPropertyObserverBase 225 { 226 public: 227 // Internal 228 enum ObserverTag { 229 ObserverNotifiesBinding, // observer was installed to notify bindings that obsverved property changed 230 ObserverNotifiesChangeHandler, // observer is a change handler, which runs on every change 231 ObserverIsPlaceholder, // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers. 232 ObserverIsAlias 233 } 234 protected: 235 alias ChangeHandler = ExternCPPFunc!(void function(QPropertyObserver*, QUntypedPropertyData* )); 236 237 private: 238 /+ friend struct QPropertyDelayedNotifications; +/ 239 /+ friend struct QPropertyObserverNodeProtector; +/ 240 /+ friend class QPropertyObserver; +/ 241 /+ friend struct QPropertyObserverPointer; +/ 242 /+ friend struct QPropertyBindingDataPointer; +/ 243 /+ friend class QPropertyBindingPrivate; +/ 244 245 QTaggedPointer!(QPropertyObserver, ObserverTag) next; 246 // prev is a pointer to the "next" element within the previous node, or to the "firstObserverPtr" if it is the 247 // first node. 248 /+ QtPrivate:: +/qt.core.propertyprivate.QTagPreservingPointerToPointer!(QPropertyObserver, ObserverTag) prev; 249 250 union { 251 QPropertyBindingPrivate* binding = null; 252 ChangeHandler changeHandler; 253 QUntypedPropertyData* aliasData; 254 } 255 } 256 257 extern(C++, class) struct /+ Q_CORE_EXPORT +/ QPropertyObserver 258 { 259 public QPropertyObserverBase base0; 260 alias base0 this; 261 protected: 262 alias ChangeHandler = QPropertyObserverBase.ChangeHandler; 263 public: 264 /+ constexpr QPropertyObserver() = default; +/ 265 /+ QPropertyObserver(QPropertyObserver &&other) noexcept; +/ 266 /+ QPropertyObserver &operator=(QPropertyObserver &&other) noexcept; +/ 267 ~this(); 268 269 /+ template<typename Property, typename = typename Property::InheritsQUntypedPropertyData> +/ 270 void setSource(Property,)(ref const(Property) property) 271 { setSource(property.bindingData()); } 272 void setSource(ref const(/+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData) property); 273 274 protected: 275 this(ChangeHandler changeHandler); 276 this(QUntypedPropertyData* aliasedPropertyPtr); 277 278 QUntypedPropertyData* aliasedProperty() /*const*/ 279 { 280 return aliasData; 281 } 282 283 private: 284 285 @disable this(this); 286 /+this(ref const(QPropertyObserver) ) /+ = delete +/;+/ 287 /+ref QPropertyObserver operator =(ref const(QPropertyObserver) ) /+ = delete +/;+/ 288 289 mixin(CREATE_CONVENIENCE_WRAPPERS); 290 } 291 292 /// Binding for C++ class [QPropertyChangeHandler](https://doc.qt.io/qt-6/qpropertychangehandler.html). 293 class /+ [[nodiscard]] +/ QPropertyChangeHandler(Functor) : QPropertyObserver 294 { 295 private: 296 Functor m_handler; 297 public: 298 /* this(Functor handler) 299 { 300 super([](QPropertyObserver *self, QUntypedPropertyData *) { 301 auto This = static_cast!(QPropertyChangeHandler!(Functor))(self); 302 This.m_handler(); 303 }); 304 this.m_handler = handler; 305 }*/ 306 307 /+ template<typename Property, typename = typename Property::InheritsQUntypedPropertyData> +/ 308 /+ this(Property,)(ref const(Property) property, Functor handler) 309 { 310 super([](QPropertyObserver *self, QUntypedPropertyData *) { 311 auto This = static_cast!(QPropertyChangeHandler!(Functor))(self); 312 This.m_handler(); 313 }); 314 this.m_handler = handler; 315 316 setSource(property); 317 } +/ 318 } 319 320 /// Binding for C++ class [QPropertyNotifier](https://doc.qt.io/qt-6/qpropertynotifier.html). 321 /+extern(C++, class) struct /+ [[nodiscard]] +/ QPropertyNotifier 322 { 323 public QPropertyObserver base0; 324 alias base0 this; 325 private: 326 /+ std:: +/function_!(UnresolvedMergeConflict!(q{UnknownType!q{void}},q{void()})) m_handler; 327 public: 328 /+ QPropertyNotifier() = default; +/ 329 /+ template<typename Functor> +/ 330 this(Functor)(Functor handler) 331 { 332 this.base0 = QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) { 333 auto This = static_cast!(QPropertyNotifier*)(self); 334 This.m_handler(); 335 }); 336 this.m_handler = handler; 337 } 338 339 /+ template<typename Functor, typename Property, typename = typename Property::InheritsQUntypedPropertyData> +/ 340 this(Functor,Property,)(ref const(Property) property, Functor handler) 341 { 342 this.base0 = QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) { 343 auto This = static_cast!(QPropertyNotifier*)(self); 344 This.m_handler(); 345 }); 346 this.m_handler = handler; 347 348 setSource(property); 349 } 350 mixin(CREATE_CONVENIENCE_WRAPPERS); 351 }+/ 352 353 /// Binding for C++ class [QProperty](https://doc.qt.io/qt-6/qproperty.html). 354 extern(C++, class) struct QProperty(T) 355 { 356 public QPropertyData!(T) base0; 357 alias base0 this; 358 private: 359 /+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData d; 360 bool is_equal(ref const(T) v) 361 { 362 static if (/+ QTypeTraits:: +/qt.core.typeinfo.has_operator_equal_v!(T)) { 363 if (v == this.val) 364 return true; 365 } 366 return false; 367 } 368 369 public: 370 alias value_type = QPropertyData!(T).value_type; 371 alias parameter_type = QPropertyData!(T).parameter_type; 372 /+ using rvalue_ref = typename QPropertyData<T>::rvalue_ref; +/ 373 alias arrow_operator_result = QPropertyData!(T).arrow_operator_result; 374 375 /+ QProperty() = default; +/ 376 /+ explicit +/this(parameter_type initialValue) 377 { 378 this.QPropertyData!(T) = initialValue; 379 } 380 /+ explicit +/this(rvalue_ref initialValue) 381 { 382 this.QPropertyData!(T) = /+ std:: +/move(initialValue); 383 } 384 /+ explicit +/this(ref const(QPropertyBinding!(T)) binding) 385 { 386 setBinding(binding); 387 } 388 /+ #ifndef Q_CLANG_QDOC +/ 389 /+ template <typename Functor> +/ 390 /+ explicit QProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 391 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr) 392 : QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location)) 393 {} +/ 394 /+ #else 395 template <typename Functor> 396 explicit QProperty(Functor &&f); 397 #endif +/ 398 /+ ~QProperty() = default; +/ 399 400 parameter_type value() const 401 { 402 d.registerWithCurrentlyEvaluatingBinding(); 403 return this.val; 404 } 405 406 /+arrow_operator_result operator ->() const 407 { 408 static if (/+ QTypeTraits:: +/qt.core.typeinfo.is_dereferenceable_v!(T)) { 409 return value(); 410 } else static if (/+ std:: +/is_pointer_v!(T)) { 411 value(); 412 return this.val; 413 } else { 414 return; 415 } 416 }+/ 417 418 parameter_type opUnary(string op)() const if(op == "*") 419 { 420 return value(); 421 } 422 423 /+auto opCast(T : parameter_type)() const 424 { 425 return value(); 426 }+/ 427 428 void setValue(rvalue_ref newValue) 429 { 430 d.removeBinding(); 431 if (is_equal(newValue)) 432 return; 433 this.val = /+ std:: +/move(newValue); 434 notify(); 435 } 436 437 void setValue(parameter_type newValue) 438 { 439 d.removeBinding(); 440 if (is_equal(newValue)) 441 return; 442 this.val = newValue; 443 notify(); 444 } 445 446 /+ref QProperty!(T) operator =(rvalue_ref newValue) 447 { 448 setValue(/+ std:: +/move(newValue)); 449 return this; 450 }+/ 451 452 /+ref QProperty!(T) operator =(parameter_type newValue) 453 { 454 setValue(newValue); 455 return this; 456 }+/ 457 458 QPropertyBinding!(T) setBinding(ref const(QPropertyBinding!(T)) newBinding) 459 { 460 return QPropertyBinding!(T)(d.setBinding(newBinding, &this)); 461 } 462 463 /+ bool setBinding(ref const(QUntypedPropertyBinding) newBinding) 464 { 465 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId!(T)()) 466 return false; 467 setBinding(static_cast!(ref const(QPropertyBinding!(T)))(newBinding)); 468 return true; 469 }+/ 470 471 /+ #ifndef Q_CLANG_QDOC +/ 472 /+ template <typename Functor> +/ 473 /+ QPropertyBinding<T> setBinding(Functor &&f, 474 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 475 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr) 476 { 477 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location)); 478 } +/ 479 /+ #else 480 template <typename Functor> 481 QPropertyBinding<T> setBinding(Functor f); 482 #endif +/ 483 484 bool hasBinding() const { return d.hasBinding(); } 485 486 QPropertyBinding!(T) binding() const 487 { 488 return QPropertyBinding!(T)(QUntypedPropertyBinding(d.binding())); 489 } 490 491 QPropertyBinding!(T) takeBinding() 492 { 493 return QPropertyBinding!(T)(d.setBinding(QUntypedPropertyBinding(), &this)); 494 } 495 496 /+ template<typename Functor> +/ 497 ValueClass!(QPropertyChangeHandler!(Functor)) onValueChanged(Functor)(Functor f) 498 { 499 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 500 return QPropertyChangeHandler!(Functor)(this, f); 501 } 502 503 /+ template<typename Functor> +/ 504 ValueClass!(QPropertyChangeHandler!(Functor)) subscribe(Functor)(Functor f) 505 { 506 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 507 f(); 508 return onValueChanged(f); 509 } 510 511 /+ template<typename Functor> +/ 512 QPropertyNotifier addNotifier(Functor)(Functor f) 513 { 514 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 515 return QPropertyNotifier(this, f); 516 } 517 518 ref const(/+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData) bindingData() const { return d; } 519 private: 520 void notify() 521 { 522 d.notifyObservers(&this); 523 } 524 525 /+ Q_DISABLE_COPY_MOVE(QProperty) +/ 526 @disable this(this); 527 /+this(ref const(QProperty));+//+ref QProperty operator =(ref const(QProperty));+/} 528 529 extern(C++, "Qt") { 530 /+ QPropertyBinding!(PropertyType) makePropertyBinding(PropertyType)(ref const(QProperty!(PropertyType)) otherProperty, 531 ref const(QPropertyBindingSourceLocation) location /+ = 532 QT_PROPERTY_DEFAULT_BINDING_LOCATION +/) 533 { 534 return makePropertyBinding([&otherProperty]() -> PropertyType { return otherProperty; }, location); 535 }+/ 536 } 537 538 539 extern(C++, "QtPrivate") 540 { 541 542 543 struct QBindableInterface 544 { 545 alias Getter = ExternCPPFunc!(void function(const(QUntypedPropertyData)* d, void* value)); 546 alias Setter = ExternCPPFunc!(void function(QUntypedPropertyData* d, const(void)* value)); 547 alias BindingGetter = ExternCPPFunc!(QUntypedPropertyBinding function(const(QUntypedPropertyData)* d)); 548 alias BindingSetter = ExternCPPFunc!(QUntypedPropertyBinding function(QUntypedPropertyData* d, ref const(QUntypedPropertyBinding) binding)); 549 alias MakeBinding = ExternCPPFunc!(QUntypedPropertyBinding function(const(QUntypedPropertyData)* d, ref const(QPropertyBindingSourceLocation) location)); 550 alias SetObserver = ExternCPPFunc!(void function(const(QUntypedPropertyData)* d, QPropertyObserver* observer)); 551 alias GetMetaType = ExternCPPFunc!(QMetaType function()); 552 Getter getter; 553 Setter setter; 554 BindingGetter getBinding; 555 BindingSetter setBinding; 556 MakeBinding makeBinding; 557 SetObserver setObserver; 558 GetMetaType metaType; 559 560 extern(D) static immutable quintptr MetaTypeAccessorFlag = 0x1; 561 } 562 563 class QBindableInterfaceForProperty(Property, ) 564 { 565 private: 566 alias T = UnknownType!q{Property.value_type}; 567 public: 568 // interface for computed properties. Those do not have a binding()/setBinding() method, but one can 569 // install observers on them. 570 /+ extern(D) static immutable QBindableInterface iface = { 571 [](const QUntypedPropertyData *d, void *value) -> void 572 { *static_cast!(T*)(value) = static_cast!(const(Property)*)(d).value(); }, 573 null, 574 null, 575 null, 576 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding 577 { return /+ Qt:: +/makePropertyBinding([d]() -> T { return static_cast!(const(Property)*)(d).value(); }, location); }, 578 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void 579 { observer.setSource(static_cast!(const(Property)*)(d).bindingData()); }, 580 []() { return QMetaType.fromType!(T)(); }} 581 ;+/ 582 } 583 584 /+ template<typename Property> 585 class QBindableInterfaceForProperty<const Property, std::void_t<decltype(std::declval<Property>().binding())>> 586 { 587 using T = typename Property::value_type; 588 public: 589 // A bindable created from a const property results in a read-only interface, too. 590 static constexpr QBindableInterface iface = { 591 592 [](const QUntypedPropertyData *d, void *value) -> void 593 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); }, 594 /*setter=*/nullptr, 595 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding 596 { return static_cast<const Property *>(d)->binding(); }, 597 /*setBinding=*/nullptr, 598 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding 599 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); }, 600 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void 601 { observer->setSource(static_cast<const Property *>(d)->bindingData()); }, 602 []() { return QMetaType::fromType<T>(); } 603 }; 604 }; 605 606 template<typename Property> 607 class QBindableInterfaceForProperty<Property, std::void_t<decltype(std::declval<Property>().binding())>> 608 { 609 using T = typename Property::value_type; 610 public: 611 static constexpr QBindableInterface iface = { 612 [](const QUntypedPropertyData *d, void *value) -> void 613 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); }, 614 [](QUntypedPropertyData *d, const void *value) -> void 615 { static_cast<Property *>(d)->setValue(*static_cast<const T*>(value)); }, 616 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding 617 { return static_cast<const Property *>(d)->binding(); }, 618 [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding 619 { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); }, 620 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding 621 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); }, 622 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void 623 { observer->setSource(static_cast<const Property *>(d)->bindingData()); }, 624 []() { return QMetaType::fromType<T>(); } 625 }; 626 }; +/ 627 628 } 629 630 extern(C++, "QtPrivate") { 631 // used in Q(Untyped)Bindable to print warnings about various binding errors 632 extern(C++, "BindableWarnings") { 633 enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface } 634 /+ Q_CORE_EXPORT +/ void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason); 635 /+ Q_CORE_EXPORT +/ void printMetaTypeMismatch(QMetaType actual, QMetaType expected); 636 } 637 } 638 639 /// Binding for C++ class [QUntypedBindable](https://doc.qt.io/qt-6/quntypedbindable.html). 640 extern(C++, class) struct QUntypedBindable 641 { 642 private: 643 /+ friend struct QUntypedBindablePrivate; +/ // allows access to internal data 644 protected: 645 QUntypedPropertyData* data = null; 646 const(/+ QtPrivate:: +/QBindableInterface)* iface = null; 647 this(QUntypedPropertyData* d, const(/+ QtPrivate:: +/QBindableInterface)* i) 648 { 649 this.data = d; 650 this.iface = i; 651 } 652 653 public: 654 /+ constexpr QUntypedBindable() = default; +/ 655 /+ template<typename Property> +/ 656 this(Property)(Property* p) 657 { 658 this.data = const_cast!(/+ std:: +/remove_cv_t!(Property)*)(p); 659 this.iface = &/+ QtPrivate:: +/QBindableInterfaceForProperty!(Property).iface; 660 (mixin(Q_ASSERT(q{QUntypedBindable.data && QUntypedBindable.iface}))); 661 } 662 663 bool isValid() const { return data !is null; } 664 bool isBindable() const { return iface && iface.getBinding; } 665 bool isReadOnly() const { return !(iface && iface.setBinding && iface.setObserver); } 666 667 QUntypedPropertyBinding makeBinding(ref const(QPropertyBindingSourceLocation) location /+ = QT_PROPERTY_DEFAULT_BINDING_LOCATION +/) const 668 { 669 return iface ? iface.makeBinding(data, location) : QUntypedPropertyBinding.create(); 670 } 671 672 QUntypedPropertyBinding takeBinding() 673 { 674 if (!iface) 675 return QUntypedPropertyBinding.create(); 676 // We do not have a dedicated takeBinding function pointer in the interface 677 // therefore we synthesize takeBinding by retrieving the binding with binding 678 // and calling setBinding with a default constructed QUntypedPropertyBinding 679 // afterwards. 680 if (!(iface.getBinding && iface.setBinding)) 681 return QUntypedPropertyBinding.create(); 682 QUntypedPropertyBinding binding = iface.getBinding(data); 683 QUntypedPropertyBinding tmp = QUntypedPropertyBinding.create(); 684 iface.setBinding(data, tmp); 685 return binding; 686 } 687 688 void observe(QPropertyObserver* observer) const 689 { 690 if (iface) 691 iface.setObserver(data, observer); 692 /+ #ifndef QT_NO_DEBUG 693 else 694 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:", 695 QtPrivate::BindableWarnings::InvalidInterface); 696 #endif +/ 697 } 698 699 /+ template<typename Functor> +/ 700 /+ ValueClass!(QPropertyChangeHandler!(Functor)) onValueChanged(Functor)(Functor f) const 701 { 702 auto handler = ValueClass!(QPropertyChangeHandler!(Functor))(f); 703 observe(&handler); 704 return handler; 705 } +/ 706 707 /+ template<typename Functor> +/ 708 /+ ValueClass!(QPropertyChangeHandler!(Functor)) subscribe(Functor)(Functor f) const 709 { 710 f(); 711 return onValueChanged(f); 712 } +/ 713 714 /+ template<typename Functor> +/ 715 QPropertyNotifier addNotifier(Functor)(Functor f) 716 { 717 auto handler = QPropertyNotifier(f); 718 observe(&handler); 719 return handler; 720 } 721 722 QUntypedPropertyBinding binding() const 723 { 724 if (!isBindable()) { 725 /+ #ifndef QT_NO_DEBUG 726 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ", 727 QtPrivate::BindableWarnings::NonBindableInterface); 728 #endif +/ 729 return QUntypedPropertyBinding.create(); 730 } 731 return iface.getBinding(data); 732 } 733 bool setBinding(ref const(QUntypedPropertyBinding) binding) 734 { 735 if (isReadOnly()) { 736 /+ #ifndef QT_NO_DEBUG 737 const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface : 738 QtPrivate::BindableWarnings::InvalidInterface; 739 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType); 740 #endif +/ 741 return false; 742 } 743 if (!binding.isNull() && binding.valueMetaType() != metaType()) { 744 /+ #ifndef QT_NO_DEBUG 745 QtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType()); 746 #endif +/ 747 return false; 748 } 749 iface.setBinding(data, binding); 750 return true; 751 } 752 bool hasBinding() const 753 { 754 return !binding().isNull(); 755 } 756 757 QMetaType metaType() const 758 { 759 if (!(iface && data)) 760 return QMetaType(); 761 if (iface.metaType) 762 return iface.metaType(); 763 // ### Qt 7: Change the metatype function to take data as its argument 764 // special casing for QML's proxy bindable: allow multiplexing in the getter 765 // function to retrieve the metatype from data 766 (mixin(Q_ASSERT(q{QUntypedBindable.iface.getter}))); 767 QMetaType result; 768 iface.getter(data, reinterpret_cast!(void*)(cast(quintptr)(&result) | /+ QtPrivate:: +/QBindableInterface.MetaTypeAccessorFlag)); 769 return result; 770 } 771 772 mixin(CREATE_CONVENIENCE_WRAPPERS); 773 } 774 775 /// Binding for C++ class [QBindable](https://doc.qt.io/qt-6/qbindable.html). 776 extern(C++, class) struct QBindable(T) 777 { 778 public QUntypedBindable base0; 779 alias base0 this; 780 private: 781 /+ template<typename U> +/ 782 /+ friend class QPropertyAlias; +/ 783 this(QUntypedPropertyData* d, const(/+ QtPrivate:: +/QBindableInterface)* i) 784 { 785 this.base0 = QUntypedBindable(d, i); 786 } 787 public: 788 /+ using QUntypedBindable::QUntypedBindable; +/ 789 /*/+ explicit +/this(ref const(QUntypedBindable) b) 790 { 791 this.base0 = QUntypedBindable(b); 792 793 if (iface && metaType() != QMetaType.fromType!(T)()) { 794 data = null; 795 iface = null; 796 } 797 }*/ 798 799 /+ QPropertyBinding!(T) makeBinding(ref const(QPropertyBindingSourceLocation) location /+ = QT_PROPERTY_DEFAULT_BINDING_LOCATION +/) const 800 { 801 return static_cast!(QPropertyBinding!(T) && /+ && +/)(QUntypedBindable.makeBinding(location)); 802 } 803 QPropertyBinding!(T) binding() const 804 { 805 return static_cast!(QPropertyBinding!(T) && /+ && +/)(QUntypedBindable.binding()); 806 } 807 808 QPropertyBinding!(T) takeBinding() 809 { 810 return static_cast!(QPropertyBinding!(T) && /+ && +/)(QUntypedBindable.takeBinding()); 811 } 812 813 /+ using QUntypedBindable::setBinding; +/ 814 QPropertyBinding!(T) setBinding(ref const(QPropertyBinding!(T)) binding) 815 { 816 (mixin(Q_ASSERT(q{!QUntypedBindable.iface || binding.isNull() || binding.valueMetaType() == QUntypedBindable.metaType()}))); 817 818 if (iface && iface.setBinding) 819 return static_cast!(QPropertyBinding!(T) && /+ && +/)(iface.setBinding(data, binding)); 820 /+ #ifndef QT_NO_DEBUG 821 if (!iface) 822 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface); 823 else 824 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface); 825 #endif +/ 826 return QPropertyBinding!(T)(); 827 }+/ 828 /+ #ifndef Q_CLANG_QDOC +/ 829 /+ template <typename Functor> +/ 830 /+ QPropertyBinding<T> setBinding(Functor &&f, 831 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 832 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr) 833 { 834 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location)); 835 } +/ 836 /+ #else 837 template <typename Functor> 838 QPropertyBinding<T> setBinding(Functor f); 839 #endif +/ 840 841 T value() const 842 { 843 if (iface) { 844 T result; 845 iface.getter(data, &result); 846 return result; 847 } 848 return T.init; 849 } 850 851 void setValue(ref const(T) value) 852 { 853 if (iface && iface.setter) 854 iface.setter(data, &value); 855 } 856 } 857 858 extern(C++, class) struct QPropertyAlias(T) 859 { 860 public QPropertyObserver base0; 861 alias base0 this; 862 private: 863 /+ Q_DISABLE_COPY_MOVE(QPropertyAlias) +/ 864 @disable this(this); 865 /+this(ref const(QPropertyAlias));+//+ref QPropertyAlias operator =(ref const(QPropertyAlias));+/ const(/+ QtPrivate:: +/QBindableInterface)* iface = null; 866 867 public: 868 /+ this(QProperty!(T)* property) 869 { 870 this.base0 = QPropertyObserver(property); 871 this.iface = &/+ QtPrivate:: +/QBindableInterfaceForProperty!(QProperty!(T)).iface; 872 873 if (iface) 874 iface.setObserver(aliasedProperty(), &this); 875 }+/ 876 877 /+ template<typename Property, typename = typename Property::InheritsQUntypedPropertyData> +/ 878 this(Property,)(Property* property) 879 { 880 this.base0 = QPropertyObserver(property); 881 this.iface = &/+ QtPrivate:: +/QBindableInterfaceForProperty!(Property).iface; 882 883 if (iface) 884 iface.setObserver(aliasedProperty(), &this); 885 } 886 887 this(QPropertyAlias!(T)* alias_) 888 { 889 this.base0 = QPropertyObserver(alias_.aliasedProperty()); 890 this.iface = alias_.iface; 891 892 if (iface) 893 iface.setObserver(aliasedProperty(), &this); 894 } 895 896 this(ref const(QBindable!(T)) property) 897 { 898 this.base0 = QPropertyObserver(property.data); 899 this.iface = property.iface; 900 901 if (iface) 902 iface.setObserver(aliasedProperty(), &this); 903 } 904 905 /+T value() const 906 { 907 T t = T(); 908 if (auto* p = aliasedProperty()) 909 iface.getter(p, &t); 910 return t; 911 }+/ 912 913 /+auto opCast(T : T)() const { return value(); }+/ 914 915 /+void setValue(ref const(T) newValue) 916 { 917 if (auto* p = aliasedProperty()) 918 iface.setter(p, &newValue); 919 }+/ 920 921 /+ref QPropertyAlias!(T) operator =(ref const(T) newValue) 922 { 923 setValue(newValue); 924 return this; 925 }+/ 926 927 /+QPropertyBinding!(T) setBinding(ref const(QPropertyBinding!(T)) newBinding) 928 { 929 return QBindable!(T)(aliasedProperty(), iface).setBinding(cast(Functor && )(newBinding)); 930 }+/ 931 932 bool setBinding(ref const(QUntypedPropertyBinding) newBinding) 933 { 934 return cast(bool)(QBindable!(T)(aliasedProperty(), iface).setBinding(newBinding)); 935 } 936 937 /+ #ifndef Q_CLANG_QDOC +/ 938 /+ template <typename Functor> +/ 939 /+ QPropertyBinding<T> setBinding(Functor &&f, 940 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 941 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr) 942 { 943 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location)); 944 } +/ 945 /+ #else 946 template <typename Functor> 947 QPropertyBinding<T> setBinding(Functor f); 948 #endif +/ 949 950 bool hasBinding() const 951 { 952 return QBindable!(T)(aliasedProperty(), iface).hasBinding(); 953 } 954 955 QPropertyBinding!(T) binding() const 956 { 957 return QBindable!(T)(aliasedProperty(), iface).binding(); 958 } 959 960 QPropertyBinding!(T) takeBinding() 961 { 962 return QBindable!(T)(aliasedProperty(), iface).takeBinding(); 963 } 964 965 /+ template<typename Functor> +/ 966 ValueClass!(QPropertyChangeHandler!(Functor)) onValueChanged(Functor)(Functor f) 967 { 968 return QBindable!(T)(aliasedProperty(), iface).onValueChanged(f); 969 } 970 971 /+ template<typename Functor> +/ 972 ValueClass!(QPropertyChangeHandler!(Functor)) subscribe(Functor)(Functor f) 973 { 974 return QBindable!(T)(aliasedProperty(), iface).subscribe(f); 975 } 976 977 /+ template<typename Functor> +/ 978 QPropertyNotifier addNotifier(Functor)(Functor f) 979 { 980 return QBindable!(T)(aliasedProperty(), iface).notify(f); 981 } 982 983 bool isValid() const 984 { 985 return aliasedProperty() !is null; 986 } 987 } 988 989 /+ 990 /// Binding for C++ class [QObjectBindableProperty](https://doc.qt.io/qt-6/qobjectbindableproperty.html). 991 extern(C++, class) struct QObjectBindableProperty(Class, T, auto Offset, auto Signal=null) 992 { 993 public QPropertyData!(T) base0; 994 alias base0 this; 995 private: 996 alias ThisType = QObjectBindableProperty!(Class, T, Offset, Signal); 997 extern(D) static immutable bool HasSignal = !/+ std:: +/is_same_v!(/+ decltype(Signal) +/auto, /+ std:: +/nullptr_t); 998 alias SignalTakesValue = /+ std:: +/is_invocable!(/+ decltype(Signal) +/auto, Class, T); 999 Class* owner() 1000 { 1001 char* that = reinterpret_cast!(char*)(&this); 1002 return reinterpret_cast!(Class*)(that - /+ QtPrivate:: +//+ detail:: +/qt.core.propertyprivate.getOffset(Offset)); 1003 } 1004 const(Class)* owner() const 1005 { 1006 char* that = const_cast!(char*)(reinterpret_cast!(const(char)*)(&this)); 1007 return reinterpret_cast!(Class*)(that - /+ QtPrivate:: +//+ detail:: +/qt.core.propertyprivate.getOffset(Offset)); 1008 } 1009 static void signalCallBack(QUntypedPropertyData* o) 1010 { 1011 QObjectBindableProperty* that = static_cast!(QObjectBindableProperty*)(o); 1012 static if (HasSignal) { 1013 static if (SignalTakesValue.value) 1014 (that.owner()->*Signal)(that.valueBypassingBindings()); 1015 else 1016 (that.owner()->*Signal)(); 1017 } 1018 } 1019 public: 1020 alias value_type = QPropertyData!(T).value_type; 1021 alias parameter_type = QPropertyData!(T).parameter_type; 1022 /+ using rvalue_ref = typename QPropertyData<T>::rvalue_ref; +/ 1023 alias arrow_operator_result = QPropertyData!(T).arrow_operator_result; 1024 1025 /+ QObjectBindableProperty() = default; +/ 1026 /+ explicit +/this(ref const(T) initialValue) 1027 { 1028 this.QPropertyData!(T) = initialValue; 1029 } 1030 /+ explicit QObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {} +/ 1031 /+ explicit +/this(ref const(QPropertyBinding!(T)) binding) 1032 { 1033 this(); 1034 setBinding(binding); 1035 } 1036 /+ #ifndef Q_CLANG_QDOC +/ 1037 /+ template <typename Functor> +/ 1038 /+ explicit QObjectBindableProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 1039 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr) 1040 : QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location)) 1041 {} +/ 1042 /+ #else 1043 template <typename Functor> 1044 explicit QObjectBindableProperty(Functor &&f); 1045 #endif +/ 1046 1047 parameter_type value() const 1048 { 1049 import qt.core.object; 1050 1051 qGetBindingStorage(owner()).registerDependency(&this); 1052 return this.val; 1053 } 1054 1055 /+arrow_operator_result operator ->() const 1056 { 1057 static if (/+ QTypeTraits:: +/qt.core.typeinfo.is_dereferenceable_v!(T)) { 1058 return value(); 1059 } else static if (/+ std:: +/is_pointer_v!(T)) { 1060 value(); 1061 return this.val; 1062 } else { 1063 return; 1064 } 1065 }+/ 1066 1067 parameter_type opUnary(string op)() const if(op == "*") 1068 { 1069 return value(); 1070 } 1071 1072 /+auto opCast(T : parameter_type)() const 1073 { 1074 return value(); 1075 }+/ 1076 1077 void setValue(parameter_type t) 1078 { 1079 import qt.core.object; 1080 1081 auto* bd = cast(auto*)(qGetBindingStorage(owner()).bindingData(&this)); 1082 if (bd) 1083 bd.removeBinding(); 1084 if (this.val == t) 1085 return; 1086 this.val = t; 1087 notify(cast(const(qt.core.propertyprivate.QPropertyBindingData)*)(bd)); 1088 } 1089 1090 void notify() { 1091 import qt.core.object; 1092 1093 auto* bd = cast(auto*)(qGetBindingStorage(owner()).bindingData(&this)); 1094 notify(cast(const(qt.core.propertyprivate.QPropertyBindingData)*)(bd)); 1095 } 1096 1097 void setValue(rvalue_ref t) 1098 { 1099 import qt.core.object; 1100 1101 auto* bd = cast(auto*)(qGetBindingStorage(owner()).bindingData(&this)); 1102 if (bd) 1103 bd.removeBinding(); 1104 if (this.val == t) 1105 return; 1106 this.val = /+ std:: +/move(t); 1107 notify(cast(const(qt.core.propertyprivate.QPropertyBindingData)*)(bd)); 1108 } 1109 1110 /+ref QObjectBindableProperty operator =(rvalue_ref newValue) 1111 { 1112 setValue(/+ std:: +/move(newValue)); 1113 return this; 1114 }+/ 1115 1116 /+ref QObjectBindableProperty operator =(parameter_type newValue) 1117 { 1118 setValue(newValue); 1119 return this; 1120 }+/ 1121 1122 QPropertyBinding!(T) setBinding(ref const(QPropertyBinding!(T)) newBinding) 1123 { 1124 import qt.core.object; 1125 1126 /+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData* bd = qGetBindingStorage(owner()).bindingData(&this, true); 1127 auto oldBinding = QUntypedPropertyBinding(bd.setBinding(newBinding, &this, HasSignal ? &signalCallBack : null)); 1128 return static_cast!(ref QPropertyBinding!(T))(oldBinding); 1129 } 1130 1131 bool setBinding(ref const(QUntypedPropertyBinding) newBinding) 1132 { 1133 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId!(T)()) 1134 return false; 1135 setBinding(static_cast!(ref const(QPropertyBinding!(T)))(newBinding)); 1136 return true; 1137 } 1138 1139 /+ #ifndef Q_CLANG_QDOC +/ 1140 /+ template <typename Functor> +/ 1141 /+ QPropertyBinding<T> setBinding(Functor &&f, 1142 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, 1143 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr) 1144 { 1145 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location)); 1146 } +/ 1147 /+ #else 1148 template <typename Functor> 1149 QPropertyBinding<T> setBinding(Functor f); 1150 #endif +/ 1151 1152 bool hasBinding() const 1153 { 1154 import qt.core.object; 1155 1156 auto* bd = cast(auto*)(qGetBindingStorage(owner()).bindingData(&this)); 1157 return bd && bd.binding() !is null; 1158 } 1159 1160 QPropertyBinding!(T) binding() const 1161 { 1162 import qt.core.object; 1163 1164 auto* bd = cast(auto*)(qGetBindingStorage(owner()).bindingData(&this)); 1165 return static_cast!(QPropertyBinding!(T) && /+ && +/)(QUntypedPropertyBinding(bd ? bd.binding() : null)); 1166 } 1167 1168 QPropertyBinding!(T) takeBinding() 1169 { 1170 return setBinding(cast(Functor && )(QPropertyBinding!(T)())); 1171 } 1172 1173 /+ template<typename Functor> +/ 1174 ValueClass!(QPropertyChangeHandler!(Functor)) onValueChanged(Functor)(Functor f) 1175 { 1176 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1177 return QPropertyChangeHandler!(Functor)(this, f); 1178 } 1179 1180 /+ template<typename Functor> +/ 1181 ValueClass!(QPropertyChangeHandler!(Functor)) subscribe(Functor)(Functor f) 1182 { 1183 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1184 f(); 1185 return onValueChanged(f); 1186 } 1187 1188 /+ template<typename Functor> +/ 1189 QPropertyNotifier addNotifier(Functor)(Functor f) 1190 { 1191 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1192 return QPropertyNotifier(this, f); 1193 } 1194 1195 ref const(/+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData) bindingData() const 1196 { 1197 import qt.core.bindingstorage; 1198 import qt.core.object; 1199 1200 auto* storage = const_cast!(QBindingStorage*)(qGetBindingStorage(owner())); 1201 return *storage.bindingData(const_cast!(ThisType*)(&this), true); 1202 } 1203 private: 1204 void notify(const(/+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData)* binding) 1205 { 1206 import qt.core.object; 1207 1208 if (binding) 1209 binding.notifyObservers(&this, qGetBindingStorage(owner())); 1210 static if (HasSignal) { 1211 static if (SignalTakesValue.value) 1212 (owner()->*Signal)(this.valueBypassingBindings()); 1213 else 1214 (owner()->*Signal)(); 1215 } 1216 } 1217 }+/ 1218 1219 /+ #define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \ 1220 static constexpr size_t _qt_property_##name##_offset() { \ 1221 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1222 return offsetof(Class, name); \ 1223 QT_WARNING_POP \ 1224 } \ 1225 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name; 1226 1227 #define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \ 1228 static constexpr size_t _qt_property_##name##_offset() { \ 1229 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1230 return offsetof(Class, name); \ 1231 QT_WARNING_POP \ 1232 } \ 1233 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name; 1234 1235 #define Q_OBJECT_BINDABLE_PROPERTY(...) \ 1236 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1237 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \ 1238 QT_WARNING_POP 1239 1240 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value) \ 1241 static constexpr size_t _qt_property_##name##_offset() \ 1242 { \ 1243 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1244 return offsetof(Class, name); \ 1245 QT_WARNING_POP \ 1246 } \ 1247 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name = \ 1248 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>( \ 1249 value); 1250 1251 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, value, Signal) \ 1252 static constexpr size_t _qt_property_##name##_offset() \ 1253 { \ 1254 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1255 return offsetof(Class, name); \ 1256 QT_WARNING_POP \ 1257 } \ 1258 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name = \ 1259 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>( \ 1260 value); 1261 1262 #define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \ 1263 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1264 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \ 1265 QT_WARNING_POP +/ 1266 1267 /// Binding for C++ class [QObjectComputedProperty](https://doc.qt.io/qt-6/qobjectcomputedproperty.html). 1268 /+class QObjectComputedProperty(Class, T, auto Offset, auto Getter) : QUntypedPropertyData 1269 { 1270 private: 1271 final Class* owner() 1272 { 1273 char* that = reinterpret_cast!(char*)(this); 1274 return reinterpret_cast!(Class*)(that - /+ QtPrivate:: +//+ detail:: +/qt.core.propertyprivate.getOffset(Offset)); 1275 } 1276 final const(Class)* owner() const 1277 { 1278 char* that = const_cast!(char*)(reinterpret_cast!(const(char)*)(this)); 1279 return reinterpret_cast!(Class*)(that - /+ QtPrivate:: +//+ detail:: +/qt.core.propertyprivate.getOffset(Offset)); 1280 } 1281 1282 public: 1283 alias value_type = T; 1284 alias parameter_type = T; 1285 1286 /+ QObjectComputedProperty() = default; +/ 1287 1288 final parameter_type value() const 1289 { 1290 import qt.core.object; 1291 1292 qGetBindingStorage(owner()).registerDependency(this); 1293 return (owner()->*Getter)(); 1294 } 1295 1296 /+ std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void> 1297 operator->() const 1298 { 1299 static if (QTypeTraits::is_dereferenceable_v<T>) 1300 return value(); 1301 else 1302 return; 1303 } +/ 1304 1305 final parameter_type opUnary(string op)() const if(op == "*") 1306 { 1307 return value(); 1308 } 1309 1310 /+final auto opCast(T : parameter_type)() const 1311 { 1312 return value(); 1313 }+/ 1314 1315 final bool hasBinding() const { return false; } 1316 1317 /+ template<typename Functor> +/ 1318 final ValueClass!(QPropertyChangeHandler!(Functor)) onValueChanged(Functor)(Functor f) 1319 { 1320 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1321 return QPropertyChangeHandler!(Functor)(*this, f); 1322 } 1323 1324 /+ template<typename Functor> +/ 1325 final ValueClass!(QPropertyChangeHandler!(Functor)) subscribe(Functor)(Functor f) 1326 { 1327 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1328 f(); 1329 return onValueChanged(f); 1330 } 1331 1332 /+ template<typename Functor> +/ 1333 final QPropertyNotifier addNotifier(Functor)(Functor f) 1334 { 1335 static assert(/+ std:: +/is_invocable_v!(Functor), "Functor callback must be callable without any parameters"); 1336 return QPropertyNotifier(*this, f); 1337 } 1338 1339 final ref /+ QtPrivate:: +/qt.core.propertyprivate.QPropertyBindingData bindingData() const 1340 { 1341 import qt.core.bindingstorage; 1342 import qt.core.object; 1343 1344 auto* storage = const_cast!(QBindingStorage*)(qGetBindingStorage(owner())); 1345 return *storage.bindingData(const_cast!(QObjectComputedProperty)(this), true); 1346 } 1347 1348 final void notify() { 1349 import qt.core.bindingstorage; 1350 import qt.core.object; 1351 1352 // computed property can't store a binding, so there's nothing to mark 1353 auto* storage = const_cast!(QBindingStorage*)(qGetBindingStorage(owner())); 1354 auto bd = storage.bindingData(const_cast!(QObjectComputedProperty)(this), false); 1355 if (bd) 1356 bd.notifyObservers(this, qGetBindingStorage(owner())); 1357 } 1358 }+/ 1359 1360 /+ #define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \ 1361 static constexpr size_t _qt_property_##name##_offset() { \ 1362 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ 1363 return offsetof(Class, name); \ 1364 QT_WARNING_POP \ 1365 } \ 1366 QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name; 1367 1368 #undef QT_SOURCE_LOCATION_NAMESPACE +/ 1369 1370