DataBinding.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../Common/TestsShell.h"
  29. #include <RmlUi/Core/Context.h>
  30. #include <RmlUi/Core/DataModelHandle.h>
  31. #include <RmlUi/Core/Element.h>
  32. #include <RmlUi/Core/ElementDocument.h>
  33. #include <doctest.h>
  34. using namespace Rml;
  35. namespace {
  36. static const String document_rml = R"(
  37. <rml>
  38. <head>
  39. <title>Test</title>
  40. <link type="text/rcss" href="/assets/rml.rcss"/>
  41. <link type="text/template" href="/assets/window.rml"/>
  42. <style>
  43. body.window
  44. {
  45. left: 50px;
  46. right: 50px;
  47. top: 30px;
  48. bottom: 30px;
  49. max-width: -1px;
  50. max-height: -1px;
  51. }
  52. div#content
  53. {
  54. text-align: left;
  55. padding: 50px;
  56. box-sizing: border-box;
  57. }
  58. </style>
  59. </head>
  60. <body template="window">
  61. <div data-model="basics">
  62. <p>{{ test }}</p>
  63. <p>{{ str1.val }}</p>
  64. <p>{{ str2.val }}</p>
  65. <p>{{ str3.val }}</p>
  66. <p>{{ test2.val }}</p>
  67. <h1>Basic</h1>
  68. <p>{{ basic.a }}</p>
  69. <p>{{ basic.b }}</p>
  70. <p>{{ basic.c }}</p>
  71. <p>{{ basic.d }}</p>
  72. <p>{{ basic.e }}</p>
  73. <p>{{ basic.f }}</p>
  74. <p>{{ basic.g }}</p>
  75. <p>{{ basic.h }}</p>
  76. <h1>Wrapped</h1>
  77. <p>{{ wrapped.a.val }}</p>
  78. <p>{{ wrapped.b.val }}</p>
  79. <p>{{ wrapped.c.val }}</p>
  80. <p>{{ wrapped.d.val }}</p>
  81. <p>{{ wrapped.e.val }}</p>
  82. <p>{{ wrapped.f.val }}</p>
  83. <p>{{ wrapped.g.val }}</p>
  84. <p>{{ wrapped.h.val }}</p>
  85. <h1>Pointed</h1>
  86. <p>{{ pointed.a.val }}</p>
  87. <p>{{ pointed.e.val }}</p>
  88. <p>{{ pointed.f.val }}</p>
  89. <p>{{ pointed.g.val }}</p>
  90. <p>{{ pointed.h.val }}</p>
  91. <h1>ConstPointed</h1>
  92. <p>{{ const_pointed.a.val }}</p>
  93. <p>{{ const_pointed.e.val }}</p>
  94. <p>{{ const_pointed.f.val }}</p>
  95. <p>{{ const_pointed.g.val }}</p>
  96. <p>{{ const_pointed.h.val }}</p>
  97. <h1>Arrays</h1>
  98. <p><span data-for="arrays.a">{{ it }} </span></p>
  99. <p><span data-for="arrays.b">{{ it }} </span></p>
  100. <p><span data-for="arrays.c">{{ it }} </span></p>
  101. <p><span data-for="arrays.d">{{ it.val }} </span></p>
  102. <p><span data-for="arrays.e">{{ it.val }} </span></p>
  103. <p><span data-for="arrays.f">{{ it.val }} </span></p>
  104. <p><span data-for="arrays.g">{{ it.val }} </span></p>
  105. </div>
  106. </body>
  107. </rml>
  108. )";
  109. struct StringWrap
  110. {
  111. StringWrap(String val = "wrap_default") : val(val) {}
  112. String val;
  113. };
  114. StringWrap gStr0 = StringWrap("obj");
  115. StringWrap* gStr1 = new StringWrap("raw");
  116. UniquePtr<StringWrap> gStr2 = MakeUnique<StringWrap>("unique");
  117. SharedPtr<StringWrap> gStr3 = MakeShared<StringWrap>("shared");
  118. const StringWrap* gStr4 = new StringWrap("const raw");
  119. const int* const_ptr_test = new int(5);
  120. struct Basic
  121. {
  122. int a = 1;
  123. int* b = new int(2);
  124. const int* c = new int(3);
  125. int GetD() {
  126. return 4;
  127. }
  128. int& GetE() const {
  129. static int e = 5;
  130. return e;
  131. }
  132. int* GetF() {
  133. static int f = 6;
  134. return &f;
  135. }
  136. const int& GetG() {
  137. static int g = 7;
  138. return g;
  139. }
  140. const int* GetH() {
  141. static int h = 8;
  142. return &h;
  143. }
  144. };
  145. struct Wrapped
  146. {
  147. StringWrap a = { "a" };
  148. StringWrap* b = new StringWrap("b");
  149. const StringWrap* c = new StringWrap("c");
  150. // Illegal: Must return by reference, or return scalar value.
  151. StringWrap GetD() {
  152. return { "d" };
  153. }
  154. StringWrap& GetE() {
  155. static StringWrap e = { "e" };
  156. return e;
  157. }
  158. StringWrap* GetF() {
  159. static StringWrap f = { "f" };
  160. return &f;
  161. }
  162. const StringWrap& GetG() {
  163. static StringWrap g = { "g" };
  164. return g;
  165. }
  166. const StringWrap* GetH() {
  167. static StringWrap h = { "h" };
  168. return &h;
  169. }
  170. };
  171. using StringWrapPtr = UniquePtr<StringWrap>;
  172. struct Pointed
  173. {
  174. StringWrapPtr a = MakeUnique<StringWrap>("a");
  175. // We disallow recursive pointer types (pointer to pointer)
  176. // Invalid:
  177. StringWrapPtr* b = new StringWrapPtr(new StringWrap("b"));
  178. const StringWrapPtr* c = new StringWrapPtr(new StringWrap("c"));
  179. StringWrapPtr GetD() {
  180. return MakeUnique<StringWrap>("d");
  181. }
  182. // -- End Invalid
  183. StringWrapPtr& GetE() {
  184. static StringWrapPtr e = MakeUnique<StringWrap>("e");
  185. return e;
  186. }
  187. StringWrapPtr* GetF() {
  188. static StringWrapPtr f = MakeUnique<StringWrap>("f");
  189. return &f;
  190. }
  191. const StringWrapPtr& GetG() {
  192. static StringWrapPtr g = MakeUnique<StringWrap>("g");
  193. return g;
  194. }
  195. const StringWrapPtr* GetH() {
  196. static StringWrapPtr h = MakeUnique<StringWrap>("h");
  197. return &h;
  198. }
  199. };
  200. using StringWrapConstPtr = UniquePtr<const StringWrap>;
  201. struct ConstPointed
  202. {
  203. StringWrapConstPtr a = MakeUnique<StringWrap>("a");
  204. // We disallow recursive pointer types (pointer to pointer)
  205. // -- Invalid
  206. StringWrapConstPtr* b = new StringWrapConstPtr(new StringWrap("b"));
  207. const StringWrapConstPtr* c = new StringWrapConstPtr(new StringWrap("c"));
  208. StringWrapConstPtr GetD() {
  209. return MakeUnique<StringWrap>("d");
  210. }
  211. // -- End Invalid
  212. StringWrapConstPtr& GetE() {
  213. static StringWrapConstPtr e = MakeUnique<StringWrap>("e");
  214. return e;
  215. }
  216. StringWrapConstPtr* GetF() {
  217. static StringWrapConstPtr f = MakeUnique<StringWrap>("f");
  218. return &f;
  219. }
  220. const StringWrapConstPtr& GetG() {
  221. static StringWrapConstPtr g = MakeUnique<StringWrap>("g");
  222. return g;
  223. }
  224. const StringWrapConstPtr* GetH() {
  225. static StringWrapConstPtr h = MakeUnique<StringWrap>("h");
  226. return &h;
  227. }
  228. };
  229. struct Arrays {
  230. Vector<int> a = { 10, 11, 12 };
  231. Vector<int*> b = { new int(20), new int(21), new int(22) };
  232. Vector<const int*> c = { new int(30), new int(31), new int(32) };
  233. Vector<StringWrap> d = { StringWrap("d1"), StringWrap("d2"), StringWrap("d3") };
  234. Vector<StringWrap*> e = { new StringWrap("e1"), new StringWrap("e2"), new StringWrap("e3") };
  235. Vector<StringWrapPtr> f;
  236. Vector<StringWrapConstPtr> g;
  237. Arrays() {
  238. f.emplace_back(MakeUnique<StringWrap>("f1"));
  239. f.emplace_back(MakeUnique<StringWrap>("f2"));
  240. f.emplace_back(MakeUnique<StringWrap>("f3"));
  241. g.emplace_back(MakeUnique<StringWrap>("g1"));
  242. g.emplace_back(MakeUnique<StringWrap>("g2"));
  243. g.emplace_back(MakeUnique<StringWrap>("g3"));
  244. }
  245. };
  246. DataModelHandle model_handle;
  247. bool InitializeDataBindings(Context* context)
  248. {
  249. Rml::DataModelConstructor constructor = context->CreateDataModel("basics");
  250. if (!constructor)
  251. return false;
  252. if (auto handle = constructor.RegisterStruct<StringWrap>())
  253. {
  254. handle.RegisterMember("val", &StringWrap::val);
  255. }
  256. constructor.Bind("test", &const_ptr_test);
  257. constructor.Bind("test2", &gStr4);
  258. constructor.Bind("str0", &gStr0);
  259. constructor.Bind("str1", &gStr1);
  260. constructor.Bind("str2", &gStr2);
  261. constructor.Bind("str3", &gStr3);
  262. if (auto handle = constructor.RegisterStruct<Basic>())
  263. {
  264. handle.RegisterMember("a", &Basic::a);
  265. handle.RegisterMember("b", &Basic::b);
  266. handle.RegisterMember("c", &Basic::c);
  267. handle.RegisterMember("d", &Basic::GetD);
  268. handle.RegisterMember("e", &Basic::GetE);
  269. handle.RegisterMember("f", &Basic::GetF);
  270. handle.RegisterMember("g", &Basic::GetG);
  271. handle.RegisterMember("h", &Basic::GetH);
  272. }
  273. constructor.Bind("basic", new Basic);
  274. if (auto handle = constructor.RegisterStruct<Wrapped>())
  275. {
  276. handle.RegisterMember("a", &Wrapped::a);
  277. handle.RegisterMember("b", &Wrapped::b);
  278. handle.RegisterMember("c", &Wrapped::c);
  279. //handle.RegisterMember("d", &Wrapped::GetD);
  280. handle.RegisterMember("e", &Wrapped::GetE);
  281. handle.RegisterMember("f", &Wrapped::GetF);
  282. handle.RegisterMember("g", &Wrapped::GetG);
  283. handle.RegisterMember("h", &Wrapped::GetH);
  284. }
  285. constructor.Bind("wrapped", new Wrapped);
  286. if (auto handle = constructor.RegisterStruct<Pointed>())
  287. {
  288. handle.RegisterMember("a", &Pointed::a);
  289. //handle.RegisterMember("b", &Pointed::b);
  290. //handle.RegisterMember("c", &Pointed::c);
  291. //handle.RegisterMember("d", &Pointed::GetD);
  292. handle.RegisterMember("e", &Pointed::GetE);
  293. handle.RegisterMember("f", &Pointed::GetF);
  294. handle.RegisterMember("g", &Pointed::GetG);
  295. handle.RegisterMember("h", &Pointed::GetH);
  296. }
  297. constructor.Bind("pointed", new Pointed);
  298. if (auto handle = constructor.RegisterStruct<ConstPointed>())
  299. {
  300. handle.RegisterMember("a", &ConstPointed::a);
  301. //handle.RegisterMember("b", &ConstPointed::b);
  302. //handle.RegisterMember("c", &ConstPointed::c);
  303. //handle.RegisterMemberGetter("d", &ConstPointed::GetD);
  304. handle.RegisterMember("e", &ConstPointed::GetE);
  305. handle.RegisterMember("f", &ConstPointed::GetF);
  306. handle.RegisterMember("g", &ConstPointed::GetG);
  307. handle.RegisterMember("h", &ConstPointed::GetH);
  308. }
  309. constructor.Bind("const_pointed", new ConstPointed);
  310. constructor.RegisterArray<decltype(Arrays::a)>();
  311. constructor.RegisterArray<decltype(Arrays::b)>();
  312. constructor.RegisterArray<decltype(Arrays::c)>();
  313. constructor.RegisterArray<decltype(Arrays::d)>();
  314. constructor.RegisterArray<decltype(Arrays::e)>();
  315. constructor.RegisterArray<decltype(Arrays::f)>();
  316. constructor.RegisterArray<decltype(Arrays::g)>();
  317. if (auto handle = constructor.RegisterStruct<Arrays>())
  318. {
  319. handle.RegisterMember("a", &Arrays::a);
  320. handle.RegisterMember("b", &Arrays::b);
  321. handle.RegisterMember("c", &Arrays::c);
  322. handle.RegisterMember("d", &Arrays::d);
  323. handle.RegisterMember("e", &Arrays::e);
  324. handle.RegisterMember("f", &Arrays::f);
  325. handle.RegisterMember("g", &Arrays::g);
  326. }
  327. constructor.Bind("arrays", new Arrays);
  328. model_handle = constructor.GetModelHandle();
  329. return true;
  330. }
  331. } // Anonymous namespace
  332. TEST_CASE("databinding")
  333. {
  334. Context* context = TestsShell::GetContext();
  335. REQUIRE(context);
  336. REQUIRE(InitializeDataBindings(context));
  337. ElementDocument* document = context->LoadDocumentFromMemory(document_rml);
  338. REQUIRE(document);
  339. document->Show();
  340. context->Update();
  341. context->Render();
  342. TestsShell::RenderLoop();
  343. document->Close();
  344. TestsShell::ShutdownShell();
  345. }