JSUI.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include <TurboBadger/tb_widgets.h>
  2. #include <Atomic/UI/UIEvents.h>
  3. #include <Atomic/UI/UIWidget.h>
  4. #include <Atomic/UI/UIButton.h>
  5. #include <Atomic/UI/UI.h>
  6. #include "JSVM.h"
  7. #include "JSUI.h"
  8. using namespace tb;
  9. namespace Atomic
  10. {
  11. JSUI::JSUI(Context* context) : Object(context)
  12. {
  13. ctx_ = JSVM::GetJSVM(nullptr)->GetJSContext();
  14. SubscribeToEvent(E_WIDGETEVENT, HANDLER(JSUI, HandleWidgetEvent));
  15. SubscribeToEvent(E_WIDGETLOADED, HANDLER(JSUI, HandleWidgetLoaded));
  16. SubscribeToEvent(E_POPUPMENUSELECT, HANDLER(JSUI, HandlePopupMenuSelect));
  17. }
  18. JSUI::~JSUI()
  19. {
  20. }
  21. void JSUI::GatherWidgets(tb::TBWidget* widget, PODVector<tb::TBWidget*>& widgets)
  22. {
  23. if (widget->GetID() != TBID())
  24. widgets.Push(widget);
  25. for (TBWidget *n = widget->GetFirstChild(); n; n = n->GetNext())
  26. {
  27. GatherWidgets(n, widgets);
  28. }
  29. }
  30. void JSUI::HandleWidgetLoaded(StringHash eventType, VariantMap& eventData)
  31. {
  32. using namespace WidgetLoaded;
  33. UIWidget* widget = static_cast<UIWidget*>(eventData[P_WIDGET].GetPtr());
  34. if (!widget)
  35. return;
  36. void* heapptr = widget->JSGetHeapPtr();
  37. if (!heapptr)
  38. return;
  39. // a loaded widget recursively gathers children which have id's and
  40. // stashes them in an internal array, so that they don't go out of scope
  41. // for instance var button = window.getWidgetByID("reveal");
  42. // if we didn't stash, any callback on button wouldn't work if button went out
  43. // of scope, which isn't expected behavior (in JS you would think the button is
  44. // in some way attached to the window object)
  45. TBWidget* tbwidget = widget->GetInternalWidget();
  46. assert(tbwidget);
  47. PODVector<TBWidget*> widgets;
  48. GatherWidgets(tbwidget, widgets);
  49. UI* ui = GetSubsystem<UI>();
  50. duk_push_heapptr(ctx_, heapptr);
  51. duk_push_array(ctx_);
  52. unsigned arrayCount = 0;
  53. for (unsigned i = 0; i < widgets.Size(); i++)
  54. {
  55. UIWidget* o = ui->WrapWidget(widgets.At(i));
  56. if (!o)
  57. continue;
  58. js_push_class_object_instance(ctx_, o);
  59. duk_put_prop_index(ctx_, -2, arrayCount++);
  60. }
  61. duk_put_prop_string(ctx_, -2, "__child_widgets");
  62. duk_pop(ctx_);
  63. }
  64. void JSUI::HandlePopupMenuSelect(StringHash eventType, VariantMap& eventData)
  65. {
  66. using namespace PopupMenuSelect;
  67. UIButton* button = static_cast<UIButton*>(eventData[P_BUTTON].GetPtr());
  68. if (!button)
  69. return;
  70. void* heapptr = button->JSGetHeapPtr();
  71. if (!heapptr) // gc'd
  72. return;
  73. int top = duk_get_top(ctx_);
  74. duk_push_heapptr(ctx_, heapptr);
  75. duk_get_prop_string(ctx_, -1, "__popup_menu_callback");
  76. if (!duk_is_callable(ctx_, -1))
  77. {
  78. duk_pop_n(ctx_, 2);
  79. assert(top == duk_get_top(ctx_));
  80. return;
  81. }
  82. UI* ui = GetSubsystem<UI>();
  83. String id;
  84. ui->GetTBIDString(eventData[P_REFID].GetUInt(), id);
  85. duk_push_string(ctx_, id.CString());
  86. duk_insert(ctx_, -1);
  87. if (duk_pcall(ctx_, 1) != 0)
  88. {
  89. JSVM::GetJSVM(nullptr)->SendJSErrorEvent();
  90. }
  91. duk_pop_n(ctx_, 2);
  92. assert(top == duk_get_top(ctx_));
  93. }
  94. void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
  95. {
  96. using namespace WidgetEvent;
  97. UIWidget* widget = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr());
  98. if (!widget)
  99. return;
  100. void* heapptr = widget->JSGetHeapPtr();
  101. if (!heapptr)
  102. return;
  103. tb::EVENT_TYPE type = (tb::EVENT_TYPE) eventData[P_TYPE].GetUInt();
  104. if (type == tb::EVENT_TYPE_CLICK)
  105. {
  106. int top = duk_get_top(ctx_);
  107. duk_push_heapptr(ctx_, heapptr);
  108. duk_get_prop_string(ctx_, -1, "onClick");
  109. if (duk_is_callable(ctx_, -1)) {
  110. duk_call(ctx_, 0);
  111. }
  112. duk_pop_n(ctx_, 2);
  113. assert(top == duk_get_top(ctx_));
  114. return;
  115. }
  116. eventData[P_TYPE];
  117. eventData[P_X];
  118. eventData[P_Y];
  119. eventData[P_DELTAX];
  120. eventData[P_DELTAY];
  121. eventData[P_COUNT];
  122. eventData[P_KEY];
  123. eventData[P_SPECIALKEY];
  124. eventData[P_MODIFIERKEYS];
  125. eventData[P_ID];
  126. eventData[P_TOUCH];
  127. }
  128. }