void JSUI::HandleWidgetDeleted(StringHash eventType, VariantMap& eventData) { UIWidget* widget = static_cast<UIWidget*>(eventData[WidgetDeleted::P_WIDGET].GetPtr()); if (!widget->JSGetHeapPtr()) return; duk_push_global_stash(ctx_); duk_get_prop_string(ctx_, -1, "__jsui_widgetkeepalive"); // can't use instance as key, as this coerces to [Object] for // string property, pointer will be string representation of // address, so, unique key duk_push_pointer(ctx_, widget); duk_del_prop(ctx_, -2); duk_pop_2(ctx_); }
void JSUI::HandleWidgetLoaded(StringHash eventType, VariantMap& eventData) { using namespace WidgetLoaded; UIWidget* widget = static_cast<UIWidget*>(eventData[P_WIDGET].GetPtr()); if (!widget) return; void* heapptr = widget->JSGetHeapPtr(); if (!heapptr) return; TBWidget* tbwidget = widget->GetInternalWidget(); assert(tbwidget); // all widgets with id's are wrapped, so that event handlers are bubbled up properly // note that all js widget object representations are kept alive in HandleObjectAdded // when pushed into the VM PODVector<TBWidget*> widgets; GatherWidgets(tbwidget, widgets); UI* ui = GetSubsystem<UI>(); for (unsigned i = 0; i < widgets.Size(); i++) { UIWidget* o = ui->WrapWidget(widgets.At(i)); if (!o) continue; js_push_class_object_instance(ctx_, o); } }
void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData) { using namespace WidgetEvent; UIWidget* handler = static_cast<UIWidget*>(eventData[P_HANDLER].GetPtr()); UIWidget* target = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr()); if (!handler) return; void* handlerHeapPtr = handler->JSGetHeapPtr(); if (!handlerHeapPtr) return; // if we have a target, however no corresponding JS object return if (target && !target->JSGetHeapPtr()) return; tb::EVENT_TYPE type = (tb::EVENT_TYPE) eventData[P_TYPE].GetUInt(); if (type == tb::EVENT_TYPE_CHANGED) { int top = duk_get_top(ctx_); duk_push_heapptr(ctx_, handlerHeapPtr); duk_get_prop_string(ctx_, -1, "onChanged"); if (duk_is_callable(ctx_, -1)) { if (duk_pcall(ctx_, 0) != 0) { JSVM::GetJSVM(nullptr)->SendJSErrorEvent(); } else { if (duk_is_boolean(ctx_, -1) && duk_to_boolean(ctx_, -1)) eventData[P_HANDLED] = true; } } duk_pop_n(ctx_, 2); assert(top == duk_get_top(ctx_)); return; } // general event handler, bubbles to (wrapped) parent widgets unless handled (returns true) if (type == tb::EVENT_TYPE_CLICK) { int top = duk_get_top(ctx_); duk_push_heapptr(ctx_, handlerHeapPtr); duk_get_prop_string(ctx_, -1, "onEvent"); if (duk_is_callable(ctx_, -1)) { PushWidgetEventObject(eventData); duk_call(ctx_, 1); if (duk_is_boolean(ctx_, -1) && duk_to_boolean(ctx_, -1)) eventData[P_HANDLED] = true; } duk_pop_n(ctx_, 2); assert(top == duk_get_top(ctx_)); } // specific event handlers if (type == tb::EVENT_TYPE_CLICK && handler == target) { int top = duk_get_top(ctx_); duk_push_heapptr(ctx_, handlerHeapPtr); duk_get_prop_string(ctx_, -1, "onClick"); if (duk_is_callable(ctx_, -1)) { if (duk_pcall(ctx_, 0) != 0) { JSVM::GetJSVM(nullptr)->SendJSErrorEvent(); } else { if (duk_is_boolean(ctx_, -1) && duk_to_boolean(ctx_, -1)) eventData[P_HANDLED] = true; } } duk_pop_n(ctx_, 2); assert(top == duk_get_top(ctx_)); return; } }
void JSUI::PushWidgetEventObject(VariantMap& eventData) { using namespace WidgetEvent; // create the event object duk_push_object(ctx_); // target UIWidget* target = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr()); if (target) { assert(target->JSGetHeapPtr()); duk_push_heapptr(ctx_, target->JSGetHeapPtr()); } else { duk_push_null(ctx_); } duk_put_prop_string(ctx_, -2, "target"); duk_push_number(ctx_, (duk_double_t) eventData[P_TYPE].GetUInt()); duk_put_prop_string(ctx_, -2, "type"); duk_push_number(ctx_, (duk_double_t) eventData[P_X].GetInt()); duk_put_prop_string(ctx_, -2, "x"); duk_push_number(ctx_, (duk_double_t) eventData[P_Y].GetInt()); duk_put_prop_string(ctx_, -2, "y"); duk_push_number(ctx_, (duk_double_t) eventData[P_DELTAX].GetInt()); duk_put_prop_string(ctx_, -2, "deltaX"); duk_push_number(ctx_, (duk_double_t) eventData[P_DELTAX].GetInt()); duk_put_prop_string(ctx_, -2, "deltaY"); duk_push_number(ctx_, (duk_double_t) eventData[P_COUNT].GetInt()); duk_put_prop_string(ctx_, -2, "count"); duk_push_number(ctx_, (duk_double_t) eventData[P_KEY].GetInt()); duk_put_prop_string(ctx_, -2, "key"); duk_push_number(ctx_, (duk_double_t) eventData[P_SPECIALKEY].GetInt()); duk_put_prop_string(ctx_, -2, "specialKey"); duk_push_number(ctx_, (duk_double_t) eventData[P_MODIFIERKEYS].GetInt()); duk_put_prop_string(ctx_, -2, "modifierKeys"); duk_push_number(ctx_, (duk_double_t) eventData[P_MODIFIERKEYS].GetInt()); duk_put_prop_string(ctx_, -2, "modifierKeys"); String id = eventData[P_REFID].GetString(); duk_push_string(ctx_, id.CString() ); duk_put_prop_string(ctx_, -2, "refID"); duk_push_boolean(ctx_,eventData[P_TOUCH].GetBool() ? 1 : 0); duk_put_prop_string(ctx_, -2, "touch"); }