Index: trunk/src/Makefile.dep =================================================================== --- trunk/src/Makefile.dep (revision 36178) +++ trunk/src/Makefile.dep (revision 36179) @@ -352,8 +352,8 @@ data.h undo.h ../src_3rd/libuundo/uundo.h undo_old.h \ ../src_plugins/dialogs/dlg_library.h \ ../src_plugins/dialogs/adialogs_conf.h \ - ../src_plugins/dialogs/dlg_library_param.h \ - ../src_plugins/dialogs/dlg_library_param.c + ../src_3rd/rnd_inclib/dialogs/dlg_library_param.h \ + ../src_3rd/rnd_inclib/dialogs/dlg_library_param.c ../src_plugins/dialogs/dlg_loadsave.o: \ ../src_plugins/dialogs/dlg_loadsave.c ../config.h board.h vtroutestyle.h \ attrib.h global_typedefs.h layer.h globalconst.h obj_common.h flag.h \ Index: trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.c =================================================================== --- trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.c (nonexistent) +++ trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.c (revision 36179) @@ -0,0 +1,634 @@ +/* + * COPYRIGHT + * + * pcb-rnd, interactive printed circuit board design + * Copyright (C) 2017,2019,2020 Tibor 'Igor2' Palinkas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Contact: + * Project page: http://repo.hu/projects/pcb-rnd + * lead developer: http://repo.hu/projects/pcb-rnd/contact.html + * mailing list: pcb-rnd (at) list.repo.hu (send "subscribe") + */ + +#include + +static void library_param_close_cb(void *caller_data, rnd_hid_attr_ev_t ev) +{ + library_param_ctx_t *ctx = caller_data; + htsi_entry_t *e; + + gds_uninit(&ctx->descr); + free(ctx->help_params); + ctx->help_params = NULL; + + for(e = htsi_first(&ctx->param_names); e != NULL; e = htsi_next(&ctx->param_names, e)) + free(e->key); + htsi_uninit(&ctx->param_names); + if (ctx->pactive) { + ctx->pactive = 0; + RND_DAD_FREE(ctx->pdlg); + } + update_edit_button(ctx->lib_ctx); +} + +#define colsplit() \ +do { \ + col = strchr(col, ':'); \ + if (col != NULL) { \ + *col = '\0'; \ + col++; \ + } \ +} while(0) + +static void set_attr(library_param_ctx_t *ctx, int pidx, char *val) +{ + rnd_hid_attr_val_t hv; + rnd_hid_attribute_t *a = &ctx->pdlg[ctx->pwid[pidx]]; + const char **s; + char *desc; + int vlen, len, n; + + switch(a->type) { + case RND_HATT_ENUM: + hv.lng = 0; /* fallback in case the loop doesn't find any match */ + vlen = strlen(val); + for(n = 0, s = a->wdata; *s != NULL; s++,n++) { + desc = strstr(*s, " ("); + if (desc != NULL) + len = desc - *s; + else + len = strlen(*s); + if ((len == vlen) && (strncmp(*s, val, len) == 0)) { + hv.lng = n; + break; + } + } + break; + case RND_HATT_STRING: + hv.str = val; + break; + case RND_HATT_BOOL: + if ((val == NULL) || (*val == '\0')) + return; + hv.lng = \ + (*val == '1') || (*val == 't') || (*val == 'T') || (*val == 'y') || (*val == 'Y') || \ + (((val[0] == 'o') || (val[0] == 'O')) && ((val[1] == 'n') || (val[1] == 'N'))); + break; + case RND_HATT_COORD: + case RND_HATT_END: /* compound widget for the spinbox! */ + hv.crd = rnd_get_value_ex(val, NULL, NULL, NULL, "mil", NULL); + break; + default: + assert(!"set_attr() can't set non-data field!\n"); + return; + } + rnd_gui->attr_dlg_set_value(ctx->pdlg_hid_ctx, ctx->pwid[pidx], &hv); +} + +static void library_param_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_inp); + +#define pre_append() \ +do { \ + if (help_def != NULL) { \ + if (help != NULL) { \ + char *tmp = rnd_concat(help, "\nDefault: ", help_def, NULL); \ + free(help); \ + free(help_def); \ + help = tmp; \ + } \ + else \ + help = help_def; \ + help_def = NULL; \ + } \ +} while(0) + +#define post_append() \ +do { \ + vtp0_uninit(&curr_enum); \ + free(name); name = NULL; \ + free(help); help = NULL; \ + curr_type = RND_HATT_END; \ + curr = -1; \ + vtp0_init(&curr_enum); \ + vtp0_append(&curr_enum, rnd_strdup("")); \ + numrows++; \ +} while(0) + +#define append() \ +do { \ + if (curr >= MAX_PARAMS) { \ + if (curr == MAX_PARAMS) \ + rnd_message(RND_MSG_ERROR, "too many parameters, displaying only the first %d\n", MAX_PARAMS); \ + break; \ + } \ + if (curr_type == RND_HATT_END) \ + break; \ + pre_append(); \ + RND_DAD_LABEL(ctx->pdlg, name); \ + RND_DAD_HELP(ctx->pdlg, rnd_strdup(help)); \ + switch(curr_type) { \ + case RND_HATT_COORD: \ + case RND_HATT_END: \ + RND_DAD_COORD(ctx->pdlg); \ + ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ + RND_DAD_MINMAX(ctx->pdlg, 0, RND_MM_TO_COORD(512)); \ + RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ + break; \ + case RND_HATT_STRING: \ + RND_DAD_STRING(ctx->pdlg); \ + ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ + RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ + break; \ + case RND_HATT_BOOL: \ + RND_DAD_BOOL(ctx->pdlg); \ + ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ + RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ + break; \ + case RND_HATT_ENUM: \ + RND_DAD_ENUM(ctx->pdlg, (const char **)curr_enum.array); \ + ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ + RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ + vtp0_init(&curr_enum); \ + vtp0_append(&curr_enum, rnd_strdup("")); \ + break; \ + default: \ + RND_DAD_LABEL(ctx->pdlg, "internal error: invalid type"); \ + } \ + RND_DAD_HELP(ctx->pdlg, rnd_strdup(help)); \ + ctx->pnames[curr] = rnd_strdup(name); \ + htsi_set(&ctx->param_names, ctx->pnames[curr], curr); \ + post_append(); \ +} while(0) + +static int library_param_build(library_param_ctx_t *ctx, library_ent_t *l, FILE *f) +{ + char line[1024]; + char *name = NULL, *help = NULL, *help_def = NULL; + vtp0_t curr_enum; + int curr, examples = 0, numrows = 0; + rnd_hid_attr_type_t curr_type = RND_HATT_END; + + curr = -1; + + free(ctx->example); + ctx->example = NULL; + ctx->num_params = 0; + + vtp0_init(&curr_enum); + vtp0_append(&curr_enum, rnd_strdup("")); + + while(fgets(line, sizeof(line), f) != NULL) { + char *end, *col, *arg, *cmd = line; + + /* rtrim */ + end = line + strlen(line) - 1; + while((end >= line) && ((*end == '\r') || (*end == '\n'))) { + *end = '\0'; + end--; + } + + /* ltrim */ + cmd = strchr(cmd, '@'); + if ((cmd == NULL) || (cmd[1] != '@')) + continue; + cmd+=2; + arg = strpbrk(cmd, " \t\r\n"); + if (arg != NULL) { + *arg = '\0'; + arg++; + while(isspace(*arg)) arg++; + } + col = cmd; + + /* parse */ + if (strcmp(cmd, "desc") == 0) { + if (examples < 2) { + gds_append_str(&ctx->descr, arg); + gds_append(&ctx->descr, '\n'); + } + } + else if (strcmp(cmd, "params") == 0) { + free(ctx->help_params); + ctx->help_params = rnd_strdup(arg); + } + else if (strcmp(cmd, "example") == 0) { + if (examples == 0) { + free(ctx->example); + ctx->example = rnd_strdup(arg); + } + examples++; + } + else if (strncmp(cmd, "optional:", 9) == 0) { + if (ctx->first_optional < 0) + ctx->first_optional = ctx->num_params-1; + } + else if (strncmp(cmd, "param:", 6) == 0) { + append(); + colsplit(); + curr = ctx->num_params; + ctx->num_params++; + free(name); + free(help); + name = rnd_strdup(col); + help = rnd_strdup(arg); + curr_type = RND_HATT_STRING; /* assume string until a dim or enum overrides that */ + } + else if (strncmp(cmd, "default:", 6) == 0) { + free(help_def); + if (arg == NULL) + arg = ""; + help_def = rnd_strdup(arg); + } + else if (strncmp(cmd, "dim:", 4) == 0) { + curr_type = RND_HATT_COORD; + } + else if (strncmp(cmd, "bool:", 5) == 0) { + curr_type = RND_HATT_BOOL; + } + else if (strncmp(cmd, "enum:", 5) == 0) { + char *evl; + + curr_type = RND_HATT_ENUM; + colsplit(); colsplit(); + if (arg != NULL) { + if (strlen(arg) > 32) { + arg[32] = '\0'; + evl = rnd_strdup_printf("%s (%s...)", col, arg); + } + else + evl = rnd_strdup_printf("%s (%s)", col, arg); + } + else + evl = rnd_strdup(col); + vtp0_append(&curr_enum, evl); + } + } + append(); + return numrows; +} + +static char *gen_cmd(library_param_ctx_t *ctx) +{ + int n, pushed = 0; + gds_t sres; + char *tmp; + + memset(&sres, 0, sizeof(sres)); + + gds_append_str(&sres, library_get_ent_name(ctx->last_l)); + + /* cut original name at "(" */ + tmp = strchr(sres.array, '('); + if (tmp != NULL) + gds_truncate(&sres, tmp - sres.array); + + gds_append_str(&sres, "("); + + for(n = 0; n < ctx->num_params; n++) { + char *desc, buff[128]; + const char *val; + rnd_hid_attribute_t *a = &ctx->pdlg[ctx->pwid[n]]; + + if (((n >= ctx->first_optional) && (!a->changed)) || (a->empty)) + continue; + + switch(a->type) { + case RND_HATT_LABEL: + case RND_HATT_BEGIN_TABLE: + continue; + case RND_HATT_ENUM: + val = ((const char **)(a->wdata))[a->val.lng]; + if (val != NULL) { + if (*val != '\0') { + desc = strstr((char *)val, " ("); + if (desc != NULL) + *desc = '\0'; + } + else + val = NULL; + } + break; + case RND_HATT_STRING: + val = a->val.str; + if ((val != NULL) && (*val == '\0')) + continue; + break; + case RND_HATT_BOOL: + val = a->val.lng ? "yes" : "no"; + break; + case RND_HATT_COORD: + case RND_HATT_END: + val = buff; + rnd_snprintf(buff, sizeof(buff), "%.09$$mH", a->val.crd); + break; + default:; + } + + if (val == NULL) + continue; + + if (pushed) + gds_append_str(&sres, ", "); + + if ((n == pushed) && (n < ctx->first_optional)) + gds_append_str(&sres, val); /* positional */ + else + rnd_append_printf(&sres, "%s=%s", ctx->pnames[n], val); + pushed++; + } + + gds_append_str(&sres, ")"); + return sres.array; +} + +static void library_param_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_inp) +{ + library_param_ctx_t *ctx = caller_data; + char *cmd = gen_cmd(ctx); + + library_set_filter(ctx->lib_ctx, cmd); + free(cmd); + timed_update_preview(ctx->lib_ctx, 1); +} + +static int param_split(char *buf, char *argv[], int amax) +{ + int n; + char *next, *bump; + + for(n=0; ;n++) { + if (n >= amax) + return n+1; + + /* ltrim */ + while(isspace(*buf)) buf++; + argv[n] = buf; + + /* find next param */ + bump = buf; + next = strchr(buf, ','); + if (next == NULL) + return n+1; + buf = next+1; + + /* rtrim */ + *next = '\0'; + next--; + while((next >= bump) && (isspace(*next))) { + *next = '\0'; + next--; + } + } + return -1; +} + +static void load_params(library_param_ctx_t *ctx, char *user_params) +{ + char *parain; + char *parahlp; + int argc_in, argc_help, posi, n; + char *end, *argv_in[MAX_PARAMS], *argv_help[MAX_PARAMS]; + char *help_params = ctx->help_params; + + if (user_params == NULL) + user_params = ""; + if (help_params == NULL) + help_params = ""; + + + parain = rnd_strdup(user_params); + parahlp = rnd_strdup(help_params); + + /* truncate trailing ")" */ + if (*parain != '\0') { + end = parain + strlen(parain) - 1; + if (*end == ')') + *end = '\0'; + } + + argc_in = param_split(parain, argv_in, MAX_PARAMS); + argc_help = param_split(parahlp, argv_help, MAX_PARAMS); + + /* iterate and assign default values and mark them changed to get them back */ + for(posi = n = 0; n < argc_in; n++) { + char *key, *val, *sep; + htsi_entry_t *e; + int pidx; + + sep = strchr(argv_in[n], '='); + if (sep != NULL) { + key = argv_in[n]; + *sep = '\0'; + val = sep+1; + + /* rtrim key */ + sep--; + while((sep >= key) && (isspace(*sep))) { + *sep = '\0'; + sep--; + } + + /* ltrim val */ + while(isspace(*val)) val++; + } + else { + if (posi >= argc_help) { + rnd_message(RND_MSG_ERROR, "More positional parameters than expected - ignoring %s", argv_in[n]); + continue; + } + key = argv_help[posi]; + val = argv_in[n]; + posi++; + } + + e = htsi_getentry(&ctx->param_names, key); + if (e == NULL) { + rnd_message(RND_MSG_ERROR, "Unknown parameter %s - ignoring value %s", key, val); + continue; + } + pidx = e->value; + set_attr(ctx, pidx, val); + } + + /* clean up */ + free(parain); + free(parahlp); +} + +int pcb_library_param_fillin(library_param_ctx_t *ctx, library_ent_t *l, const char *filter_txt) +{ + rnd_hid_attr_val_t hv; + + if (filter_txt != NULL) { + char *sep; + int len; + sep = strchr(library_get_ent_name(l), '('); + if (sep != NULL) + len = sep - library_get_ent_name(l); + else + len = strlen(library_get_ent_name(l)); + if (strncmp(filter_txt, library_get_ent_name(l), len) != 0) { + /* clicked away from the previous parametric, but the filter text is still for that one; replace it */ + filter_txt = NULL; + } + } + + + if (filter_txt == NULL) { + filter_txt = ctx->example; + library_set_filter(ctx->lib_ctx, filter_txt); + } + + if (filter_txt != NULL) { + const char *n1, *n2; + char *prm = strchr(filter_txt, '('); + + /* if filter text doesn't have parameters, try the example */ + if ((prm == NULL) || (prm[1] == ')')) { + if (ctx->example != NULL) { + filter_txt = ctx->example; + library_set_filter(ctx->lib_ctx, filter_txt); + prm = strchr(filter_txt, '('); + } + } + + /* do not load parameters from the comamnd of a differently named + footprint to avoid invalid mixing of similar named parameters; in + that case rather fill in the dialog with the example */ + for(n1 = filter_txt, n2 = library_get_ent_name(l);; n1++, n2++) { + if (*n1 != *n2) { + prm = ctx->example; + if (prm == NULL) + return -1; + while((*prm != '(') && (*prm != '\0')) prm++; + break; + } + else if ((*n1 == '(') || (*n1 == '\0')) + break; + } + + if (prm != NULL) + load_params(ctx, prm+1); + } + + hv.str = ctx->descr.array; + if (hv.str == NULL) + hv.str = ""; + rnd_gui->attr_dlg_set_value(ctx->pdlg_hid_ctx, ctx->pwdesc, &hv); + timed_update_preview(ctx->lib_ctx, 1); + return 0; +} + +static int library_param_open(library_param_ctx_t *ctx, library_ent_t *l, FILE *f) +{ + rnd_hid_dad_buttons_t clbtn[] = {{"Close", 0}, {NULL, 0}}; + int w, oversized = 0; + + RND_DAD_BEGIN_VBOX(ctx->pdlg); + RND_DAD_COMPFLAG(ctx->pdlg, RND_HATF_EXPFILL); + RND_DAD_LABEL(ctx->pdlg, "n/a"); + ctx->pwdesc = RND_DAD_CURRENT(ctx->pdlg); + RND_DAD_BEGIN_TABLE(ctx->pdlg, 2); + RND_DAD_COMPFLAG(ctx->pdlg, RND_HATF_EXPFILL); + w = RND_DAD_CURRENT(ctx->pdlg); + if (library_param_build(ctx, l, f) > 16) { + ctx->pdlg[w].rnd_hatt_flags |= RND_HATF_SCROLL; + oversized = 1; + } + RND_DAD_END(ctx->pdlg); + RND_DAD_BUTTON_CLOSES(ctx->pdlg, clbtn); + RND_DAD_END(ctx->pdlg); + return oversized; +} + +static FILE *library_param_get_help(library_param_ctx_t *ctx, library_ent_t *l) +{ + FILE *f; + char *cmd; + +#ifdef __WIN32__ + { + char *s; + cmd = rnd_strdup_printf("%s/sh -c \"%s --help\"", rnd_w32_bindir, l->data.fp.loc_info); + for(s = cmd; *s != '\0'; s++) + if (*s == '\\') + *s = '/'; + } +#else + cmd = rnd_strdup_printf("%s --help", l->data.fp.loc_info); +#endif + f = rnd_popen(NULL, cmd, "r"); + free(cmd); + if (f == NULL) { + rnd_message(RND_MSG_ERROR, "Can not execute parametric footprint %s\n", l->data.fp.loc_info); + return NULL; + } + + return f; +} + +static void library_param_dialog(library_param_ctx_t *ctx, library_ent_t *l, const char *filter_txt) +{ + FILE *f; + + if (ctx->last_l != l) { + if (ctx->pactive) { + ctx->pactive = 0; + RND_DAD_FREE(ctx->pdlg); + } + update_edit_button(ctx->lib_ctx); + } + else if (ctx->pactive) /* reopening the same -> nop */ + return; + + ctx->last_l = l; + + if (l == NULL) + return; + + f = library_param_get_help(ctx, l); + if (f == NULL) + return; + + htsi_init(&ctx->param_names, strhash, strkeyeq); + gds_init(&ctx->descr); + ctx->first_optional = -1; + + + ctx->pactive = 1; + if (library_param_open(ctx, l, f)) { + /* oversized dialog got the scroll bar, which would make it small; + set preferred size so it opens in reasonable area even when win size + not persistent (window palcement code) */ + RND_DAD_DEFSIZE(ctx->pdlg, 700, 500); + } + rnd_pclose(f); + + RND_DAD_NEW("lib_param", ctx->pdlg, "pcb-rnd parametric footprint", ctx, rnd_false, library_param_close_cb); + + update_edit_button(ctx->lib_ctx); + pcb_library_param_fillin(ctx, l, filter_txt); +} + +static void library_param_dialog_close(library_param_ctx_t *ctx) +{ + if (ctx->pactive) { + ctx->pactive = 0; + RND_DAD_FREE(ctx->pdlg); + } +} + Index: trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.h =================================================================== --- trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.h (nonexistent) +++ trunk/src_3rd/rnd_inclib/dialogs/dlg_library_param.h (revision 36179) @@ -0,0 +1,13 @@ +typedef struct { + int pactive; /* already open - allow only one instance */ + int pwdesc; + RND_DAD_DECL_NOINIT(pdlg) + library_ent_t *last_l; + char *example, *help_params; + htsi_t param_names; /* param_name -> param_idx */ + int pwid[MAX_PARAMS]; /* param_idx -> widget_idx (for the input field widget) */ + char *pnames[MAX_PARAMS]; /* param_idx -> parameter_name (also key stored in the param_names hash */ + int num_params, first_optional; + gds_t descr; + library_ctx_t *lib_ctx; +} library_param_ctx_t; Index: trunk/src_plugins/dialogs/dlg_library_param.c =================================================================== --- trunk/src_plugins/dialogs/dlg_library_param.c (revision 36178) +++ trunk/src_plugins/dialogs/dlg_library_param.c (nonexistent) @@ -1,634 +0,0 @@ -/* - * COPYRIGHT - * - * pcb-rnd, interactive printed circuit board design - * Copyright (C) 2017,2019,2020 Tibor 'Igor2' Palinkas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact: - * Project page: http://repo.hu/projects/pcb-rnd - * lead developer: http://repo.hu/projects/pcb-rnd/contact.html - * mailing list: pcb-rnd (at) list.repo.hu (send "subscribe") - */ - -#include - -static void library_param_close_cb(void *caller_data, rnd_hid_attr_ev_t ev) -{ - library_param_ctx_t *ctx = caller_data; - htsi_entry_t *e; - - gds_uninit(&ctx->descr); - free(ctx->help_params); - ctx->help_params = NULL; - - for(e = htsi_first(&ctx->param_names); e != NULL; e = htsi_next(&ctx->param_names, e)) - free(e->key); - htsi_uninit(&ctx->param_names); - if (ctx->pactive) { - ctx->pactive = 0; - RND_DAD_FREE(ctx->pdlg); - } - update_edit_button(ctx->lib_ctx); -} - -#define colsplit() \ -do { \ - col = strchr(col, ':'); \ - if (col != NULL) { \ - *col = '\0'; \ - col++; \ - } \ -} while(0) - -static void set_attr(library_param_ctx_t *ctx, int pidx, char *val) -{ - rnd_hid_attr_val_t hv; - rnd_hid_attribute_t *a = &ctx->pdlg[ctx->pwid[pidx]]; - const char **s; - char *desc; - int vlen, len, n; - - switch(a->type) { - case RND_HATT_ENUM: - hv.lng = 0; /* fallback in case the loop doesn't find any match */ - vlen = strlen(val); - for(n = 0, s = a->wdata; *s != NULL; s++,n++) { - desc = strstr(*s, " ("); - if (desc != NULL) - len = desc - *s; - else - len = strlen(*s); - if ((len == vlen) && (strncmp(*s, val, len) == 0)) { - hv.lng = n; - break; - } - } - break; - case RND_HATT_STRING: - hv.str = val; - break; - case RND_HATT_BOOL: - if ((val == NULL) || (*val == '\0')) - return; - hv.lng = \ - (*val == '1') || (*val == 't') || (*val == 'T') || (*val == 'y') || (*val == 'Y') || \ - (((val[0] == 'o') || (val[0] == 'O')) && ((val[1] == 'n') || (val[1] == 'N'))); - break; - case RND_HATT_COORD: - case RND_HATT_END: /* compound widget for the spinbox! */ - hv.crd = rnd_get_value_ex(val, NULL, NULL, NULL, "mil", NULL); - break; - default: - assert(!"set_attr() can't set non-data field!\n"); - return; - } - rnd_gui->attr_dlg_set_value(ctx->pdlg_hid_ctx, ctx->pwid[pidx], &hv); -} - -static void library_param_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_inp); - -#define pre_append() \ -do { \ - if (help_def != NULL) { \ - if (help != NULL) { \ - char *tmp = rnd_concat(help, "\nDefault: ", help_def, NULL); \ - free(help); \ - free(help_def); \ - help = tmp; \ - } \ - else \ - help = help_def; \ - help_def = NULL; \ - } \ -} while(0) - -#define post_append() \ -do { \ - vtp0_uninit(&curr_enum); \ - free(name); name = NULL; \ - free(help); help = NULL; \ - curr_type = RND_HATT_END; \ - curr = -1; \ - vtp0_init(&curr_enum); \ - vtp0_append(&curr_enum, rnd_strdup("")); \ - numrows++; \ -} while(0) - -#define append() \ -do { \ - if (curr >= MAX_PARAMS) { \ - if (curr == MAX_PARAMS) \ - rnd_message(RND_MSG_ERROR, "too many parameters, displaying only the first %d\n", MAX_PARAMS); \ - break; \ - } \ - if (curr_type == RND_HATT_END) \ - break; \ - pre_append(); \ - RND_DAD_LABEL(ctx->pdlg, name); \ - RND_DAD_HELP(ctx->pdlg, rnd_strdup(help)); \ - switch(curr_type) { \ - case RND_HATT_COORD: \ - case RND_HATT_END: \ - RND_DAD_COORD(ctx->pdlg); \ - ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ - RND_DAD_MINMAX(ctx->pdlg, 0, RND_MM_TO_COORD(512)); \ - RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ - break; \ - case RND_HATT_STRING: \ - RND_DAD_STRING(ctx->pdlg); \ - ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ - RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ - break; \ - case RND_HATT_BOOL: \ - RND_DAD_BOOL(ctx->pdlg); \ - ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ - RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ - break; \ - case RND_HATT_ENUM: \ - RND_DAD_ENUM(ctx->pdlg, (const char **)curr_enum.array); \ - ctx->pwid[curr] = RND_DAD_CURRENT(ctx->pdlg); \ - RND_DAD_CHANGE_CB(ctx->pdlg, library_param_cb); \ - vtp0_init(&curr_enum); \ - vtp0_append(&curr_enum, rnd_strdup("")); \ - break; \ - default: \ - RND_DAD_LABEL(ctx->pdlg, "internal error: invalid type"); \ - } \ - RND_DAD_HELP(ctx->pdlg, rnd_strdup(help)); \ - ctx->pnames[curr] = rnd_strdup(name); \ - htsi_set(&ctx->param_names, ctx->pnames[curr], curr); \ - post_append(); \ -} while(0) - -static int library_param_build(library_param_ctx_t *ctx, library_ent_t *l, FILE *f) -{ - char line[1024]; - char *name = NULL, *help = NULL, *help_def = NULL; - vtp0_t curr_enum; - int curr, examples = 0, numrows = 0; - rnd_hid_attr_type_t curr_type = RND_HATT_END; - - curr = -1; - - free(ctx->example); - ctx->example = NULL; - ctx->num_params = 0; - - vtp0_init(&curr_enum); - vtp0_append(&curr_enum, rnd_strdup("")); - - while(fgets(line, sizeof(line), f) != NULL) { - char *end, *col, *arg, *cmd = line; - - /* rtrim */ - end = line + strlen(line) - 1; - while((end >= line) && ((*end == '\r') || (*end == '\n'))) { - *end = '\0'; - end--; - } - - /* ltrim */ - cmd = strchr(cmd, '@'); - if ((cmd == NULL) || (cmd[1] != '@')) - continue; - cmd+=2; - arg = strpbrk(cmd, " \t\r\n"); - if (arg != NULL) { - *arg = '\0'; - arg++; - while(isspace(*arg)) arg++; - } - col = cmd; - - /* parse */ - if (strcmp(cmd, "desc") == 0) { - if (examples < 2) { - gds_append_str(&ctx->descr, arg); - gds_append(&ctx->descr, '\n'); - } - } - else if (strcmp(cmd, "params") == 0) { - free(ctx->help_params); - ctx->help_params = rnd_strdup(arg); - } - else if (strcmp(cmd, "example") == 0) { - if (examples == 0) { - free(ctx->example); - ctx->example = rnd_strdup(arg); - } - examples++; - } - else if (strncmp(cmd, "optional:", 9) == 0) { - if (ctx->first_optional < 0) - ctx->first_optional = ctx->num_params-1; - } - else if (strncmp(cmd, "param:", 6) == 0) { - append(); - colsplit(); - curr = ctx->num_params; - ctx->num_params++; - free(name); - free(help); - name = rnd_strdup(col); - help = rnd_strdup(arg); - curr_type = RND_HATT_STRING; /* assume string until a dim or enum overrides that */ - } - else if (strncmp(cmd, "default:", 6) == 0) { - free(help_def); - if (arg == NULL) - arg = ""; - help_def = rnd_strdup(arg); - } - else if (strncmp(cmd, "dim:", 4) == 0) { - curr_type = RND_HATT_COORD; - } - else if (strncmp(cmd, "bool:", 5) == 0) { - curr_type = RND_HATT_BOOL; - } - else if (strncmp(cmd, "enum:", 5) == 0) { - char *evl; - - curr_type = RND_HATT_ENUM; - colsplit(); colsplit(); - if (arg != NULL) { - if (strlen(arg) > 32) { - arg[32] = '\0'; - evl = rnd_strdup_printf("%s (%s...)", col, arg); - } - else - evl = rnd_strdup_printf("%s (%s)", col, arg); - } - else - evl = rnd_strdup(col); - vtp0_append(&curr_enum, evl); - } - } - append(); - return numrows; -} - -static char *gen_cmd(library_param_ctx_t *ctx) -{ - int n, pushed = 0; - gds_t sres; - char *tmp; - - memset(&sres, 0, sizeof(sres)); - - gds_append_str(&sres, library_get_ent_name(ctx->last_l)); - - /* cut original name at "(" */ - tmp = strchr(sres.array, '('); - if (tmp != NULL) - gds_truncate(&sres, tmp - sres.array); - - gds_append_str(&sres, "("); - - for(n = 0; n < ctx->num_params; n++) { - char *desc, buff[128]; - const char *val; - rnd_hid_attribute_t *a = &ctx->pdlg[ctx->pwid[n]]; - - if (((n >= ctx->first_optional) && (!a->changed)) || (a->empty)) - continue; - - switch(a->type) { - case RND_HATT_LABEL: - case RND_HATT_BEGIN_TABLE: - continue; - case RND_HATT_ENUM: - val = ((const char **)(a->wdata))[a->val.lng]; - if (val != NULL) { - if (*val != '\0') { - desc = strstr((char *)val, " ("); - if (desc != NULL) - *desc = '\0'; - } - else - val = NULL; - } - break; - case RND_HATT_STRING: - val = a->val.str; - if ((val != NULL) && (*val == '\0')) - continue; - break; - case RND_HATT_BOOL: - val = a->val.lng ? "yes" : "no"; - break; - case RND_HATT_COORD: - case RND_HATT_END: - val = buff; - rnd_snprintf(buff, sizeof(buff), "%.09$$mH", a->val.crd); - break; - default:; - } - - if (val == NULL) - continue; - - if (pushed) - gds_append_str(&sres, ", "); - - if ((n == pushed) && (n < ctx->first_optional)) - gds_append_str(&sres, val); /* positional */ - else - rnd_append_printf(&sres, "%s=%s", ctx->pnames[n], val); - pushed++; - } - - gds_append_str(&sres, ")"); - return sres.array; -} - -static void library_param_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_inp) -{ - library_param_ctx_t *ctx = caller_data; - char *cmd = gen_cmd(ctx); - - library_set_filter(ctx->lib_ctx, cmd); - free(cmd); - timed_update_preview(ctx->lib_ctx, 1); -} - -static int param_split(char *buf, char *argv[], int amax) -{ - int n; - char *next, *bump; - - for(n=0; ;n++) { - if (n >= amax) - return n+1; - - /* ltrim */ - while(isspace(*buf)) buf++; - argv[n] = buf; - - /* find next param */ - bump = buf; - next = strchr(buf, ','); - if (next == NULL) - return n+1; - buf = next+1; - - /* rtrim */ - *next = '\0'; - next--; - while((next >= bump) && (isspace(*next))) { - *next = '\0'; - next--; - } - } - return -1; -} - -static void load_params(library_param_ctx_t *ctx, char *user_params) -{ - char *parain; - char *parahlp; - int argc_in, argc_help, posi, n; - char *end, *argv_in[MAX_PARAMS], *argv_help[MAX_PARAMS]; - char *help_params = ctx->help_params; - - if (user_params == NULL) - user_params = ""; - if (help_params == NULL) - help_params = ""; - - - parain = rnd_strdup(user_params); - parahlp = rnd_strdup(help_params); - - /* truncate trailing ")" */ - if (*parain != '\0') { - end = parain + strlen(parain) - 1; - if (*end == ')') - *end = '\0'; - } - - argc_in = param_split(parain, argv_in, MAX_PARAMS); - argc_help = param_split(parahlp, argv_help, MAX_PARAMS); - - /* iterate and assign default values and mark them changed to get them back */ - for(posi = n = 0; n < argc_in; n++) { - char *key, *val, *sep; - htsi_entry_t *e; - int pidx; - - sep = strchr(argv_in[n], '='); - if (sep != NULL) { - key = argv_in[n]; - *sep = '\0'; - val = sep+1; - - /* rtrim key */ - sep--; - while((sep >= key) && (isspace(*sep))) { - *sep = '\0'; - sep--; - } - - /* ltrim val */ - while(isspace(*val)) val++; - } - else { - if (posi >= argc_help) { - rnd_message(RND_MSG_ERROR, "More positional parameters than expected - ignoring %s", argv_in[n]); - continue; - } - key = argv_help[posi]; - val = argv_in[n]; - posi++; - } - - e = htsi_getentry(&ctx->param_names, key); - if (e == NULL) { - rnd_message(RND_MSG_ERROR, "Unknown parameter %s - ignoring value %s", key, val); - continue; - } - pidx = e->value; - set_attr(ctx, pidx, val); - } - - /* clean up */ - free(parain); - free(parahlp); -} - -int pcb_library_param_fillin(library_param_ctx_t *ctx, library_ent_t *l, const char *filter_txt) -{ - rnd_hid_attr_val_t hv; - - if (filter_txt != NULL) { - char *sep; - int len; - sep = strchr(library_get_ent_name(l), '('); - if (sep != NULL) - len = sep - library_get_ent_name(l); - else - len = strlen(library_get_ent_name(l)); - if (strncmp(filter_txt, library_get_ent_name(l), len) != 0) { - /* clicked away from the previous parametric, but the filter text is still for that one; replace it */ - filter_txt = NULL; - } - } - - - if (filter_txt == NULL) { - filter_txt = ctx->example; - library_set_filter(ctx->lib_ctx, filter_txt); - } - - if (filter_txt != NULL) { - const char *n1, *n2; - char *prm = strchr(filter_txt, '('); - - /* if filter text doesn't have parameters, try the example */ - if ((prm == NULL) || (prm[1] == ')')) { - if (ctx->example != NULL) { - filter_txt = ctx->example; - library_set_filter(ctx->lib_ctx, filter_txt); - prm = strchr(filter_txt, '('); - } - } - - /* do not load parameters from the comamnd of a differently named - footprint to avoid invalid mixing of similar named parameters; in - that case rather fill in the dialog with the example */ - for(n1 = filter_txt, n2 = library_get_ent_name(l);; n1++, n2++) { - if (*n1 != *n2) { - prm = ctx->example; - if (prm == NULL) - return -1; - while((*prm != '(') && (*prm != '\0')) prm++; - break; - } - else if ((*n1 == '(') || (*n1 == '\0')) - break; - } - - if (prm != NULL) - load_params(ctx, prm+1); - } - - hv.str = ctx->descr.array; - if (hv.str == NULL) - hv.str = ""; - rnd_gui->attr_dlg_set_value(ctx->pdlg_hid_ctx, ctx->pwdesc, &hv); - timed_update_preview(ctx->lib_ctx, 1); - return 0; -} - -static int library_param_open(library_param_ctx_t *ctx, library_ent_t *l, FILE *f) -{ - rnd_hid_dad_buttons_t clbtn[] = {{"Close", 0}, {NULL, 0}}; - int w, oversized = 0; - - RND_DAD_BEGIN_VBOX(ctx->pdlg); - RND_DAD_COMPFLAG(ctx->pdlg, RND_HATF_EXPFILL); - RND_DAD_LABEL(ctx->pdlg, "n/a"); - ctx->pwdesc = RND_DAD_CURRENT(ctx->pdlg); - RND_DAD_BEGIN_TABLE(ctx->pdlg, 2); - RND_DAD_COMPFLAG(ctx->pdlg, RND_HATF_EXPFILL); - w = RND_DAD_CURRENT(ctx->pdlg); - if (library_param_build(ctx, l, f) > 16) { - ctx->pdlg[w].rnd_hatt_flags |= RND_HATF_SCROLL; - oversized = 1; - } - RND_DAD_END(ctx->pdlg); - RND_DAD_BUTTON_CLOSES(ctx->pdlg, clbtn); - RND_DAD_END(ctx->pdlg); - return oversized; -} - -static FILE *library_param_get_help(library_param_ctx_t *ctx, library_ent_t *l) -{ - FILE *f; - char *cmd; - -#ifdef __WIN32__ - { - char *s; - cmd = rnd_strdup_printf("%s/sh -c \"%s --help\"", rnd_w32_bindir, l->data.fp.loc_info); - for(s = cmd; *s != '\0'; s++) - if (*s == '\\') - *s = '/'; - } -#else - cmd = rnd_strdup_printf("%s --help", l->data.fp.loc_info); -#endif - f = rnd_popen(NULL, cmd, "r"); - free(cmd); - if (f == NULL) { - rnd_message(RND_MSG_ERROR, "Can not execute parametric footprint %s\n", l->data.fp.loc_info); - return NULL; - } - - return f; -} - -static void library_param_dialog(library_param_ctx_t *ctx, library_ent_t *l, const char *filter_txt) -{ - FILE *f; - - if (ctx->last_l != l) { - if (ctx->pactive) { - ctx->pactive = 0; - RND_DAD_FREE(ctx->pdlg); - } - update_edit_button(ctx->lib_ctx); - } - else if (ctx->pactive) /* reopening the same -> nop */ - return; - - ctx->last_l = l; - - if (l == NULL) - return; - - f = library_param_get_help(ctx, l); - if (f == NULL) - return; - - htsi_init(&ctx->param_names, strhash, strkeyeq); - gds_init(&ctx->descr); - ctx->first_optional = -1; - - - ctx->pactive = 1; - if (library_param_open(ctx, l, f)) { - /* oversized dialog got the scroll bar, which would make it small; - set preferred size so it opens in reasonable area even when win size - not persistent (window palcement code) */ - RND_DAD_DEFSIZE(ctx->pdlg, 700, 500); - } - rnd_pclose(f); - - RND_DAD_NEW("lib_param", ctx->pdlg, "pcb-rnd parametric footprint", ctx, rnd_false, library_param_close_cb); - - update_edit_button(ctx->lib_ctx); - pcb_library_param_fillin(ctx, l, filter_txt); -} - -static void library_param_dialog_close(library_param_ctx_t *ctx) -{ - if (ctx->pactive) { - ctx->pactive = 0; - RND_DAD_FREE(ctx->pdlg); - } -} - Index: trunk/src_plugins/dialogs/dlg_library_param.h =================================================================== --- trunk/src_plugins/dialogs/dlg_library_param.h (revision 36178) +++ trunk/src_plugins/dialogs/dlg_library_param.h (nonexistent) @@ -1,13 +0,0 @@ -typedef struct { - int pactive; /* already open - allow only one instance */ - int pwdesc; - RND_DAD_DECL_NOINIT(pdlg) - library_ent_t *last_l; - char *example, *help_params; - htsi_t param_names; /* param_name -> param_idx */ - int pwid[MAX_PARAMS]; /* param_idx -> widget_idx (for the input field widget) */ - char *pnames[MAX_PARAMS]; /* param_idx -> parameter_name (also key stored in the param_names hash */ - int num_params, first_optional; - gds_t descr; - library_ctx_t *lib_ctx; -} library_param_ctx_t; Index: trunk/src_plugins/dialogs/dlg_library.c =================================================================== --- trunk/src_plugins/dialogs/dlg_library.c (revision 36178) +++ trunk/src_plugins/dialogs/dlg_library.c (revision 36179) @@ -60,7 +60,7 @@ typedef struct library_ctx_s library_ctx_t; typedef pcb_fplibrary_t library_ent_t; -#include "dlg_library_param.h" +#include "../../src_3rd/rnd_inclib/dialogs/dlg_library_param.h" struct library_ctx_s { RND_DAD_DECL_NOINIT(dlg) @@ -248,7 +248,7 @@ static const char *library_get_ent_name(library_ent_t *e) { return e->name; } -#include "dlg_library_param.c" +#include "../../src_3rd/rnd_inclib/dialogs/dlg_library_param.c" static void library_close_cb(void *caller_data, rnd_hid_attr_ev_t ev) {