diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 1d06683..4b5f9ae 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -501,14 +501,17 @@ function main(){ const param = fun!.params![index] param.binding = { jsType: `{ ${param.name}: number }`, - customConverter: gen => { + customConverter: (gen,src) => { + gen.declare(param.name, param.type, false, "NULL"); gen.declare(param.name+"_out", param.type.replace(" *","")) - gen.declare(param.name, param.type, false, "&"+param.name+"_out") - gen.call("JS_GetPropertyStr", ["ctx","argv["+index+"]", '"'+param.name+'"'], { name: param.name+"_js", type: "JSValue" }) - gen.call("JS_ToInt32", ["ctx",param.name,param.name+"_js"]) + const body = gen.if("!JS_IsNull("+src+")") + body.statement(param.name + " = &" + param.name + "_out") + body.call("JS_GetPropertyStr", ["ctx",src, '"'+param.name+'"'], { name: param.name+"_js", type: "JSValue" }) + body.call("JS_ToInt32", ["ctx",param.name,param.name+"_js"]) }, - customCleanup: gen => { - gen.call("JS_SetPropertyStr", ["ctx", "argv["+index+"]", `"${param.name}"`, "JS_NewInt32(ctx,"+param.name+"_out)"]) + customCleanup: (gen,src) => { + const body = gen.if("!JS_IsNull("+src+")") + body.call("JS_SetPropertyStr", ["ctx", src, `"${param.name}"`, "JS_NewInt32(ctx,"+param.name+"_out)"]) } } } @@ -518,8 +521,8 @@ function main(){ const param = fun!.params![index] param.binding = { jsType: `{ ${param.name}: string }`, - customConverter: gen => { - gen.call("JS_GetPropertyStr", ["ctx","argv["+index+"]", '"'+param.name+'"'], { name: param.name+"_js", type: "JSValue" }) + customConverter: (gen,src) => { + gen.call("JS_GetPropertyStr", ["ctx",src, '"'+param.name+'"'], { name: param.name+"_js", type: "JSValue" }) gen.declare(param.name+"_len", "size_t"); gen.call("JS_ToCStringLen",["ctx", "&"+param.name+"_len", param.name+"_js"], { name: param.name+"_val", type: "const char *" }) gen.call("memcpy", ["(void *)textbuffer", param.name+"_val", param.name+"_len"]) @@ -527,9 +530,9 @@ function main(){ gen.declare(param.name, param.type, false, "textbuffer"); gen.declare(lenParam.name, lenParam.type, false, "4096") }, - customCleanup: gen => { + customCleanup: (gen, src) => { gen.jsCleanUpParameter("const char *", param.name + "_val") - gen.call("JS_SetPropertyStr", ["ctx", "argv["+index+"]", `"${param.name}"`, "JS_NewString(ctx,"+param.name+")"]) + gen.call("JS_SetPropertyStr", ["ctx", src, `"${param.name}"`, "JS_NewString(ctx,"+param.name+")"]) } } @@ -544,7 +547,10 @@ function main(){ ignore("GuiListViewEx") setOutParamString(getFunction(api.functions, "GuiTextBox")!, 1,2) //ignore("GuiTextBox") - ignore("GuiTextInputBox") + const gtib = getFunction(api.functions, "GuiTextInputBox")! + setOutParamString(gtib,4,5) + setOutParam(gtib, 6) + //setOutParam(getFunction(api.functions, "GuiTextInputBox")!, 6) ignore("GuiTabBar") ignore("GuiGetIcons") diff --git a/bindings/src/interfaces.ts b/bindings/src/interfaces.ts index 35e0dc9..bc0716a 100644 --- a/bindings/src/interfaces.ts +++ b/bindings/src/interfaces.ts @@ -21,8 +21,8 @@ export interface FuncBindingOptions { export interface ParamBindingOptions { ignore?: boolean, - customConverter?: (gen: QuickJsGenerator) => void, - customCleanup?: (gen: QuickJsGenerator) => void, + customConverter?: (gen: QuickJsGenerator, src: string) => void, + customCleanup?: (gen: QuickJsGenerator, src: string) => void, jsType?: string, typeAlias?: string } diff --git a/bindings/src/raylib-header.ts b/bindings/src/raylib-header.ts index 51511f5..4ea5a84 100644 --- a/bindings/src/raylib-header.ts +++ b/bindings/src/raylib-header.ts @@ -31,18 +31,20 @@ export class RayLibHeader extends QuickJsHeader { if(options.before) options.before(fun) // read parameters api.params = api.params || [] - for (let i = 0; i < api.params.length; i++) { - if(api.params[i]?.binding?.ignore) continue; - const para = api.params[i] - if(para.binding?.customConverter) para.binding.customConverter(fun) + const activeParams = api.params.filter(x => !x.binding?.ignore) + + for (let i = 0; i < activeParams.length; i++) { + const para = activeParams[i] + if(para.binding?.customConverter) para.binding.customConverter(fun, "argv["+i+"]") else fun.jsToC(para.type,para.name,"argv["+i+"]", this.structLookup, false, para.binding?.typeAlias) } // call c function if(options.customizeCall) fun.line(options.customizeCall) else fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"}) // clean up parameters - for (const param of api.params) { - if(param.binding?.customCleanup) param.binding.customCleanup(fun) + for (let i = 0; i < activeParams.length; i++) { + const param = activeParams[i] + if(param.binding?.customCleanup) param.binding.customCleanup(fun, "argv["+i+"]") else fun.jsCleanUpParameter(param.type, param.name) } // return result diff --git a/examples/lib.raylib.d.ts b/examples/lib.raylib.d.ts index cc2e668..b6e8709 100644 --- a/examples/lib.raylib.d.ts +++ b/examples/lib.raylib.d.ts @@ -1502,6 +1502,8 @@ declare function guiGrid(bounds: Rectangle, text: string, spacing: number, subdi declare function guiListView(bounds: Rectangle, text: string, scrollIndex: { scrollIndex: number }, active: number): number; /** Message Box control, displays a message */ declare function guiMessageBox(bounds: Rectangle, title: string, message: string, buttons: string): number; +/** Text Input Box control, ask for text, supports secret */ +declare function guiTextInputBox(bounds: Rectangle, title: string, message: string, buttons: string, text: { text: string }, secretViewActive: { secretViewActive: number }): number; /** Color Picker control (multiple color controls) */ declare function guiColorPicker(bounds: Rectangle, text: string, color: Color): Color; /** Color Panel control */ diff --git a/examples/raygui/controls_test_suite.js b/examples/raygui/controls_test_suite.js index cba70ed..3284b9b 100644 --- a/examples/raygui/controls_test_suite.js +++ b/examples/raygui/controls_test_suite.js @@ -57,7 +57,7 @@ let viewScroll = new Vector2(0,0); let exitWindow = false; let showMessageBox = false; -let textInput = ""; +let textInput = { text: "" }; let showTextInputBox = false; let textInputFileName = ""; @@ -105,7 +105,7 @@ while (!exitWindow) // Detect window close button or ESC key if (guiSpinner(new Rectangle(25, 135, 125, 30), null, spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode; if (guiValueBox(new Rectangle(25, 175, 125, 30), null, valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode; guiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - if (guiTextBox(new Rectangle(25, 215, 125, 30), textBoxText, 64, textBoxEditMode)) textBoxEditMode = !textBoxEditMode; + if (guiTextBox(new Rectangle(25, 215, 125, 30), textBoxText, textBoxEditMode)) textBoxEditMode = !textBoxEditMode; guiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -162,24 +162,23 @@ while (!exitWindow) // Detect window close button or ESC key else if (result == 1) exitWindow = true; } - // if (showTextInputBox) - // { - // drawRectangle(0, 0, getScreenWidth(), getScreenHeight(), fade(RAYWHITE, 0.8)); - // let result = guiTextInputBox(new Rectangle(getScreenWidth()/2 - 120, getScreenHeight()/2 - 60, 240, 140), "Save", guiIconText(ICON_FILE_SAVE, "Save file as..."), "Ok;Cancel", textInput, 255, null); + if (showTextInputBox) + { + drawRectangle(0, 0, getScreenWidth(), getScreenHeight(), fade(RAYWHITE, 0.8)); + let result = guiTextInputBox(new Rectangle(getScreenWidth()/2 - 120, getScreenHeight()/2 - 60, 240, 140), "Save", guiIconText(ICON_FILE_SAVE, "Save file as..."), "Ok;Cancel", textInput, null); - // if (result == 1) - // { - // // TODO: Validate textInput value and save + if (result == 1) + { + // TODO: Validate textInput value and save + textInputFileName = textInput.text + } - // strcpy(textInputFileName, textInput); - // } - - // if ((result == 0) || (result == 1) || (result == 2)) - // { - // showTextInputBox = false; - // strcpy(textInput, "\0"); - // } - // } + if ((result == 0) || (result == 1) || (result == 2)) + { + showTextInputBox = false; + textInput.text = "" + } + } //---------------------------------------------------------------------------------- endDrawing(); diff --git a/generate-bindings.js b/generate-bindings.js index 772c307..2b37481 100644 --- a/generate-bindings.js +++ b/generate-bindings.js @@ -660,12 +660,11 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { options.before(fun); // read parameters api.params = api.params || []; - for (let i = 0; i < api.params.length; i++) { - if (api.params[i]?.binding?.ignore) - continue; - const para = api.params[i]; + const activeParams = api.params.filter(x => !x.binding?.ignore); + for (let i = 0; i < activeParams.length; i++) { + const para = activeParams[i]; if (para.binding?.customConverter) - para.binding.customConverter(fun); + para.binding.customConverter(fun, "argv[" + i + "]"); else fun.jsToC(para.type, para.name, "argv[" + i + "]", this.structLookup, false, para.binding?.typeAlias); } @@ -675,9 +674,10 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { else fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : { type: api.returnType, name: "returnVal" }); // clean up parameters - for (const param of api.params) { + for (let i = 0; i < activeParams.length; i++) { + const param = activeParams[i]; if (param.binding?.customCleanup) - param.binding.customCleanup(fun); + param.binding.customCleanup(fun, "argv[" + i + "]"); else fun.jsCleanUpParameter(param.type, param.name); } @@ -1387,14 +1387,17 @@ function main() { const param = fun.params[index]; param.binding = { jsType: `{ ${param.name}: number }`, - customConverter: gen => { + customConverter: (gen, src) => { + gen.declare(param.name, param.type, false, "NULL"); gen.declare(param.name + "_out", param.type.replace(" *", "")); - gen.declare(param.name, param.type, false, "&" + param.name + "_out"); - gen.call("JS_GetPropertyStr", ["ctx", "argv[" + index + "]", '"' + param.name + '"'], { name: param.name + "_js", type: "JSValue" }); - gen.call("JS_ToInt32", ["ctx", param.name, param.name + "_js"]); + const body = gen.if("!JS_IsNull(" + src + ")"); + body.statement(param.name + " = &" + param.name + "_out"); + body.call("JS_GetPropertyStr", ["ctx", src, '"' + param.name + '"'], { name: param.name + "_js", type: "JSValue" }); + body.call("JS_ToInt32", ["ctx", param.name, param.name + "_js"]); }, - customCleanup: gen => { - gen.call("JS_SetPropertyStr", ["ctx", "argv[" + index + "]", `"${param.name}"`, "JS_NewInt32(ctx," + param.name + "_out)"]); + customCleanup: (gen, src) => { + const body = gen.if("!JS_IsNull(" + src + ")"); + body.call("JS_SetPropertyStr", ["ctx", src, `"${param.name}"`, "JS_NewInt32(ctx," + param.name + "_out)"]); } }; }; @@ -1404,8 +1407,8 @@ function main() { const param = fun.params[index]; param.binding = { jsType: `{ ${param.name}: string }`, - customConverter: gen => { - gen.call("JS_GetPropertyStr", ["ctx", "argv[" + index + "]", '"' + param.name + '"'], { name: param.name + "_js", type: "JSValue" }); + customConverter: (gen, src) => { + gen.call("JS_GetPropertyStr", ["ctx", src, '"' + param.name + '"'], { name: param.name + "_js", type: "JSValue" }); gen.declare(param.name + "_len", "size_t"); gen.call("JS_ToCStringLen", ["ctx", "&" + param.name + "_len", param.name + "_js"], { name: param.name + "_val", type: "const char *" }); gen.call("memcpy", ["(void *)textbuffer", param.name + "_val", param.name + "_len"]); @@ -1413,9 +1416,9 @@ function main() { gen.declare(param.name, param.type, false, "textbuffer"); gen.declare(lenParam.name, lenParam.type, false, "4096"); }, - customCleanup: gen => { + customCleanup: (gen, src) => { gen.jsCleanUpParameter("const char *", param.name + "_val"); - gen.call("JS_SetPropertyStr", ["ctx", "argv[" + index + "]", `"${param.name}"`, "JS_NewString(ctx," + param.name + ")"]); + gen.call("JS_SetPropertyStr", ["ctx", src, `"${param.name}"`, "JS_NewString(ctx," + param.name + ")"]); } }; }; @@ -1427,7 +1430,9 @@ function main() { ignore("GuiListViewEx"); setOutParamString(getFunction(api.functions, "GuiTextBox"), 1, 2); //ignore("GuiTextBox") - ignore("GuiTextInputBox"); + const gtib = getFunction(api.functions, "GuiTextInputBox"); + setOutParamString(gtib, 4, 5); + setOutParam(gtib, 6); //setOutParam(getFunction(api.functions, "GuiTextInputBox")!, 6) ignore("GuiTabBar"); ignore("GuiGetIcons"); diff --git a/src/bindings/js_raylib_core.h b/src/bindings/js_raylib_core.h index cbca14f..ef7e3db 100644 --- a/src/bindings/js_raylib_core.h +++ b/src/bindings/js_raylib_core.h @@ -8913,14 +8913,19 @@ static JSValue js_guiDropdownBox(JSContext * ctx, JSValueConst this_val, int arg if(bounds_ptr == NULL) return JS_EXCEPTION; Rectangle bounds = *bounds_ptr; const char * text = JS_IsNull(argv[1]) ? NULL : (const char *)JS_ToCString(ctx, argv[1]); + int * active = NULL; int active_out; - int * active = &active_out; - JSValue active_js = JS_GetPropertyStr(ctx, argv[2], "active"); - JS_ToInt32(ctx, active, active_js); + if(!JS_IsNull(argv[2])) { + active = &active_out; + JSValue active_js = JS_GetPropertyStr(ctx, argv[2], "active"); + JS_ToInt32(ctx, active, active_js); + } bool editMode = JS_ToBool(ctx, argv[3]); bool returnVal = GuiDropdownBox(bounds, text, active, editMode); JS_FreeCString(ctx, text); - JS_SetPropertyStr(ctx, argv[2], "active", JS_NewInt32(ctx,active_out)); + if(!JS_IsNull(argv[2])) { + JS_SetPropertyStr(ctx, argv[2], "active", JS_NewInt32(ctx,active_out)); + } JSValue ret = JS_NewBool(ctx, returnVal); return ret; } @@ -8930,10 +8935,13 @@ static JSValue js_guiSpinner(JSContext * ctx, JSValueConst this_val, int argc, J if(bounds_ptr == NULL) return JS_EXCEPTION; Rectangle bounds = *bounds_ptr; const char * text = JS_IsNull(argv[1]) ? NULL : (const char *)JS_ToCString(ctx, argv[1]); + int * value = NULL; int value_out; - int * value = &value_out; - JSValue value_js = JS_GetPropertyStr(ctx, argv[2], "value"); - JS_ToInt32(ctx, value, value_js); + if(!JS_IsNull(argv[2])) { + value = &value_out; + JSValue value_js = JS_GetPropertyStr(ctx, argv[2], "value"); + JS_ToInt32(ctx, value, value_js); + } int minValue; JS_ToInt32(ctx, &minValue, argv[3]); int maxValue; @@ -8941,7 +8949,9 @@ static JSValue js_guiSpinner(JSContext * ctx, JSValueConst this_val, int argc, J bool editMode = JS_ToBool(ctx, argv[5]); bool returnVal = GuiSpinner(bounds, text, value, minValue, maxValue, editMode); JS_FreeCString(ctx, text); - JS_SetPropertyStr(ctx, argv[2], "value", JS_NewInt32(ctx,value_out)); + if(!JS_IsNull(argv[2])) { + JS_SetPropertyStr(ctx, argv[2], "value", JS_NewInt32(ctx,value_out)); + } JSValue ret = JS_NewBool(ctx, returnVal); return ret; } @@ -8951,10 +8961,13 @@ static JSValue js_guiValueBox(JSContext * ctx, JSValueConst this_val, int argc, if(bounds_ptr == NULL) return JS_EXCEPTION; Rectangle bounds = *bounds_ptr; const char * text = JS_IsNull(argv[1]) ? NULL : (const char *)JS_ToCString(ctx, argv[1]); + int * value = NULL; int value_out; - int * value = &value_out; - JSValue value_js = JS_GetPropertyStr(ctx, argv[2], "value"); - JS_ToInt32(ctx, value, value_js); + if(!JS_IsNull(argv[2])) { + value = &value_out; + JSValue value_js = JS_GetPropertyStr(ctx, argv[2], "value"); + JS_ToInt32(ctx, value, value_js); + } int minValue; JS_ToInt32(ctx, &minValue, argv[3]); int maxValue; @@ -8962,7 +8975,9 @@ static JSValue js_guiValueBox(JSContext * ctx, JSValueConst this_val, int argc, bool editMode = JS_ToBool(ctx, argv[5]); bool returnVal = GuiValueBox(bounds, text, value, minValue, maxValue, editMode); JS_FreeCString(ctx, text); - JS_SetPropertyStr(ctx, argv[2], "value", JS_NewInt32(ctx,value_out)); + if(!JS_IsNull(argv[2])) { + JS_SetPropertyStr(ctx, argv[2], "value", JS_NewInt32(ctx,value_out)); + } JSValue ret = JS_NewBool(ctx, returnVal); return ret; } @@ -8978,7 +8993,7 @@ static JSValue js_guiTextBox(JSContext * ctx, JSValueConst this_val, int argc, J textbuffer[text_len] = 0; char * text = textbuffer; int textSize = 4096; - bool editMode = JS_ToBool(ctx, argv[3]); + bool editMode = JS_ToBool(ctx, argv[2]); bool returnVal = GuiTextBox(bounds, text, textSize, editMode); JS_FreeCString(ctx, text_val); JS_SetPropertyStr(ctx, argv[1], "text", JS_NewString(ctx,text)); @@ -9096,15 +9111,20 @@ static JSValue js_guiListView(JSContext * ctx, JSValueConst this_val, int argc, if(bounds_ptr == NULL) return JS_EXCEPTION; Rectangle bounds = *bounds_ptr; const char * text = JS_IsNull(argv[1]) ? NULL : (const char *)JS_ToCString(ctx, argv[1]); + int * scrollIndex = NULL; int scrollIndex_out; - int * scrollIndex = &scrollIndex_out; - JSValue scrollIndex_js = JS_GetPropertyStr(ctx, argv[2], "scrollIndex"); - JS_ToInt32(ctx, scrollIndex, scrollIndex_js); + if(!JS_IsNull(argv[2])) { + scrollIndex = &scrollIndex_out; + JSValue scrollIndex_js = JS_GetPropertyStr(ctx, argv[2], "scrollIndex"); + JS_ToInt32(ctx, scrollIndex, scrollIndex_js); + } int active; JS_ToInt32(ctx, &active, argv[3]); int returnVal = GuiListView(bounds, text, scrollIndex, active); JS_FreeCString(ctx, text); - JS_SetPropertyStr(ctx, argv[2], "scrollIndex", JS_NewInt32(ctx,scrollIndex_out)); + if(!JS_IsNull(argv[2])) { + JS_SetPropertyStr(ctx, argv[2], "scrollIndex", JS_NewInt32(ctx,scrollIndex_out)); + } JSValue ret = JS_NewInt32(ctx, returnVal); return ret; } @@ -9124,6 +9144,40 @@ static JSValue js_guiMessageBox(JSContext * ctx, JSValueConst this_val, int argc return ret; } +static JSValue js_guiTextInputBox(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + Rectangle* bounds_ptr = (Rectangle*)JS_GetOpaque2(ctx, argv[0], js_Rectangle_class_id); + if(bounds_ptr == NULL) return JS_EXCEPTION; + Rectangle bounds = *bounds_ptr; + const char * title = JS_IsNull(argv[1]) ? NULL : (const char *)JS_ToCString(ctx, argv[1]); + const char * message = JS_IsNull(argv[2]) ? NULL : (const char *)JS_ToCString(ctx, argv[2]); + const char * buttons = JS_IsNull(argv[3]) ? NULL : (const char *)JS_ToCString(ctx, argv[3]); + JSValue text_js = JS_GetPropertyStr(ctx, argv[4], "text"); + size_t text_len; + const char * text_val = JS_ToCStringLen(ctx, &text_len, text_js); + memcpy((void *)textbuffer, text_val, text_len); + textbuffer[text_len] = 0; + char * text = textbuffer; + int textMaxSize = 4096; + int * secretViewActive = NULL; + int secretViewActive_out; + if(!JS_IsNull(argv[5])) { + secretViewActive = &secretViewActive_out; + JSValue secretViewActive_js = JS_GetPropertyStr(ctx, argv[5], "secretViewActive"); + JS_ToInt32(ctx, secretViewActive, secretViewActive_js); + } + int returnVal = GuiTextInputBox(bounds, title, message, buttons, text, textMaxSize, secretViewActive); + JS_FreeCString(ctx, title); + JS_FreeCString(ctx, message); + JS_FreeCString(ctx, buttons); + JS_FreeCString(ctx, text_val); + JS_SetPropertyStr(ctx, argv[4], "text", JS_NewString(ctx,text)); + if(!JS_IsNull(argv[5])) { + JS_SetPropertyStr(ctx, argv[5], "secretViewActive", JS_NewInt32(ctx,secretViewActive_out)); + } + JSValue ret = JS_NewInt32(ctx, returnVal); + return ret; +} + static JSValue js_guiColorPicker(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { Rectangle* bounds_ptr = (Rectangle*)JS_GetOpaque2(ctx, argv[0], js_Rectangle_class_id); if(bounds_ptr == NULL) return JS_EXCEPTION; @@ -10248,6 +10302,7 @@ static const JSCFunctionListEntry js_raylib_core_funcs[] = { JS_CFUNC_DEF("guiGrid",4,js_guiGrid), JS_CFUNC_DEF("guiListView",4,js_guiListView), JS_CFUNC_DEF("guiMessageBox",4,js_guiMessageBox), + JS_CFUNC_DEF("guiTextInputBox",6,js_guiTextInputBox), JS_CFUNC_DEF("guiColorPicker",3,js_guiColorPicker), JS_CFUNC_DEF("guiColorPanel",3,js_guiColorPanel), JS_CFUNC_DEF("guiColorBarAlpha",3,js_guiColorBarAlpha),