/* * COPYRIGHT * * pcb-rnd, interactive printed circuit board design * Copyright (C) 2019 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 "config.h" #include #include "conf_core.h" #include "funchash_core.h" #include #include "search.h" #include "undo.h" #include #include "extobj.h" static int extobj_pick_gui(void) { int n, res; static int last = 0; rnd_hid_dad_buttons_t clbtn[] = {{"Cancel", -1}, {NULL, 0}}; RND_DAD_DECL(dlg); RND_DAD_BEGIN_VBOX(dlg); RND_DAD_COMPFLAG(dlg, RND_HATF_EXPFILL); RND_DAD_LABEL(dlg, "Choose extended object:"); if ((last > 0) && (last < pcb_extobj_i2o.used)) { pcb_extobj_t *eo = pcb_extobj_i2o.array[last]; RND_DAD_BEGIN_HBOX(dlg); RND_DAD_LABEL(dlg, "Last used:"); RND_DAD_BUTTON_CLOSE(dlg, eo->name, last); RND_DAD_END(dlg); } RND_DAD_BEGIN_TABLE(dlg, 3); for(n = 1; n < pcb_extobj_i2o.used; n++) { pcb_extobj_t *eo = pcb_extobj_i2o.array[n]; RND_DAD_BUTTON_CLOSE(dlg, eo->name, n); } RND_DAD_END(dlg); RND_DAD_BUTTON_CLOSES(dlg, clbtn); RND_DAD_END(dlg); RND_DAD_NEW("extobj_select", dlg, "Select extended object", NULL, rnd_true, NULL); res = RND_DAD_RUN(dlg); RND_DAD_FREE(dlg); if (res > 0) last = res; return res; } static const char pcb_acts_ExtobjConvFrom[] = "ExtobjConvFrom(selected|buffer, extotype)\nExtobjConvFrom(object, extotype, [idpath])"; static const char pcb_acth_ExtobjConvFrom[] = "Create a new extended object of extotype by converting existing objects"; fgw_error_t pcb_act_ExtobjConvFrom(fgw_arg_t *res, int argc, fgw_arg_t *argv) { pcb_board_t *pcb = PCB_ACT_BOARD; pcb_extobj_t *eo; const char *eoname = NULL; int op; pcb_subc_t *sc = NULL; pcb_any_obj_t *obj; RND_ACT_CONVARG(1, FGW_KEYWORD, ExtobjConvFrom, op = fgw_keyword(&argv[1])); RND_ACT_CONVARG(2, FGW_STR, ExtobjConvFrom, eoname = argv[2].val.str); if (strcmp(eoname, "@gui") != 0) { eo = pcb_extobj_lookup(eoname); if (eo == NULL) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: extended object '%s' is not available\n", eoname); RND_ACT_IRES(-1); return 0; } } else { int idx = extobj_pick_gui(); if (idx <= 0) { RND_ACT_IRES(-1); return 0; } eo = pcb_extobj_i2o.array[idx]; } switch(op) { case F_Object: if (argc > 3) { /* convert by idpath */ pcb_idpath_t *idp; RND_ACT_CONVARG(3, FGW_IDPATH, ExtobjConvFrom, idp = fgw_idpath(&argv[2])); if ((idp == NULL) || !fgw_ptr_in_domain(&rnd_fgw, &argv[3], RND_PTR_DOMAIN_IDPATH)) return FGW_ERR_PTR_DOMAIN; obj = pcb_idpath2obj(PCB, idp); } else { /* interactive convert */ void *p1, *p3; rnd_coord_t x, y; rnd_hid_get_coords("Click on object to convert", &x, &y, 0); obj = NULL; if (pcb_search_screen(x, y, PCB_OBJ_CLASS_REAL, &p1, (void **)&obj, &p3) == 0) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: object not found (no object under the cursor)\n"); RND_ACT_IRES(-1); return 0; } } if ((obj == NULL) || ((obj->type & PCB_OBJ_CLASS_REAL) == 0)) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: object not found\n"); RND_ACT_IRES(-1); return 0; } sc = pcb_extobj_conv_obj(pcb, eo, pcb->Data, obj, 1); break; case F_Selected: sc = pcb_extobj_conv_selected_objs(pcb, eo, pcb->Data, pcb->Data, 1); break; case F_Buffer: sc = pcb_extobj_conv_all_objs(pcb, eo, PCB_PASTEBUFFER->Data, PCB_PASTEBUFFER->Data, 1); break; default: RND_ACT_FAIL(ExtobjConvFrom); } if (sc == NULL) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: failed to create the extended object\n"); RND_ACT_IRES(-1); return 0; } pcb_undo_inc_serial(); RND_ACT_IRES(0); return 0; } static const char pcb_acts_ExtobjGUIPropEdit[] = "ExtobjGUIPropEdit([object, [idpath]])"; static const char pcb_acth_ExtobjGUIPropEdit[] = "Invoke the extobj-implementation-specific GUI property editor, if available"; static int exto_get_obj(fgw_arg_t *res, int argc, fgw_arg_t *argv, pcb_subc_t **dst_obj, pcb_extobj_t **dst_eo, rnd_bool require_extobj) { int op = F_Object; pcb_extobj_t *eo; pcb_subc_t *obj; *dst_obj = NULL; *dst_eo = NULL; RND_ACT_MAY_CONVARG(1, FGW_KEYWORD, ExtobjGUIPropEdit, op = fgw_keyword(&argv[1])); switch(op) { case F_Object: if (argc > 2) { /* convert by idpath */ pcb_idpath_t *idp; RND_ACT_CONVARG(2, FGW_IDPATH, ExtobjGUIPropEdit, idp = fgw_idpath(&argv[2])); if ((idp == NULL) || !fgw_ptr_in_domain(&rnd_fgw, &argv[2], RND_PTR_DOMAIN_IDPATH)) return FGW_ERR_PTR_DOMAIN; obj = (pcb_subc_t *)pcb_idpath2obj(PCB, idp); } else { /* interactive convert */ void *p1, *p3; rnd_coord_t x, y; rnd_hid_get_coords("Click on extended object to edit", &x, &y, 0); obj = NULL; if (pcb_search_screen(x, y, PCB_OBJ_SUBC, &p1, (void **)&obj, &p3) == 0) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: object not found (no object under the cursor)\n"); RND_ACT_IRES(-1); return 0; } } if ((obj == NULL) || ((obj->type & PCB_OBJ_CLASS_REAL) == 0)) { rnd_message(RND_MSG_ERROR, "ExtobjConvFrom: object not found\n"); RND_ACT_IRES(-1); return 0; } break; default: RND_ACT_FAIL(ExtobjConvFrom); } if ((obj == NULL) || (obj->type != PCB_OBJ_SUBC)) { rnd_message(RND_MSG_ERROR, "Object is not an extended object (not even a subcircuit)\n"); RND_ACT_IRES(-1); return 0; } if (require_extobj && (obj->extobj == NULL)) { rnd_message(RND_MSG_ERROR, "Subcircuit is not an extended object\n"); RND_ACT_IRES(-1); return 0; } eo = pcb_extobj_get(obj); if (require_extobj && (eo == NULL)) { rnd_message(RND_MSG_ERROR, "Extended object '%s' is not available\n", obj->extobj); RND_ACT_IRES(1); return 0; } *dst_obj = obj; *dst_eo = eo; return 0; } fgw_error_t pcb_act_ExtobjGUIPropEdit(fgw_arg_t *res, int argc, fgw_arg_t *argv) { pcb_extobj_t *eo; pcb_subc_t *obj; int rv = exto_get_obj(res, argc, argv, &obj, &eo, 1); if (obj == NULL) { RND_ACT_IRES(1); return rv; } if (eo->gui_propedit != NULL) eo->gui_propedit(obj); else rnd_message(RND_MSG_ERROR, "Extended object '%s' does not implement GUI property editor", obj->extobj); RND_ACT_IRES(0); return 0; } static const char pcb_acts_ExtobjToggle[] = "ExtobjToggle([object, [idpath]])"; static const char pcb_acth_ExtobjToggle[] = "Convert an extobj into a plain subc or back"; fgw_error_t pcb_act_ExtobjToggle(fgw_arg_t *res, int argc, fgw_arg_t *argv) { pcb_extobj_t *eo; pcb_subc_t *obj; int rv = exto_get_obj(res, argc, argv, &obj, &eo, 0); if (obj == NULL) { RND_ACT_IRES(1); return rv; } if (eo != NULL) { pcb_attribute_put(&obj->Attributes, "disabled_extobj", obj->extobj); pcb_attribute_remove(&obj->Attributes, "extobj"); PCB_FLAG_CLEAR(PCB_FLAG_LOCK, obj); } else { const char *type = pcb_attribute_get(&obj->Attributes, "disabled_extobj"); if (type == NULL) { rnd_message(RND_MSG_ERROR, "Subcircuit was not an extended object\n"); RND_ACT_IRES(1); return 0; } pcb_attribute_put(&obj->Attributes, "extobj", type); pcb_attribute_remove(&obj->Attributes, "disabled_extobj"); PCB_FLAG_SET(PCB_FLAG_LOCK, obj); } RND_ACT_IRES(0); return 0; } static rnd_action_t pcb_extobj_action_list[] = { {"ExtobjConvFrom", pcb_act_ExtobjConvFrom, pcb_acth_ExtobjConvFrom, pcb_acts_ExtobjConvFrom}, {"ExtobjGUIPropEdit", pcb_act_ExtobjGUIPropEdit, pcb_acth_ExtobjGUIPropEdit, pcb_acts_ExtobjGUIPropEdit}, {"ExtobjToggle", pcb_act_ExtobjToggle, pcb_acth_ExtobjToggle, pcb_acts_ExtobjToggle} }; void pcb_extobj_act_init2(void) { RND_REGISTER_ACTIONS(pcb_extobj_action_list, NULL); }