/* * COPYRIGHT * * cschem - modular/flexible schematics editor - libcschem (core library) * Copyright (C) 2019 Tibor 'Igor2' Palinkas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version.* * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA * * Contact: * Project page: http://repo.hu/projects/sch-rnd * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html */ #include "config.h" #include #include #include #include #include "cnc_any_obj.h" #include "event.h" #include "concrete.h" #include "cnc_arc.h" #include "cnc_bitmap.h" #include "cnc_conn.h" #include "cnc_grp.h" #include "cnc_line.h" #include "cnc_text.h" #include "cnc_obj.h" #include "cnc_pen.h" #include "cnc_poly.h" #include "undo.h" #include "extobj.h" void csch_cobj_free(csch_chdr_t *obj) { switch(obj->type) { case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: break; case CSCH_CTYPE_LINE: csch_line_free((csch_line_t *)obj); break; case CSCH_CTYPE_ARC: csch_arc_free((csch_arc_t *)obj); break; case CSCH_CTYPE_POLY: csch_cpoly_free((csch_cpoly_t *)obj); break; case CSCH_CTYPE_TEXT: csch_text_free((csch_text_t *)obj); break; case CSCH_CTYPE_BITMAP: csch_cbitmap_free((csch_cbitmap_t *)obj); break; case CSCH_CTYPE_CONN: csch_conn_free((csch_conn_t *)obj); break; case CSCH_CTYPE_GRP: csch_cgrp_free((csch_cgrp_t *)obj); break; case CSCH_CTYPE_GRP_REF: csch_cgrp_ref_free((csch_cgrp_t *)obj); break; case CSCH_CTYPE_PEN: csch_pen_free((csch_cpen_t *)obj); break; } } csch_chdr_t *csch_cobj_dup(csch_sheet_t *sheet, csch_cgrp_t *grp, const csch_chdr_t *src, int keep_id, int inst2spec) { void *dst; switch(src->type) { case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: return NULL; case CSCH_CTYPE_LINE: dst = csch_line_dup(sheet, grp, (const csch_line_t *)src, keep_id, inst2spec); break; case CSCH_CTYPE_ARC: dst = csch_arc_dup(sheet, grp, (const csch_arc_t *)src, keep_id); break; case CSCH_CTYPE_POLY: dst = csch_cpoly_dup(sheet, grp, (const csch_cpoly_t *)src, keep_id); break; case CSCH_CTYPE_TEXT: dst = csch_text_dup(sheet, grp, (const csch_text_t *)src, keep_id, inst2spec); break; case CSCH_CTYPE_BITMAP: dst = csch_cbitmap_dup(sheet, grp, (const csch_cbitmap_t *)src, keep_id); break; case CSCH_CTYPE_CONN: abort(); case CSCH_CTYPE_GRP: case CSCH_CTYPE_GRP_REF: dst = csch_cgrp_dup(sheet, grp, (const csch_cgrp_t *)src, keep_id); break; case CSCH_CTYPE_PEN: dst = csch_pen_dup(sheet, grp, (const csch_cpen_t *)src); break; /* id is name and is always kept */ } return dst; } void csch_cobj_update(csch_sheet_t *sheet, csch_chdr_t *src, int do_xform) { switch(src->type) { case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: abort(); case CSCH_CTYPE_LINE: csch_line_update(sheet, (csch_line_t *)src, do_xform); break; case CSCH_CTYPE_ARC: csch_arc_update(sheet, (csch_arc_t *)src, do_xform); break; case CSCH_CTYPE_POLY: csch_poly_update(sheet, (csch_cpoly_t *)src, do_xform); break; case CSCH_CTYPE_TEXT: csch_text_update(sheet, (csch_text_t *)src, do_xform); break; case CSCH_CTYPE_BITMAP: abort(); case CSCH_CTYPE_CONN: csch_conn_update(sheet, (csch_conn_t *)src, do_xform); break; case CSCH_CTYPE_GRP: csch_cgrp_update(sheet, (csch_cgrp_t *)src, do_xform); break; case CSCH_CTYPE_GRP_REF: csch_cgrp_ref_update(sheet, (csch_cgrp_t *)src, do_xform); break; case CSCH_CTYPE_PEN: /* nop */ break; } } int csch_cobj_attrib_set(csch_sheet_t *sheet, csch_cgrp_t *obj, int prio, const char *key, const char *val, csch_source_arg_t *source) { csch_attrib_t *a; int res; assert(csch_obj_is_grp(&obj->hdr)); csch_extrobj_attr_edit_pre(obj, key); res = csch_attrib_set(&obj->attr, prio, key, val, source, &a); if (res == 0) /* attribute value changed */ csch_cgrp_attrib_update(sheet, obj, prio, a->key, a->val); csch_extrobj_attr_edit_post(obj, key); return res; } int csch_cobj_attrib_seti(csch_sheet_t *sheet, csch_cgrp_t *obj, int prio, const char *key, long idx, const char *val, csch_source_arg_t *source) { TODO("call csch_cobj_attrib_update() with idx"); assert(csch_obj_is_grp(&obj->hdr)); return csch_attrib_seti(&obj->attr, prio, key, idx, val, source, NULL); } void csch_cobj_attrib_copy_all(csch_sheet_t *sheet, csch_cgrp_t *dst, const csch_cgrp_t *src) { csch_attrib_t *a, *b; htsp_entry_t *e; assert(csch_obj_is_grp(&dst->hdr) && csch_obj_is_grp(&src->hdr)); for(e = htsp_first(&src->attr); e; e = htsp_next(&src->attr, e)) { a = e->value; b = csch_attrib_dup(a); csch_extrobj_attr_edit_pre(dst, b->key); htsp_set(&dst->attr, b->key, b); csch_cgrp_attrib_update(sheet, dst, b->prio, b->key, b->val); csch_extrobj_attr_edit_post(dst, b->key); } } unsigned csch_cobj_hash_(csch_chdr_t *obj, csch_hash_ignore_t ignore) { switch(obj->type) { case CSCH_CTYPE_LINE: return csch_line_hash((csch_line_t *)obj, ignore); case CSCH_CTYPE_ARC: return csch_arc_hash((csch_arc_t *)obj, ignore); case CSCH_CTYPE_POLY: return csch_cpoly_hash((csch_cpoly_t *)obj, ignore); case CSCH_CTYPE_TEXT: return csch_text_hash((csch_text_t *)obj, ignore); case CSCH_CTYPE_BITMAP: /*return csch_bitmap_hash((csch_bitmap_t *)obj, ignore);*/ case CSCH_CTYPE_CONN: /*return csch_conn_hash((csch_conn_t *)obj, ignore);*/ case CSCH_CTYPE_GRP: case CSCH_CTYPE_GRP_REF: return csch_cgrp_hash_((csch_cgrp_t *)obj, ignore); case CSCH_CTYPE_PEN: return csch_pen_hash((csch_cpen_t *)obj, ignore); case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: break; } return 0; } unsigned csch_cobj_hash(csch_chdr_t *obj) { return csch_cobj_hash_(obj, 0); } int csch_cobj_keyeq_(csch_chdr_t *obj1, csch_chdr_t *obj2, csch_hash_ignore_t ignore) { if (obj1->type != obj2->type) return 0; switch(obj1->type) { case CSCH_CTYPE_LINE: return csch_line_keyeq((csch_line_t *)obj1, (csch_line_t *)obj2, ignore); case CSCH_CTYPE_ARC: return csch_arc_keyeq((csch_arc_t *)obj1, (csch_arc_t *)obj2, ignore); case CSCH_CTYPE_POLY: return csch_cpoly_keyeq((csch_cpoly_t *)obj1, (csch_cpoly_t *)obj2, ignore); case CSCH_CTYPE_TEXT: return csch_text_keyeq((csch_text_t *)obj1, (csch_text_t *)obj2, ignore); case CSCH_CTYPE_BITMAP: /*return csch_bitmap_keyeq((csch_bitmap_t *)obj1, (csch_bitmap_t *)obj2, ignore);*/ case CSCH_CTYPE_CONN: /*return csch_conn_keyeq((csch_conn_t *)obj1, (csch_conn_t *)obj2, ignore);*/ case CSCH_CTYPE_GRP: case CSCH_CTYPE_GRP_REF: return csch_cgrp_keyeq_((csch_cgrp_t *)obj1, (csch_cgrp_t *)obj2, ignore); case CSCH_CTYPE_PEN: return csch_pen_keyeq((csch_cpen_t *)obj1, (csch_cpen_t *)obj2, ignore); case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: break; } return 0; } int csch_cobj_keyeq(csch_chdr_t *obj1, csch_chdr_t *obj2) { return csch_cobj_keyeq_(obj1, obj2, 0); } int csch_cobj_get_endxy(const csch_chdr_t *src, int side, csch_coord_t *x, csch_coord_t *y) { switch(src->type) { case CSCH_CTYPE_LINE: return csch_line_get_endxy((csch_line_t *)src, side, x, y); case CSCH_CTYPE_ARC: return csch_arc_get_endxy((csch_arc_t *)src, side, x, y); case CSCH_CTYPE_POLY: case CSCH_CTYPE_TEXT: case CSCH_CTYPE_BITMAP: case CSCH_CTYPE_CONN: case CSCH_CTYPE_GRP: case CSCH_CTYPE_GRP_REF: case CSCH_CTYPE_PEN: case CSCH_CTYPE_max: case CSCH_CTYPE_invalid: break; } return -1; } static const char core_any_obj_cookie[] = "libcschem/core/cnc_any_obj.c"; /*** undoable pen name mod ***/ typedef struct { csch_chdr_t *obj; csch_comm_str_t stroke_name; csch_comm_str_t fill_name; } undo_pen_name_modify_t; static int undo_pen_name_modify_swap(void *udata) { undo_pen_name_modify_t *u = udata; rnd_swap(csch_comm_str_t, u->stroke_name, u->obj->stroke_name); rnd_swap(csch_comm_str_t, u->fill_name, u->obj->fill_name); u->obj->stroke = NULL; u->obj->fill = NULL; csch_cobj_update_pen(u->obj); return 0; } static void undo_pen_name_modify_print(void *udata, char *dst, size_t dst_len) { undo_pen_name_modify_t *u = udata; rnd_snprintf(dst, dst_len, "obj pen name change: stroke: %s <--> %s fill: %s <--> %s", u->obj->stroke_name, u->stroke_name, u->obj->fill_name, u->fill_name); } static const uundo_oper_t undo_pen_name_modify = { core_any_obj_cookie, NULL, undo_pen_name_modify_swap, undo_pen_name_modify_swap, undo_pen_name_modify_print }; void csch_chdr_pen_name_modify(csch_sheet_t *sheet, csch_chdr_t *obj, csch_comm_str_t *stroke_name, csch_comm_str_t *fill_name, int undoable) { undo_pen_name_modify_t utmp, *u = &utmp; if (undoable) u = uundo_append(&sheet->undo, &undo_pen_name_modify, sizeof(undo_pen_name_modify_t)); u->obj = obj; u->stroke_name = stroke_name == NULL ? obj->stroke_name : *stroke_name; u->fill_name = fill_name == NULL ? obj->fill_name : *fill_name; undo_pen_name_modify_swap(u); if (undoable) csch_undo_inc_serial(sheet); } RND_INLINE void select_side_effects(csch_sheet_t *sheet, csch_chdr_t *obj, int root) { if (obj->type == CSCH_CTYPE_TEXT) csch_text_invalidate_font((csch_text_t *)obj); /* may need to re-render for indicate selection */ if (csch_obj_is_grp(obj)) { csch_cgrp_t *grp = (csch_cgrp_t *)obj; htip_entry_t *e; for(e = htip_first(&grp->id2obj); e != NULL; e = htip_next(&grp->id2obj, e)) select_side_effects(sheet, e->value, 0); } if (root) csch_cobj_redraw(obj); } void csch_cobj_select(csch_sheet_t *sheet, csch_chdr_t *obj) { if (!obj->selected) { obj->selected = 1; select_side_effects(sheet, obj, 1); } } void csch_cobj_unselect(csch_sheet_t *sheet, csch_chdr_t *obj) { if (obj->selected) { obj->selected = 0; select_side_effects(sheet, obj, 1); } } int csch_cobj_is_direct(const csch_chdr_t *obj) { csch_cgrp_t *g, *direct = &obj->sheet->direct; for(g = obj->parent; g != NULL; g = g->hdr.parent) if (g == direct) return 1; return 0; } int csch_cobj_is_indirect(const csch_chdr_t *obj) { csch_cgrp_t *g, *indirect = &obj->sheet->indirect; for(g = obj->parent; g != NULL; g = g->hdr.parent) if (g == indirect) return 1; return 0; }