JSCore.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #include "JSCore.h"
  5. #include "JSEventHelper.h"
  6. #include "JSVM.h"
  7. namespace Atomic
  8. {
  9. static int EventHandler_Property_Get(duk_context* ctx)
  10. {
  11. // targ, key, recv
  12. if (duk_is_string(ctx, 1))
  13. {
  14. const char* cstr = duk_to_string(ctx, 1);
  15. StringHash key = cstr;
  16. JSEventHelper* helper = js_to_class_instance<JSEventHelper>(ctx, 0, 0);
  17. VariantMap& data = helper->GetCurrentData();
  18. if (!data.Contains(key))
  19. {
  20. duk_push_undefined(ctx);
  21. return 1;
  22. }
  23. js_push_variant(ctx, data[key]);
  24. return 1;
  25. }
  26. duk_push_undefined(ctx);
  27. return 1;
  28. }
  29. static int Object_SubscribeToEvent(duk_context* ctx)
  30. {
  31. int top = duk_get_top(ctx);
  32. Object* sender = NULL;
  33. StringHash eventType = StringHash::ZERO;
  34. if ( top == 2 ) // General notification: subscribeToEvent("ScreenMode", function() {});
  35. {
  36. if (duk_is_string(ctx, 0) && duk_is_function(ctx, 1))
  37. {
  38. eventType = duk_to_string(ctx, 0);
  39. }
  40. }
  41. else if (top == 3) // Listen to specific object sender subscribeToEvent(graphics, "ScreenMode", function() {});
  42. {
  43. if (duk_is_object(ctx, 0) && duk_is_string(ctx, 1) && duk_is_function(ctx, 2))
  44. {
  45. sender = js_to_class_instance<Object>(ctx, 0, 0);
  46. eventType = duk_to_string(ctx, 1);
  47. }
  48. }
  49. if ( eventType == StringHash::ZERO)
  50. {
  51. duk_push_string(ctx, "Object.subscribeToEvent() - Bad Arguments");
  52. duk_throw(ctx);
  53. }
  54. duk_push_this(ctx);
  55. // event receiver
  56. Object* object = js_to_class_instance<Object>(ctx, -1, 0);
  57. duk_get_prop_string(ctx, -1, "__eventHelper");
  58. // need to setup the handler
  59. if (duk_is_null_or_undefined(ctx, -1))
  60. {
  61. duk_pop(ctx); // pop null or undefined
  62. // construct a new event helper
  63. js_push_class_object_instance(ctx, new JSEventHelper(object->GetContext()));
  64. // proxy support
  65. duk_get_global_string(ctx, "Proxy");
  66. duk_dup(ctx, -2);
  67. // setup property handler
  68. duk_push_object(ctx);
  69. duk_push_c_function(ctx, EventHandler_Property_Get, 3);
  70. duk_put_prop_string(ctx, -2, "get");
  71. duk_new(ctx, 2);
  72. duk_put_prop_string(ctx, -2, "__eventHelperProxy");
  73. duk_push_object(ctx);
  74. duk_put_prop_string(ctx, -2, "__eventHelperFunctions");
  75. // dup so when we set the helper is left on stack
  76. duk_dup_top(ctx);
  77. duk_put_prop_string(ctx, -3, "__eventHelper");
  78. }
  79. JSEventHelper* helper = js_to_class_instance<JSEventHelper>(ctx, -1, 0);
  80. duk_get_prop_string(ctx, -1, "__eventHelperFunctions");
  81. assert(duk_is_object(ctx, -1));
  82. assert(duk_is_function(ctx, sender ? 2 : 1));
  83. duk_dup(ctx, sender ? 2 : 1);
  84. duk_put_prop_string(ctx, -2, eventType.ToString().CString());
  85. duk_pop(ctx);
  86. if (sender)
  87. helper->AddEventHandler(sender, eventType);
  88. else
  89. helper->AddEventHandler(eventType);
  90. return 0;
  91. }
  92. void jsapi_init_core(JSVM* vm)
  93. {
  94. duk_context* ctx = vm->GetJSContext();
  95. js_class_get_prototype(ctx, "Atomic", "AObject");
  96. duk_push_c_function(ctx, Object_SubscribeToEvent, DUK_VARARGS);
  97. duk_put_prop_string(ctx, -2, "subscribeToEvent");
  98. duk_pop(ctx);
  99. }
  100. }