1 /* Lepton EDA Schematic Capture
2  * Copyright (C) 1998-2010 Ales Hvezda
3  * Copyright (C) 1998-2015 gEDA Contributors
4  * Copyright (C) 2017-2021 Lepton EDA Contributors
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <config.h>
21 
22 #include <stdio.h>
23 #include <math.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 
28 #include "gschem.h"
29 
30 /*! \todo Finish function documentation!!!
31  *  \brief
32  *  \par Function Description
33  *
34  */
35 void
o_component_prepare_place(GschemToplevel * w_current,const CLibSymbol * sym)36 o_component_prepare_place (GschemToplevel *w_current,
37                            const CLibSymbol *sym)
38 {
39   GList *temp_list;
40   LeptonObject *o_current;
41   char *buffer;
42   const gchar *sym_name = s_clib_symbol_get_name (sym);
43   GError *err = NULL;
44 
45   LeptonPage *active_page = schematic_window_get_active_page (w_current);
46 
47   i_set_state (w_current, COMPMODE);
48   i_action_start (w_current);
49 
50   /* remove the old place list if it exists */
51   lepton_object_list_delete (active_page->place_list);
52   active_page->place_list = NULL;
53 
54   /* Insert the new object into the buffer at world coordinates (0,0).
55    * It will be translated to the mouse coordinates during placement. */
56 
57   w_current->first_wx = 0;
58   w_current->first_wy = 0;
59 
60   if (w_current->include_component) {
61 
62     temp_list = NULL;
63 
64     buffer = s_clib_symbol_get_data (sym);
65     temp_list = o_read_buffer (active_page,
66                                temp_list,
67                                buffer, -1,
68                                sym_name,
69                                &err);
70     g_free (buffer);
71 
72     if (err) {
73       /* If an error occurs here, we can assume that the preview also has failed to load,
74          and the error message is displayed there. We therefore ignore this error, but
75          end the component insertion.
76          */
77 
78       g_error_free(err);
79       i_set_state (w_current, SELECT);
80       i_action_stop (w_current);
81       return;
82     }
83 
84     /* Take the added objects */
85     active_page->place_list =
86       g_list_concat (active_page->place_list, temp_list);
87 
88   } else { /* if (w_current->include_component) {..} else { */
89     LeptonObject *new_object;
90 
91     new_object = lepton_component_new (active_page,
92                                        default_color_id(),
93                                        0,
94                                        0,
95                                        0,
96                                        0,
97                                        sym,
98                                        sym_name,
99                                        1);
100 
101     if (lepton_component_object_get_missing (new_object)) {
102       /* If created object is missing, the loading failed and we
103          end the insert action. */
104       lepton_object_delete (new_object);
105       i_set_state (w_current, SELECT);
106       i_action_stop (w_current);
107       return;
108     }
109     else {
110 
111       active_page->place_list =
112           g_list_concat (active_page->place_list,
113                          lepton_component_promote_attribs (new_object));
114       active_page->place_list =
115           g_list_append (active_page->place_list, new_object);
116 
117       /* Flag the symbol as embedded if necessary */
118       o_current = (LeptonObject*) (g_list_last (active_page->place_list))->data;
119       if (w_current->embed_component) {
120         lepton_component_object_set_embedded (o_current, TRUE);
121       }
122     }
123   }
124 
125   /* Run the component place list changed hook without redrawing */
126   /* since the place list is going to be redrawn afterwards */
127   o_component_place_changed_run_hook (w_current);
128 }
129 
130 
131 /*! \brief Run the component place list changed hook.
132  *  \par Function Description
133  *  The component place list is usually used when placing new components
134  *  in the schematic. This function should be called whenever that list
135  *  is modified.
136  *  \param [in] w_current GschemToplevel structure.
137  *
138  */
139 void
o_component_place_changed_run_hook(GschemToplevel * w_current)140 o_component_place_changed_run_hook (GschemToplevel *w_current)
141 {
142   GList *ptr = NULL;
143   LeptonPage *active_page = schematic_window_get_active_page (w_current);
144 
145   /* Run the component place list changed hook */
146   if (scm_is_false (scm_hook_empty_p (complex_place_list_changed_hook)) &&
147       active_page->place_list != NULL)
148   {
149     ptr = active_page->place_list;
150 
151     scm_dynwind_begin ((scm_t_dynwind_flags) 0);
152     g_dynwind_window (w_current);
153     while (ptr) {
154       SCM expr = scm_list_3 (scm_from_utf8_symbol ("run-hook"),
155                              complex_place_list_changed_hook,
156                              edascm_from_object ((LeptonObject *) ptr->data));
157       g_scm_eval_protected (expr, scm_interaction_environment ());
158       ptr = g_list_next(ptr);
159     }
160     scm_dynwind_end ();
161   }
162 }
163 
164 
165 /*! \todo Finish function documentation!!!
166  *  \brief
167  *  \par Function Description
168  *
169  *  \note
170  *  don't know if this belongs yet
171  */
172 void
o_component_translate_all(GschemToplevel * w_current,int offset)173 o_component_translate_all (GschemToplevel *w_current, int offset)
174 {
175   int w_rleft, w_rtop, w_rright, w_rbottom;
176   LeptonObject *o_current;
177   const GList *iter;
178   int x, y;
179   GschemPageView *view = gschem_toplevel_get_current_page_view (w_current);
180   g_return_if_fail (view != NULL);
181 
182   LeptonPage *active_page = schematic_window_get_active_page (w_current);
183 
184   gboolean show_hidden_text =
185     gschem_toplevel_get_show_hidden_text (w_current);
186 
187   /* first zoom extents */
188   gschem_page_view_zoom_extents (view, NULL);
189   gschem_page_view_invalidate_all (view);
190 
191   world_get_object_glist_bounds (lepton_page_objects (active_page),
192                                  show_hidden_text,
193                                  &w_rleft,  &w_rtop,
194                                  &w_rright, &w_rbottom);
195 
196   /*! \todo do we want snap grid here? */
197   x = snap_grid (w_current, w_rleft);
198   /* WARNING: w_rtop isn't the top of the bounds, it is the smaller
199    * y_coordinate, which represents in the bottom in world coords.
200    * These variables are as named from when screen-coords (which had
201    * the correct sense) were in use . */
202   y = snap_grid (w_current, w_rtop);
203 
204   for (iter = lepton_page_objects (active_page);
205        iter != NULL; iter = g_list_next (iter)) {
206     o_current = (LeptonObject*) iter->data;
207     s_conn_remove_object_connections (o_current);
208   }
209 
210   if (offset == 0) {
211     g_message (_("Translating schematic [%1$d %2$d]"), -x, -y);
212     lepton_object_list_translate (lepton_page_objects (active_page), -x, -y);
213   } else {
214     g_message (_("Translating schematic [%1$d %2$d]"),
215                offset, offset);
216     lepton_object_list_translate (lepton_page_objects (active_page), offset, offset);
217   }
218 
219   for (iter = lepton_page_objects (active_page);
220        iter != NULL;  iter = g_list_next (iter)) {
221     o_current = (LeptonObject*) iter->data;
222     s_conn_update_object (active_page, o_current);
223   }
224 
225   /* this is an experimental mod, to be able to translate to all
226    * places */
227   gschem_page_view_zoom_extents (view, NULL);
228   if (!w_current->SHIFTKEY) o_select_unselect_all(w_current);
229   gschem_page_view_invalidate_all (view);
230   gschem_toplevel_page_content_changed (w_current, active_page);
231   o_undo_savestate_old(w_current, UNDO_ALL);
232   i_update_menus(w_current);
233 }
234