/* * 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 "obj_subc.h" #include "conf_core.h" #include #include #include "change.h" #include "undo.h" /*** API ***/ /* Convert an attribute to coord, return 0 on success */ RND_INLINE int pcb_extobj_unpack_coord(const pcb_subc_t *obj, rnd_coord_t *res, const char *name); RND_INLINE int pcb_extobj_unpack_int(const pcb_subc_t *obj, int *res, const char *name); /* Wrap the update/re-generation of an extobject-subc in this begin/end to make sure bbox and undo are updated properly. The end() call always returns 0. */ RND_INLINE void pcb_exto_regen_begin(pcb_subc_t *subc); RND_INLINE int pcb_exto_regen_end(pcb_subc_t *subc); /*** implementation ***/ RND_INLINE int pcb_extobj_unpack_coord(const pcb_subc_t *obj, rnd_coord_t *res, const char *name) { double v; rnd_bool succ; const char *s = pcb_attribute_get(&obj->Attributes, name); if (s != NULL) { v = rnd_get_value(s, NULL, NULL, &succ); if (succ) { *res = v; return 0; } } return -1; } RND_INLINE int pcb_extobj_unpack_int(const pcb_subc_t *obj, int *res, const char *name) { long l; char *end; const char *s = pcb_attribute_get(&obj->Attributes, name); if (s != NULL) { l = strtol(s, &end, 10); if (*end == '\0') { *res = l; return 0; } } return -1; } RND_INLINE void pcb_exto_regen_begin(pcb_subc_t *subc) { pcb_data_t *data = subc->parent.data; if (data->subc_tree != NULL) rnd_rtree_delete(data->subc_tree, subc, (rnd_rtree_box_t *)subc); pcb_undo_freeze_add(); } RND_INLINE int pcb_exto_regen_end(pcb_subc_t *subc) { pcb_data_t *data = subc->parent.data; pcb_undo_unfreeze_add(); pcb_subc_bbox(subc); if ((data != NULL) && (data->subc_tree != NULL)) rnd_rtree_insert(data->subc_tree, subc, (rnd_rtree_box_t *)subc); return 0; } RND_INLINE pcb_subc_t *pcb_exto_create(pcb_data_t *dst, const char *eoname, const pcb_dflgmap_t *layers, rnd_coord_t ox, rnd_coord_t oy, rnd_bool on_bottom, pcb_subc_t *copy_from) { pcb_subc_t *subc = pcb_subc_alloc(); pcb_board_t *pcb = NULL; if (copy_from != NULL) pcb_subc_copy_meta(subc, copy_from); pcb_attribute_put(&subc->Attributes, "extobj", eoname); for(; layers->name != NULL; layers++) pcb_subc_layer_create(subc, layers->name, layers->lyt, layers->comb, 0, layers->purpose); pcb_subc_create_aux(subc, ox, oy, 0, on_bottom); PCB_FLAG_SET(PCB_FLAG_LOCK, subc); pcb_subc_bbox(subc); pcb_subc_reg(dst, subc); if (dst->parent_type == PCB_PARENT_BOARD) pcb = dst->parent.board; if (pcb != NULL) { pcb_subc_rebind(pcb, subc); pcb_subc_bind_globals(pcb, subc); if (!dst->subc_tree) rnd_rtree_init(dst->subc_tree = malloc(sizeof(rnd_rtree_t))); rnd_rtree_insert(dst->subc_tree, subc, (rnd_rtree_box_t *)subc); } pcb_undo_add_obj_to_create(PCB_OBJ_SUBC, subc, subc, subc); return subc; } RND_INLINE void pcb_exto_draw_mark(pcb_draw_info_t *info, pcb_subc_t *subc) { rnd_coord_t x, y, unit = PCB_SUBC_AUX_UNIT; if (pcb_subc_get_origin(subc, &x, &y) != 0) return; rnd_render->set_color(pcb_draw_out.fgGC, &conf_core.appearance.color.extobj); rnd_hid_set_line_width(pcb_draw_out.fgGC, -2); rnd_render->draw_line(pcb_draw_out.fgGC, x, y, x, y + unit); rnd_render->draw_line(pcb_draw_out.fgGC, x, y, x + unit/2, y); rnd_render->draw_line(pcb_draw_out.fgGC, x, y + unit, x + unit/2, y + unit); rnd_render->draw_line(pcb_draw_out.fgGC, x, y + unit/2, x + unit/3, y + unit/2); } /*** dialog box build ***/ RND_INLINE void pcb_exto_dlg_gui_chg_attr(pcb_subc_t *subc, rnd_hid_attribute_t *attr, const char *newval) /* for internal use */ { pcb_board_t *pcb; pcb_data_t *data; if (subc->parent_type != PCB_PARENT_DATA) return; data = subc->parent.data; if (data->parent_type != PCB_PARENT_BOARD) return; pcb = data->parent.board; pcb_uchg_attr(pcb, (pcb_any_obj_t *)subc, (char *)attr->user_data, newval); rnd_trace("chg: %s\n", (char *)attr->user_data); rnd_gui->invalidate_all(rnd_gui); } RND_INLINE void pcb_exto_dlg_coord_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr) { pcb_subc_t *subc = caller_data; char tmp[128]; rnd_snprintf(tmp, sizeof(tmp), "%$mm", attr->val.crd); pcb_exto_dlg_gui_chg_attr(subc, attr, tmp); } #define pcb_exto_dlg_coord(dlg, subc, vis_name, attr_name, help) \ do { \ rnd_hid_dad_spin_t *spin; \ double d = 0; \ rnd_coord_t currval; \ const rnd_unit_t *unit_out = NULL; \ int wid; \ char *sval = pcb_attribute_get(&subc->Attributes, attr_name); \ if (sval != NULL) \ rnd_get_value_unit(sval, NULL, 0, &d, &unit_out); \ currval = d; \ RND_DAD_LABEL(dlg, vis_name); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_COORD(dlg); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_CHANGE_CB(dlg, pcb_exto_dlg_coord_cb); \ wid = RND_DAD_CURRENT(dlg); \ dlg[wid].user_data = (void *)attr_name; \ RND_DAD_DEFAULT_NUM(dlg, currval); \ spin = dlg[wid].wdata; \ spin->unit = unit_out; \ spin->no_unit_chg = 1; \ rnd_dad_spin_update_internal(spin); \ } while(0) /* hv.crd = currval; \*/ /* rnd_dad_spin_set_value(spin->cmp.wend, NULL, wid, &hv); \*/ RND_INLINE void pcb_exto_dlg_str_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr) { pcb_subc_t *subc = caller_data; pcb_exto_dlg_gui_chg_attr(subc, attr, attr->val.str); } #define pcb_exto_dlg_str(dlg, subc, vis_name, attr_name, help) \ do { \ int wid; \ const char *currval = pcb_attribute_get(&subc->Attributes, attr_name); \ if (currval == NULL) currval = ""; \ currval = rnd_strdup(currval); \ RND_DAD_LABEL(dlg, vis_name); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_STRING(dlg); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_CHANGE_CB(dlg, pcb_exto_dlg_str_cb); \ wid = RND_DAD_CURRENT(dlg); \ dlg[wid].user_data = (void *)attr_name; \ RND_DAD_DEFAULT_PTR(dlg, currval); \ } while(0) RND_INLINE void pcb_exto_dlg_int_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr) { pcb_subc_t *subc = caller_data; char tmp[128]; rnd_snprintf(tmp, sizeof(tmp), "%d", attr->val.lng); pcb_exto_dlg_gui_chg_attr(subc, attr, tmp); } #define pcb_exto_dlg_int(dlg, subc, vis_name, attr_name, help) \ do { \ rnd_coord_t currval = 0; \ int wid; \ char *sval = pcb_attribute_get(&subc->Attributes, attr_name); \ if (sval != NULL) \ currval = strtol(sval, NULL, 10); \ RND_DAD_LABEL(dlg, vis_name); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_INTEGER(dlg); \ if (help != NULL) RND_DAD_HELP(dlg, help); \ RND_DAD_CHANGE_CB(dlg, pcb_exto_dlg_int_cb); \ wid = RND_DAD_CURRENT(dlg); \ dlg[wid].user_data = (void *)attr_name; \ RND_DAD_DEFAULT_NUM(dlg, currval); \ } while(0)