missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / o_find.c
blobc871e6aaf4947305e66bc01ce951142c785e7bc1
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <math.h>
23 #include <stdio.h>
25 #include "gschem.h"
28 /*! \brief Tests a if a given OBJECT was hit at a given set of coordinates
30 * \par Function Description
31 * Tests a if a given OBJECT was hit at a given set of coordinates. If an
32 * object is not selectable (e.g. it is locked), or it is invisible and
33 * not being rendered, this function will return FALSE.
35 * \param [in] w_current The GschemToplevel object.
36 * \param [in] object The OBJECT being hit-tested.
37 * \param [in] w_x The X coordinate to test (in world coords).
38 * \param [in] w_y The Y coordinate to test (in world coords).
39 * \param [in] w_slack The slack applied to the hit-test.
41 * \returns TRUE if the OBJECT was hit, otherwise FALSE.
43 static gboolean
44 is_object_hit (GschemToplevel *w_current, OBJECT *object,
45 int w_x, int w_y, int w_slack)
47 int left, top, right, bottom;
49 if (!object->selectable)
50 return FALSE;
52 /* We can't hit invisible (text) objects unless show_hidden_text is active.
54 if (!o_is_visible (object) && !w_current->toplevel->show_hidden_text)
55 return FALSE;
57 /* Do a coarse test first to avoid computing distances for objects ouside
58 * of the hit range.
60 if (!world_get_single_object_bounds(w_current->toplevel, object,
61 &left, &top, &right, &bottom) ||
62 !inside_region (left - w_slack, top - w_slack,
63 right + w_slack, bottom + w_slack,
64 w_x, w_y))
65 return FALSE;
67 return (o_shortest_distance (w_current->toplevel, object, w_x, w_y) < w_slack);
71 /*! \brief Tests a if a given OBJECT was hit at a given set of coordinates
73 * \par Function Description
74 * Tests a if a given OBJECT was hit at a given set of coordinates. If so,
75 * processes selection changes as appropriate for the object and passed
76 * flag. Saves a pointer to the found object so future find operations
77 * resume after this object.
79 * \param [in] w_current The GschemToplevel object.
80 * \param [in] object The OBJECT being hit-tested.
81 * \param [in] w_x The X coordinate to test (in world coords).
82 * \param [in] w_y The Y coordinate to test (in world coords).
83 * \param [in] w_slack The slack applied to the hit-test.
84 * \param [in] change_selection Whether to select the found object or not.
85 * \returns TRUE if the OBJECT was hit, otherwise FALSE.
87 static gboolean
88 find_single_object (GschemToplevel *w_current, OBJECT *object,
89 int w_x, int w_y, int w_slack,
90 int change_selection)
92 if (!is_object_hit (w_current, object, w_x, w_y, w_slack))
93 return FALSE;
95 if (change_selection) {
96 /* FIXME: should this be moved to o_select_object()? (Werner) */
97 if (object->type == OBJ_NET && w_current->net_selection_mode)
98 o_select_connected_nets (w_current, object);
99 else
100 o_select_object (w_current, object, SINGLE, 0); /* 0 is count */
103 w_current->toplevel->page_current->object_lastplace = object;
104 i_update_menus (w_current);
105 return TRUE;
109 /*! \brief Find an OBJECT at a given set of coordinates
111 * \par Function Description
112 * Tests for OBJECTS hit at a given set of coordinates. If
113 * change_selection is TRUE, it updates the page's selection.
115 * Find operations resume searching after the last object which was
116 * found, so multiple find operations at the same point will cycle
117 * through any objects on top of each other at this location.
119 * \param [in] w_current The GschemToplevel object.
120 * \param [in] w_x The X coordinate to test (in world coords).
121 * \param [in] w_y The Y coordinate to test (in world coords).
122 * \param [in] change_selection Whether to select the found object or not.
123 * \returns TRUE if the object was hit at the given coordinates,
124 * otherwise FALSE.
126 gboolean o_find_object (GschemToplevel *w_current, int w_x, int w_y,
127 gboolean change_selection)
129 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
130 g_return_val_if_fail (page_view != NULL, FALSE);
132 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
133 g_return_val_if_fail (toplevel != NULL, FALSE);
135 int w_slack;
136 const GList *iter = NULL;
138 w_slack = gschem_page_view_WORLDabs (page_view, w_current->select_slack_pixels);
140 /* Decide whether to iterate over all object or start at the last
141 found object. If there is more than one object below the
142 (w_x/w_y) position, this will select the next object below the
143 position point. You can change the selected object by clicking
144 at the same place multiple times. */
145 if (toplevel->page_current->object_lastplace != NULL) {
146 /* NB: g_list_find doesn't declare its input const, so we cast */
147 iter = g_list_find ((GList *)s_page_objects (toplevel->page_current),
148 toplevel->page_current->object_lastplace);
149 iter = g_list_next (iter);
152 /* do first search (if we found any objects after the last found object) */
153 while (iter != NULL) {
154 OBJECT *o_current = iter->data;
155 if (find_single_object (w_current, o_current,
156 w_x, w_y, w_slack, change_selection)) {
157 return TRUE;
159 iter = g_list_next (iter);
162 /* now search from the beginning up until the object_lastplace */
163 for (iter = s_page_objects (toplevel->page_current);
164 iter != NULL; iter = g_list_next (iter)) {
165 OBJECT *o_current = iter->data;
166 if (find_single_object (w_current, o_current,
167 w_x, w_y, w_slack, change_selection)) {
168 return TRUE;
170 /* break once we've inspected up to where we started the first loop */
171 if (o_current == toplevel->page_current->object_lastplace)
172 break;
175 /* didn't find anything.... reset lastplace */
176 toplevel->page_current->object_lastplace = NULL;
178 /* deselect everything only if shift key isn't pressed and
179 the caller allows it */
180 if (change_selection && (!w_current->SHIFTKEY)) {
181 o_select_unselect_all (w_current);
184 i_update_menus(w_current);
185 return FALSE;
188 /*! \todo Finish function documentation!!!
189 * \brief
190 * \par Function Description
193 gboolean
194 o_find_selected_object (GschemToplevel *w_current, int w_x, int w_y)
196 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
197 g_return_val_if_fail (page_view != NULL, FALSE);
199 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
200 g_return_val_if_fail (toplevel != NULL, FALSE);
202 int w_slack = gschem_page_view_WORLDabs (page_view, w_current->select_slack_pixels);
203 GList *s_current;
205 for (s_current = geda_list_get_glist (toplevel->page_current->selection_list);
206 s_current != NULL; s_current = g_list_next (s_current)) {
207 OBJECT *o_current = s_current->data;
209 if (is_object_hit (w_current, o_current, w_x, w_y, w_slack))
210 return TRUE;
213 return FALSE;