Index: trunk/src/obj_pstk.h =================================================================== --- trunk/src/obj_pstk.h (revision 30038) +++ trunk/src/obj_pstk.h (revision 30039) @@ -176,8 +176,8 @@ ID, else dup it and insert it. The forcedup variant always dups. WARNING: make sure pcb_pstk_proto_update() was called on proto some point in time before this call, esle the hash is invalid. */ -pcb_cardinal_t pcb_pstk_proto_insert_dup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet); -pcb_cardinal_t pcb_pstk_proto_insert_forcedup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet); +pcb_cardinal_t pcb_pstk_proto_insert_dup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int undoable); +pcb_cardinal_t pcb_pstk_proto_insert_forcedup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int undoable); /* Change the non-NULL hole properties of a padstack proto; undoable. Returns 0 on success. */ Index: trunk/src/obj_pstk_op.c =================================================================== --- trunk/src/obj_pstk_op.c (revision 30038) +++ trunk/src/obj_pstk_op.c (revision 30039) @@ -35,7 +35,7 @@ if (proto == NULL) return NULL; - npid = pcb_pstk_proto_insert_dup(ctx->buffer.dst, proto, 1); + npid = pcb_pstk_proto_insert_dup(ctx->buffer.dst, proto, 1, 0); p = pcb_pstk_new_tr(ctx->buffer.dst, -1, npid, ps->x, ps->y, ps->Clearance, pcb_flag_mask(ps->Flags, PCB_FLAG_FOUND | ctx->buffer.extraflg), ps->rot, ps->xmirror, ps->smirror); if (ctx->buffer.keep_id) pcb_obj_change_id((pcb_any_obj_t *)p, ps->ID); return pcb_pstk_copy_meta(p, ps); @@ -49,7 +49,7 @@ if (proto == NULL) return NULL; - npid = pcb_pstk_proto_insert_dup(ctx->buffer.dst, proto, 1); + npid = pcb_pstk_proto_insert_dup(ctx->buffer.dst, proto, 1, 0); pcb_poly_restore_to_poly(ctx->buffer.src, PCB_OBJ_PSTK, NULL, ps); pcb_r_delete_entry(ctx->buffer.src->padstack_tree, (pcb_box_t *)ps); @@ -79,7 +79,7 @@ if (proto == NULL) return NULL; - npid = pcb_pstk_proto_insert_dup(data, proto, 1); + npid = pcb_pstk_proto_insert_dup(data, proto, 1, 0); nps = pcb_pstk_new_tr(data, -1, npid, ps->x + ctx->copy.DeltaX, ps->y + ctx->copy.DeltaY, ps->Clearance, pcb_flag_mask(ps->Flags, PCB_FLAG_FOUND), ps->rot, ps->xmirror, ps->smirror); if (nps == NULL) @@ -257,7 +257,7 @@ /* create the new prototype and insert it */ pcb_pstk_proto_copy(&proto, pcb_pstk_get_proto(ps)); pcb_pstk_proto_grow(&proto, ctx->chgsize.is_absolute, ctx->chgsize.value); - nproto = pcb_pstk_proto_insert_dup(ps->parent.data, &proto, 1); + nproto = pcb_pstk_proto_insert_dup(ps->parent.data, &proto, 1, 0); pcb_pstk_proto_free_fields(&proto); if (nproto == PCB_PADSTACK_INVALID) @@ -311,7 +311,7 @@ } else proto.hdia = ctx->chgsize.value; - nproto = pcb_pstk_proto_insert_dup(ps->parent.data, &proto, 1); + nproto = pcb_pstk_proto_insert_dup(ps->parent.data, &proto, 1, 0); pcb_pstk_proto_free_fields(&proto); if (nproto == PCB_PADSTACK_INVALID) Index: trunk/src/obj_pstk_proto.c =================================================================== --- trunk/src/obj_pstk_proto.c (revision 30038) +++ trunk/src/obj_pstk_proto.c (revision 30039) @@ -674,9 +674,59 @@ return PCB_PADSTACK_INVALID; } +/*** undoable prototype creation ***/ +typedef struct { + pcb_data_t *data; + pcb_pstk_proto_t proto; + long pid; + int in_data; +} undo_proto_set_t; + +static int undo_proto_set_swap(void *udata) +{ + undo_proto_set_t *a = udata; + pcb_pstk_proto_t *np; + + if (a->in_data) { /* move from data proto vector to undo struct */ + int n = pcb_vtpadstack_proto_len(&a->data->ps_protos); + if (n < a->pid) { + pcb_message(PCB_MSG_ERROR, "undo_proto_set_swap(): not enough proto in data\n save and exit ASAP and report this bug!\n"); + return -1; + } + a->proto = a->data->ps_protos.array[a->pid]; + a->data->ps_protos.array[a->pid].in_use = 0; + } + else { /* move from undo struct to data proto vector */ + pcb_vtpadstack_proto_enlarge(&a->data->ps_protos, a->pid); + a->data->ps_protos.array[a->pid] = a->proto; + } + a->in_data = !a->in_data; + + np = pcb_vtpadstack_proto_get(&a->data->ps_protos, a->pid, 0); + pcb_pstk_proto_update(np); + + return 0; +} + +static void undo_proto_set_print(void *udata, char *dst, size_t dst_len) +{ + pcb_snprintf(dst, dst_len, "proto set"); +} + +static const uundo_oper_t undo_proto_set = { + core_proto_cookie, + NULL, + undo_proto_set_swap, + undo_proto_set_swap, + undo_proto_set_print +}; + + + pcb_cardinal_t pcb_pstk_proto_insert_or_free(pcb_data_t *data, pcb_pstk_proto_t *proto, int quiet) { - pcb_cardinal_t n, first_free; + pcb_cardinal_t id, n, first_free; + int undoable = 1; n = pcb_pstk_proto_insert_try(data, proto, &first_free); if (n != PCB_PADSTACK_INVALID) { @@ -687,7 +737,7 @@ /* no match, have to register a new one */ if (first_free == PCB_PADSTACK_INVALID) { pcb_pstk_proto_t *np; - n = pcb_vtpadstack_proto_len(&data->ps_protos); + id = n = pcb_vtpadstack_proto_len(&data->ps_protos); pcb_vtpadstack_proto_append(&data->ps_protos, *proto); np = pcb_vtpadstack_proto_get(&data->ps_protos, n, 0); np->parent = data; @@ -698,15 +748,24 @@ data->ps_protos.array[first_free].in_use = 1; data->ps_protos.array[first_free].parent = data; pcb_pstk_proto_update(data->ps_protos.array+first_free); - n = first_free; + id = first_free; } memset(proto, 0, sizeof(pcb_pstk_proto_t)); /* make sure a subsequent free() won't do any harm */ - return n; + + if (undoable) { + undo_proto_set_t *a = pcb_undo_alloc(pcb_data_get_top(data), &undo_proto_set, sizeof(undo_proto_set_t)); + a->data = data; + a->pid = id; + a->in_data = 1; + } + + return id; } -static pcb_cardinal_t pcb_pstk_proto_insert_dup_(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int forcedup) +static pcb_cardinal_t pcb_pstk_proto_insert_dup_(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int forcedup, int undoable) { - pcb_cardinal_t n, first_free = PCB_PADSTACK_INVALID; + pcb_cardinal_t id, n, first_free = PCB_PADSTACK_INVALID; + undo_proto_set_t *a; n = pcb_pstk_proto_insert_try(data, proto, &first_free); if ((n != PCB_PADSTACK_INVALID) && (!forcedup)) @@ -720,6 +779,7 @@ pcb_pstk_proto_copy(nproto, proto); nproto->parent = data; pcb_pstk_proto_update(nproto); + id = n; } else { pcb_pstk_proto_copy(data->ps_protos.array+first_free, proto); @@ -726,19 +786,27 @@ data->ps_protos.array[first_free].in_use = 1; data->ps_protos.array[first_free].parent = data; pcb_pstk_proto_update(data->ps_protos.array+first_free); - return first_free; + id = first_free; } - return n; + + if (undoable) { + undo_proto_set_t *a = pcb_undo_alloc(pcb_data_get_top(data), &undo_proto_set, sizeof(undo_proto_set_t)); + a->data = data; + a->pid = id; + a->in_data = 1; + } + + return id; } -pcb_cardinal_t pcb_pstk_proto_insert_dup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet) +pcb_cardinal_t pcb_pstk_proto_insert_dup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int undoable) { - return pcb_pstk_proto_insert_dup_(data, proto, quiet, 0); + return pcb_pstk_proto_insert_dup_(data, proto, quiet, 0, undoable); } -pcb_cardinal_t pcb_pstk_proto_insert_forcedup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet) +pcb_cardinal_t pcb_pstk_proto_insert_forcedup(pcb_data_t *data, const pcb_pstk_proto_t *proto, int quiet, int undoable) { - return pcb_pstk_proto_insert_dup_(data, proto, quiet, 1); + return pcb_pstk_proto_insert_dup_(data, proto, quiet, 1, undoable); } Index: trunk/src/obj_subc.c =================================================================== --- trunk/src/obj_subc.c (revision 30038) +++ trunk/src/obj_subc.c (revision 30039) @@ -654,7 +654,7 @@ pcb_pstk_unreg(ps); pcb_pstk_reg(sc->data, ps); PCB_FLAG_CLEAR(PCB_FLAG_WARN | PCB_FLAG_FOUND | PCB_FLAG_SELECTED, ps); - ps->proto = pcb_pstk_proto_insert_dup(sc->data, proto, 1); + ps->proto = pcb_pstk_proto_insert_dup(sc->data, proto, 1, 0); ps->protoi = -1; } } @@ -832,6 +832,7 @@ pcb_board_t *src_pcb; int n; pcb_subc_t *sc = pcb_subc_alloc(); + int dst_is_pcb = pcb_data_get_top(dst) == pcb; if (keep_ids) sc->ID = src->ID; @@ -950,7 +951,7 @@ gdl_iterator_t it; padstacklist_foreach(&src->data->padstack, &it, ps) { - pcb_cardinal_t pid = pcb_pstk_proto_insert_dup(sc->data, pcb_pstk_get_proto(ps), 1); + pcb_cardinal_t pid = pcb_pstk_proto_insert_dup(sc->data, pcb_pstk_get_proto(ps), 1, dst_is_pcb); nps = pcb_pstk_new_tr(sc->data, -1, pid, ps->x+dx, ps->y+dy, ps->Clearance, ps->Flags, ps->rot, ps->xmirror, ps->smirror); pcb_pstk_copy_meta(nps, ps); MAYBE_KEEP_ID(nps, ps); @@ -1402,7 +1403,7 @@ pcb_pstk_reg(dst, ps); } if (dst != NULL) - ps->proto = pcb_pstk_proto_insert_dup(ps->parent.data, proto, 1); + ps->proto = pcb_pstk_proto_insert_dup(ps->parent.data, proto, 1, dst_is_pcb); ps->protoi = -1; ps->parent.data = new_parent; if (dst_is_pcb) Index: trunk/src_plugins/act_draw/act_pstk_proto.c =================================================================== --- trunk/src_plugins/act_draw/act_pstk_proto.c (revision 30038) +++ trunk/src_plugins/act_draw/act_pstk_proto.c (revision 30039) @@ -125,9 +125,9 @@ } res->type = FGW_LONG; if (cmdi == act_draw_keywords_insert_dup) - res->val.nat_long = pcb_pstk_proto_insert_forcedup(data, proto, 1); + res->val.nat_long = pcb_pstk_proto_insert_forcedup(data, proto, 1, !noundo); else - res->val.nat_long = pcb_pstk_proto_insert_dup(data, proto, 1); + res->val.nat_long = pcb_pstk_proto_insert_dup(data, proto, 1, !noundo); return 0; case act_draw_keywords_free: Index: trunk/src_plugins/dialogs/dlg_lib_pstk.c =================================================================== --- trunk/src_plugins/dialogs/dlg_lib_pstk.c (revision 30038) +++ trunk/src_plugins/dialogs/dlg_lib_pstk.c (revision 30039) @@ -345,7 +345,7 @@ if (row == NULL) return; proto = pcb_pstk_get_proto_(data, strtol(row->cell[0], NULL, 10)); - ctx->proto_id = pcb_pstk_proto_insert_forcedup(data, proto, 0); + ctx->proto_id = pcb_pstk_proto_insert_forcedup(data, proto, 0, (pcb_data_get_top(data) == ctx->pcb)); tab = 1; } else { @@ -352,7 +352,7 @@ memset(&proto_, 0, sizeof(proto_)); pcb_pstk_proto_update(&proto_); proto = &proto_; - ctx->proto_id = pcb_pstk_proto_insert_dup(data, proto, 1); + ctx->proto_id = pcb_pstk_proto_insert_dup(data, proto, 1, (pcb_data_get_top(data) == ctx->pcb)); tab = 2; } Index: trunk/src_plugins/dialogs/dlg_padstack.c =================================================================== --- trunk/src_plugins/dialogs/dlg_padstack.c (revision 30038) +++ trunk/src_plugins/dialogs/dlg_padstack.c (revision 30039) @@ -241,7 +241,7 @@ pcb_message(PCB_MSG_ERROR, "Internal error: can't determine prototype\n"); return; } - proto_id = pcb_pstk_proto_insert_forcedup(pse->ps->parent.data, proto, 0); + proto_id = pcb_pstk_proto_insert_forcedup(pse->ps->parent.data, proto, 0, pcb_data_get_top(pse->ps->parent.data) == pse->pcb); pcb_pstk_change_instance(pse->ps, &proto_id, NULL, NULL, NULL, NULL); pse_ps2dlg(hid_ctx, pse); pse_changed(pse); @@ -727,7 +727,7 @@ pcb_message(PCB_MSG_ERROR, "Internal error: pse_gen() failed to raplace padstack prototype\n"); } else { - pid = pcb_pstk_proto_insert_dup(pse->data, &proto, 1); + pid = pcb_pstk_proto_insert_dup(pse->data, &proto, 1, 1); if (pid == PCB_PADSTACK_INVALID) pcb_message(PCB_MSG_ERROR, "Internal error: pse_gen() failed to insert padstack prototype\n"); else Index: trunk/src_plugins/exto_std/cord.c =================================================================== --- trunk/src_plugins/exto_std/cord.c (revision 30038) +++ trunk/src_plugins/exto_std/cord.c (revision 30039) @@ -270,7 +270,7 @@ proto.hplated = 0; pcb_pstk_proto_update(&proto); - return pcb_pstk_proto_insert_dup(data, &proto, 1); + return pcb_pstk_proto_insert_dup(data, &proto, 1, 0); } static pcb_pstk_t *endpt_pstk(pcb_subc_t *subc, const char *ptidx, pcb_cardinal_t pid, pcb_coord_t x, pcb_coord_t y, pcb_coord_t ox, pcb_coord_t oy, const char *term, const char *grp, int floater) Index: trunk/src_plugins/io_dsn/read.c =================================================================== --- trunk/src_plugins/io_dsn/read.c (revision 30038) +++ trunk/src_plugins/io_dsn/read.c (revision 30039) @@ -846,7 +846,7 @@ pcb_cardinal_t pid; DSN_LOAD_COORDS_FMT(crd, ncoord, "XY", goto err_coord); - pid = pcb_pstk_proto_insert_dup(subc->data, proto, 1); + pid = pcb_pstk_proto_insert_dup(subc->data, proto, 1, 0); pcb_pstk_new(subc->data, -1, pid, crd[0], crd[1], conf_core.design.clearance/2, pcb_flag_make(PCB_FLAG_CLEARLINE)); } @@ -896,7 +896,7 @@ } } - pid = pcb_pstk_proto_insert_dup(subc->data, proto, 1); + pid = pcb_pstk_proto_insert_dup(subc->data, proto, 1, 0); ps = pcb_pstk_new(subc->data, -1, pid, crd[0], crd[1], conf_core.design.clearance/2, pcb_flag_make(PCB_FLAG_CLEARLINE)); if (ps != NULL) { if (rotang != 0.0) { @@ -1411,7 +1411,7 @@ DSN_LOAD_COORDS_FMT(crd, vnd->children->next, "xy", goto err_coord); - pid = pcb_pstk_proto_insert_dup(ctx->pcb->Data, proto, 1); + pid = pcb_pstk_proto_insert_dup(ctx->pcb->Data, proto, 1, 0); if (pcb_pstk_new(ctx->pcb->Data, -1, pid, crd[0], crd[1], conf_core.design.clearance/2, pcb_flag_make(PCB_FLAG_CLEARLINE)) == NULL) pcb_message(PCB_MSG_ERROR, "Failed to create via - expect missing vias (at %ld:%ld)\n", (long)vnd->line, (long)vnd->col); @@ -1469,7 +1469,7 @@ shp->shape = PCB_PSSH_CIRC; shp->data.circ.dia = pcb_round((double)conf_core.design.min_wid * 1.05); - ctx->testpoint = pcb_pstk_proto_insert_dup(ctx->pcb->Data, &tpp, 1); + ctx->testpoint = pcb_pstk_proto_insert_dup(ctx->pcb->Data, &tpp, 1, 0); ctx->has_testpoint = 1; pcb_pstk_proto_free_fields(&tpp); } Index: trunk/src_plugins/io_mentor_cell/read.c =================================================================== --- trunk/src_plugins/io_mentor_cell/read.c (revision 30038) +++ trunk/src_plugins/io_mentor_cell/read.c (revision 30039) @@ -722,7 +722,7 @@ return; } - pid = pcb_pstk_proto_insert_dup(ctx->pcb->Data, &hps->proto, 1); + pid = pcb_pstk_proto_insert_dup(ctx->pcb->Data, &hps->proto, 1, 0); ps = pcb_pstk_alloc(ctx->pcb->Data); ps->Flags = DEFAULT_OBJ_FLAG; ps->x = vx; Index: trunk/src_plugins/io_mentor_cell/read_pstk.c =================================================================== --- trunk/src_plugins/io_mentor_cell/read_pstk.c (revision 30038) +++ trunk/src_plugins/io_mentor_cell/read_pstk.c (revision 30039) @@ -376,7 +376,7 @@ return; } - pid = pcb_pstk_proto_insert_dup(subc->data, &hpstk->proto, 1); + pid = pcb_pstk_proto_insert_dup(subc->data, &hpstk->proto, 1, 0); ps = pcb_pstk_alloc(subc->data); ps->Flags = DEFAULT_OBJ_FLAG; ps->x = px; Index: trunk/src_plugins/lib_compat_help/pstk_compat.c =================================================================== --- trunk/src_plugins/lib_compat_help/pstk_compat.c (revision 30038) +++ trunk/src_plugins/lib_compat_help/pstk_compat.c (revision 30039) @@ -179,7 +179,7 @@ proto.hplated = plated; pcb_pstk_proto_update(&proto); - pid = pcb_pstk_proto_insert_dup(data, &proto, 1); + pid = pcb_pstk_proto_insert_dup(data, &proto, 1, 0); if (pid == PCB_PADSTACK_INVALID) { compat_shape_free(&copper_master); return NULL; @@ -513,7 +513,7 @@ } pcb_pstk_proto_update(&proto); - pid = pcb_pstk_proto_insert_dup(data, &proto, 1); + pid = pcb_pstk_proto_insert_dup(data, &proto, 1, 0); for(n = 0; n < tshp.len; n++) compat_shape_free(&shape[n]); Index: trunk/src_plugins/lib_compat_help/pstk_help.c =================================================================== --- trunk/src_plugins/lib_compat_help/pstk_help.c (revision 30038) +++ trunk/src_plugins/lib_compat_help/pstk_help.c (revision 30039) @@ -44,7 +44,7 @@ proto.hplated = plated; pcb_pstk_proto_update(&proto); - pid = pcb_pstk_proto_insert_dup(data, &proto, 1); + pid = pcb_pstk_proto_insert_dup(data, &proto, 1, 0); return pcb_pstk_new(data, -1, pid, x, y, 0, pcb_flag_make(PCB_FLAG_CLEARLINE)); } @@ -303,7 +303,7 @@ proto.hplated = plated; pcb_pstk_proto_update(&proto); - pid = pcb_pstk_proto_insert_dup(data, &proto, 1); + pid = pcb_pstk_proto_insert_dup(data, &proto, 1, 0); if (pid == PCB_PADSTACK_INVALID) return NULL;