Created
June 21, 2021 17:28
-
-
Save nikki93/6e41ab5bc177209944aea99dc1041c95 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "core.hh" | |
// Elements | |
JS_DEFINE(void, JS_uiElemOpenStart, (const char *tag), | |
{ IncrementalDOM.elementOpenStart(UTF8ToString(tag)); }) | |
JS_DEFINE(void, JS_uiElemOpenStartKeyInt, (const char *tag, int key), | |
{ IncrementalDOM.elementOpenStart(UTF8ToString(tag), key); }) | |
JS_DEFINE(void, JS_uiElemOpenStartKeyString, (const char *tag, const char *key), | |
{ IncrementalDOM.elementOpenStart(UTF8ToString(tag), UTF8ToString(key)); }) | |
JS_DEFINE(void, JS_uiElemOpenEnd, (), { IncrementalDOM.elementOpenEnd(); }) | |
JS_DEFINE( | |
void, JS_uiElemClose, (const char *tag), { IncrementalDOM.elementClose(UTF8ToString(tag)); }) | |
JS_DEFINE(int, JS_uiGetElemToken, (), { | |
const target = IncrementalDOM.currentElement(); | |
let token = target.__UIToken; | |
if (!token) { | |
token = UI.nextToken++; | |
target.__UIToken = token; | |
} | |
return token; | |
}) | |
// Attributes | |
JS_DEFINE(void, JS_uiAttrInt, (const char *name, int value), | |
{ IncrementalDOM.attr(UTF8ToString(name), value); }) | |
JS_DEFINE(void, JS_uiAttrFloat, (const char *name, float value), | |
{ IncrementalDOM.attr(UTF8ToString(name), value); }) | |
JS_DEFINE(void, JS_uiAttrDouble, (const char *name, double value), | |
{ IncrementalDOM.attr(UTF8ToString(name), value); }) | |
JS_DEFINE(void, JS_uiAttrString, (const char *name, const char *value), | |
{ IncrementalDOM.attr(UTF8ToString(name), UTF8ToString(value)); }) | |
JS_DEFINE( | |
void, JS_uiAttrEmpty, (const char *name), { IncrementalDOM.attr(UTF8ToString(name), ""); }) | |
JS_DEFINE(void, JS_uiAttrClass, (const char *value), | |
{ IncrementalDOM.attr("class", UTF8ToString(value)); }) | |
// Text | |
JS_DEFINE(void, JS_uiText, (const char *value), { IncrementalDOM.text(UTF8ToString(value)); }) | |
// Events | |
JS_DEFINE(int, JS_uiGetEventCount, (const char *type), { | |
const typeStr = UTF8ToString(type); | |
const target = IncrementalDOM.currentElement(); | |
if (!target.__UIIsEventListenerSetup) { | |
UI.setupEventListener(target, typeStr); | |
target.__UIIsEventListenerSetup = true; | |
} | |
const counts = window.UI.eventCounts.get(target); | |
if (typeof(counts) == "undefined") { | |
return 0; | |
} | |
const count = counts[typeStr]; | |
if (typeof(count) == "undefined") { | |
return 0; | |
} | |
delete counts[typeStr]; | |
return count; | |
}) | |
JS_DEFINE(void, JS_uiClearEventCounts, (), { window.UI.eventCounts = new WeakMap(); }) | |
JS_DEFINE(bool, JS_uiIsKeyboardCaptured, (), { return !!window.UI.isKeyboardCaptured; }) | |
// Values | |
JS_DEFINE(char *, JS_uiGetValue, (), { | |
let value = IncrementalDOM.currentElement().value; | |
if (!value) { | |
value = ""; | |
} | |
return allocate(intArrayFromString(value), ALLOC_NORMAL); | |
}); | |
JS_DEFINE(void, JS_uiSetValue, (const char *value), | |
{ IncrementalDOM.currentElement().value = UTF8ToString(value); }); | |
// Patch | |
JS_EXPORT void JS_uiCallPatchFunc() { | |
if (uiPatchState.wrapper) { | |
uiPatchState.wrapper(); | |
uiPatchState = {}; | |
} | |
} | |
JS_DEFINE(void, JS_uiPatch, (const char *id), { | |
const el = document.getElementById(UTF8ToString(id)); | |
if (el) { | |
IncrementalDOM.patch(el, Module._JS_uiCallPatchFunc.bind(Module)); | |
} | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "core.hh" | |
// | |
// JS interface | |
// | |
// Elements | |
extern "C" void JS_uiElemOpenStart(const char *tag); | |
extern "C" void JS_uiElemOpenStartKeyInt(const char *tag, int key); | |
extern "C" void JS_uiElemOpenStartKeyString(const char *tag, const char *key); | |
extern "C" void JS_uiElemOpenEnd(); | |
extern "C" void JS_uiElemClose(const char *tag); | |
extern "C" int JS_uiGetElemToken(); | |
// Attributes | |
extern "C" void JS_uiAttrInt(const char *name, int value); | |
extern "C" void JS_uiAttrFloat(const char *name, float value); | |
extern "C" void JS_uiAttrDouble(const char *name, double value); | |
extern "C" void JS_uiAttrString(const char *name, const char *value); | |
extern "C" void JS_uiAttrEmpty(const char *name); | |
extern "C" void JS_uiAttrClass(const char *value); | |
// Text | |
extern "C" void JS_uiText(const char *value); | |
// Events | |
extern "C" int JS_uiGetEventCount(const char *type); | |
extern "C" void JS_uiClearEventCounts(); | |
extern "C" bool JS_uiIsKeyboardCaptured(); | |
// Value | |
extern "C" char *JS_uiGetValue(); | |
extern "C" void JS_uiSetValue(const char *value); | |
// Patch | |
extern "C" void JS_uiPatch(const char *id); | |
// | |
// Elements | |
// | |
struct UIElem { | |
const char *tag = "div"; | |
bool ended = false; | |
~UIElem() { | |
end(); | |
JS_uiElemClose(tag); | |
} | |
UIElem &operator()(const char *attrName, int value) { | |
JS_uiAttrInt(attrName, value); | |
return *this; | |
} | |
UIElem &operator()(const char *attrName, float value) { | |
JS_uiAttrFloat(attrName, value); | |
return *this; | |
} | |
UIElem &operator()(const char *attrName, double value) { | |
JS_uiAttrDouble(attrName, value); | |
return *this; | |
} | |
UIElem &operator()(const char *attrName, const char *value) { | |
JS_uiAttrString(attrName, value); | |
return *this; | |
} | |
UIElem &operator()(const char *attrName, char *value) { | |
return operator()(attrName, (const char *)value); | |
} | |
UIElem &operator()(const char *attrName, bool value) { | |
if (value) { | |
JS_uiAttrEmpty(attrName); | |
} | |
return *this; | |
} | |
UIElem &operator()(const char *klass) { | |
JS_uiAttrClass(klass); | |
return *this; | |
} | |
UIElem &operator()(char *klass) { | |
JS_uiAttrClass(klass); | |
return *this; | |
} | |
UIElem &operator()(const char *eventName, auto &&f) { | |
end(); | |
auto count = JS_uiGetEventCount(eventName); | |
for (auto i = 0; i < count; ++i) { | |
callEventHandler(f); | |
} | |
return *this; | |
} | |
UIElem &operator()(const char *eventName, rl::KeyboardKey key, auto &&f) { | |
if (!JS_uiIsKeyboardCaptured() && rl::IsKeyReleased(key)) { | |
callEventHandler(f); | |
} | |
return operator()(eventName, std::forward<decltype(f)>(f)); | |
} | |
UIElem &operator()(const char *eventName, rl::KeyboardKey mod, rl::KeyboardKey key, auto &&f) { | |
if (!JS_uiIsKeyboardCaptured() | |
&& ((rl::IsKeyDown(mod) && rl::IsKeyReleased(key)) | |
|| (rl::IsKeyReleased(mod) && rl::IsKeyDown(key)))) { | |
callEventHandler(f); | |
} | |
return operator()(eventName, std::forward<decltype(f)>(f)); | |
} | |
UIElem &operator()(auto &&f) { | |
end(); | |
f(); | |
return *this; | |
} | |
void end() { | |
if (!ended) { | |
JS_uiElemOpenEnd(); | |
ended = true; | |
} | |
} | |
template<typename F> | |
void callEventHandler(F &&f) { | |
if constexpr (std::is_invocable_v<F, const char *>) { | |
auto value = JS_uiGetValue(); | |
if constexpr (std::is_convertible_v<std::invoke_result_t<F, const char *>, const char *>) { | |
JS_uiSetValue(f(value)); | |
} else { | |
f(value); | |
} | |
std::free(value); | |
} else { | |
f(); | |
} | |
} | |
}; | |
inline UIElem ui(const char *tag) { | |
JS_uiElemOpenStart(tag); | |
return { .tag = tag }; | |
} | |
inline UIElem ui(const char *tag, int key) { | |
JS_uiElemOpenStartKeyInt(tag, key); | |
return { .tag = tag }; | |
} | |
inline UIElem ui(const char *tag, const char *key) { | |
JS_uiElemOpenStartKeyString(tag, key); | |
return { .tag = tag }; | |
} | |
// | |
// Text | |
// | |
inline void uiText(const char *format, auto &&...args) { | |
JS_uiText(bprint<1024>(format, std::forward<decltype(args)>(args)...)); | |
} | |
inline void uiText(const char *msg) { | |
JS_uiText(msg); | |
} | |
// | |
// Patch | |
// | |
inline struct UIPatchState { | |
void (*wrapper)() = nullptr; | |
void *func = nullptr; | |
} uiPatchState; | |
template<typename F> | |
inline void uiPatch(const char *id, F &&f) { | |
#ifdef __EMSCRIPTEN__ | |
uiPatchState.func = (void *)&f; | |
uiPatchState.wrapper = []() { | |
if (uiPatchState.func) { | |
auto &f = *static_cast<F *>(uiPatchState.func); | |
f(); | |
} | |
}; | |
JS_uiPatch(id); | |
uiPatchState = {}; | |
#else | |
f(); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment