/* * 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 "config.h" #include #include "event.h" #include #include #include #include #include "board.h" #include "conf_core.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "find.h" #include "brave.h" #include "tool_logic.h" static void tool_logic_chg_layer(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]); static void pcb_release_mode(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]); static void pcb_press_mode(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]); /*** Generic part, all rnd apps should do something like this ***/ static char tool_logic_cookie[] = "tool_logic"; static void tool_logic_chg_tool(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]) { int *ok = argv[1].d.p; int id = argv[2].d.i; pcb_board_t *pcb = (pcb_board_t *)hidlib; if (pcb->RatDraw && !(rnd_tool_get(id)->user_flags & PCB_TLF_RAT)) { rnd_message(RND_MSG_WARNING, "That tool can not be used on the rat layer!\n"); *ok = 0; } } static void tool_logic_chg_mode(rnd_conf_native_t *cfg, int arr_idx, void *user_data) { rnd_tool_chg_mode(&PCB->hidlib); } void pcb_tool_logic_init(void) { static rnd_conf_hid_callbacks_t cbs_mode; static rnd_conf_hid_id_t tool_conf_id; rnd_conf_native_t *n_mode = rnd_conf_get_field("editor/mode"); tool_conf_id = rnd_conf_hid_reg(tool_logic_cookie, NULL); if (n_mode != NULL) { memset(&cbs_mode, 0, sizeof(rnd_conf_hid_callbacks_t)); cbs_mode.val_change_post = tool_logic_chg_mode; rnd_conf_hid_set_cb(n_mode, tool_conf_id, &cbs_mode); } rnd_event_bind(RND_EVENT_TOOL_SELECT_PRE, tool_logic_chg_tool, NULL, tool_logic_cookie); rnd_event_bind(RND_EVENT_TOOL_RELEASE, pcb_release_mode, NULL, tool_logic_cookie); rnd_event_bind(RND_EVENT_TOOL_PRESS, pcb_press_mode, NULL, tool_logic_cookie); rnd_event_bind(PCB_EVENT_LAYERVIS_CHANGED, tool_logic_chg_layer, NULL, tool_logic_cookie); } void pcb_tool_logic_uninit(void) { rnd_event_unbind_allcookie(tool_logic_cookie); rnd_conf_hid_unreg(tool_logic_cookie); } /*** pcb-rnd-specific parts ***/ static void tool_logic_chg_layer(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]) { static int was_rat; if (PCB->RatDraw && !was_rat && !(rnd_tool_get(rnd_conf.editor.mode)->user_flags & PCB_TLF_RAT)) rnd_tool_select_by_name(&PCB->hidlib, "line"); was_rat = PCB->RatDraw; } static void get_grid_lock_coordinates(int type, void *ptr1, void *ptr2, void *ptr3, rnd_coord_t * x, rnd_coord_t * y) { switch (type) { case PCB_OBJ_LINE: *x = ((pcb_line_t *) ptr2)->Point1.X; *y = ((pcb_line_t *) ptr2)->Point1.Y; break; case PCB_OBJ_TEXT: *x = ((pcb_text_t *) ptr2)->X; *y = ((pcb_text_t *) ptr2)->Y; break; case PCB_OBJ_POLY: *x = ((pcb_poly_t *) ptr2)->Points[0].X; *y = ((pcb_poly_t *) ptr2)->Points[0].Y; break; case PCB_OBJ_LINE_POINT: case PCB_OBJ_POLY_POINT: case PCB_OBJ_GFX_POINT: *x = ((rnd_point_t *) ptr3)->X; *y = ((rnd_point_t *) ptr3)->Y; break; case PCB_OBJ_ARC: pcb_arc_get_end((pcb_arc_t *) ptr2, 0, x, y); break; case PCB_OBJ_ARC_POINT: if (ptr3 != NULL) /* need to check because: if snap off, there's no known endpoint (leave x;y as is, then) */ pcb_arc_get_end((pcb_arc_t *) ptr2, ((*(int **)ptr3) != pcb_arc_start_ptr), x, y); break; } } void pcb_tool_attach_for_copy(rnd_design_t *hl, rnd_coord_t PlaceX, rnd_coord_t PlaceY, rnd_bool do_rubberband) { rnd_coord_t mx = 0, my = 0; pcb_board_t *pcb = (pcb_board_t *)hl; if (conf_core.editor.auto_drc && (pcb_crosshair.AttachedObject.Type == PCB_OBJ_LINE_POINT) && (rnd_conf.editor.mode == pcb_crosshair.tool_move) && !(pcb_brave & PCB_BRAVE_NO_ENFORCE_CLR_MOVE)) { pcb_find_t fctx; pcb_line_t *line; /* clearance enforce on move: need to do a find on the given object to avoid self-intersect blocks on the same network */ memset(&fctx, 0, sizeof(fctx)); fctx.flag_set = PCB_FLAG_FOUND; fctx.flag_chg_undoable = 1; fctx.consider_rats = 1; pcb_find_from_xy(&fctx, pcb->Data, PlaceX, PlaceY); pcb_find_free(&fctx); /* set up the startpoint for the drc line enforcer */ pcb_crosshair.AttachedLine.Point1.X = PlaceX; pcb_crosshair.AttachedLine.Point1.Y = PlaceY; /* set line total thickness for enforcing the endpoint move gap */ line = pcb_crosshair.AttachedObject.Ptr2; if ((line != NULL) && (line->type == PCB_OBJ_LINE)) pcb_crosshair.AttachedLine.tot_thick = line->Thickness + line->Clearance+1; else pcb_crosshair.AttachedLine.tot_thick = conf_core.design.line_thickness + 2 * (conf_core.design.clearance + 1); } rnd_event(hl, PCB_EVENT_RUBBER_RESET, NULL); if (!conf_core.editor.snap_pin) { /* dither the grab point so that the mark, center, etc * will end up on a grid coordinate */ get_grid_lock_coordinates(pcb_crosshair.AttachedObject.Type, pcb_crosshair.AttachedObject.Ptr1, pcb_crosshair.AttachedObject.Ptr2, pcb_crosshair.AttachedObject.Ptr3, &mx, &my); mx = rnd_grid_fit(mx, hl->grid, hl->grid_ox) - mx; my = rnd_grid_fit(my, hl->grid, hl->grid_oy) - my; } pcb_crosshair.AttachedObject.X = PlaceX - mx; pcb_crosshair.AttachedObject.Y = PlaceY - my; if ((!pcb_marked.status || conf_core.editor.local_ref) && !pcb_marked.user_placed) pcb_crosshair_set_local_ref(PlaceX - mx, PlaceY - my, rnd_true); pcb_crosshair.AttachedObject.State = PCB_CH_STATE_SECOND; /* get all attached objects if necessary */ if (do_rubberband && conf_core.editor.rubber_band_mode) rnd_event(hl, PCB_EVENT_RUBBER_LOOKUP_LINES, "ippp", pcb_crosshair.AttachedObject.Type, pcb_crosshair.AttachedObject.Ptr1, pcb_crosshair.AttachedObject.Ptr2, pcb_crosshair.AttachedObject.Ptr3); if (do_rubberband && (pcb_crosshair.AttachedObject.Type == PCB_OBJ_SUBC || pcb_crosshair.AttachedObject.Type == PCB_OBJ_PSTK || pcb_crosshair.AttachedObject.Type == PCB_OBJ_LINE || pcb_crosshair.AttachedObject.Type == PCB_OBJ_LINE_POINT)) rnd_event(hl, PCB_EVENT_RUBBER_LOOKUP_RATS, "ippp", pcb_crosshair.AttachedObject.Type, pcb_crosshair.AttachedObject.Ptr1, pcb_crosshair.AttachedObject.Ptr2, pcb_crosshair.AttachedObject.Ptr3); } void pcb_tool_notify_block(void) { rnd_hid_notify_crosshair_change(&PCB->hidlib, rnd_false); switch (pcb_crosshair.AttachedBox.State) { case PCB_CH_STATE_FIRST: /* setup first point */ pcb_crosshair.AttachedBox.Point1.X = pcb_crosshair.AttachedBox.Point2.X = pcb_crosshair.X; pcb_crosshair.AttachedBox.Point1.Y = pcb_crosshair.AttachedBox.Point2.Y = pcb_crosshair.Y; pcb_crosshair.AttachedBox.State = PCB_CH_STATE_SECOND; break; case PCB_CH_STATE_SECOND: /* setup second point */ pcb_crosshair.AttachedBox.State = PCB_CH_STATE_THIRD; break; } rnd_hid_notify_crosshair_change(&PCB->hidlib, rnd_true); } /*** old helpers ***/ static void pcb_release_mode(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]) { pcb_draw(); } static void pcb_press_mode(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[]) { pcb_board_t *pcb = (pcb_board_t *)hidlib; if (conf_core.temp.rat_warn) { if (pcb_data_clear_flag(pcb->Data, PCB_FLAG_WARN, 1, 0) > 0) pcb_board_set_changed_flag(pcb, rnd_true); } pcb_draw(); }