Support out-parameter for strings

This commit is contained in:
Alexander Klingenbeck 2023-06-04 22:31:15 +02:00
parent 5c2cb695e1
commit 7e0c04020e
7 changed files with 141 additions and 72 deletions

View File

@ -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")

View File

@ -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
}

View File

@ -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

View File

@ -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 */

View File

@ -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();

View File

@ -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");

View File

@ -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;
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);
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;
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);
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;
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);
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;
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);
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),