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
25 #include "actions.decl.x"
27 /* This works, but using one macro inside of other doesn't */
28 #define GET_PICTURE_WIDTH(w) \
29 abs((w)->second_wx - (w)->first_wx)
30 #define GET_PICTURE_HEIGHT(w) \
31 (w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio
32 #define GET_PICTURE_LEFT(w) \
33 min((w)->first_wx, (w)->second_wx)
34 #define GET_PICTURE_TOP(w) \
35 (w)->first_wy > (w)->second_wy ? (w)->first_wy : \
36 (w)->first_wy+abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio
38 /*! \brief Start process to input a new picture.
39 * \par Function Description
40 * This function starts the process to input a new picture. Parameters
41 * for this picture are put into/extracted from the <B>w_current</B> toplevel
43 * <B>w_x</B> and <B>w_y</B> are current coordinates of the pointer in world
46 * The first step is to input one corner of the picture. This corner is
47 * (<B>w_x</B>,<B>w_y</B>) snapped to the grid and saved in
48 * <B>w_current->first_wx</B> and <B>w_current->first_wy</B>.
50 * The other corner will be saved in (<B>w_current->second_wx</B>,
51 * <B>w_current->second_wy</B>).
53 * \param [in] w_current The GschemToplevel object.
54 * \param [in] w_x Current x coordinate of pointer in world units.
55 * \param [in] w_y Current y coordinate of pointer in world units.
57 void o_picture_start(GschemToplevel
*w_current
, int w_x
, int w_y
)
59 i_action_start (w_current
);
61 /* init first_w[x|y], second_w[x|y] to describe box */
62 w_current
->first_wx
= w_current
->second_wx
= w_x
;
63 w_current
->first_wy
= w_current
->second_wy
= w_y
;
65 /* start to draw the box */
66 o_picture_invalidate_rubber (w_current
);
67 w_current
->rubber_visible
= 1;
70 /*! \brief End the input of a circle.
71 * \par Function Description
72 * This function ends the input of the second corner of a picture.
73 * The picture is defined by (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>
74 * and (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>.
76 * The temporary picture frame is erased ; a new picture object is allocated,
77 * initialized and linked to the object list ; The object is finally
78 * drawn on the current sheet.
80 * \param [in] w_current The GschemToplevel object.
81 * \param [in] w_x (unused)
82 * \param [in] w_y (unused)
84 void o_picture_end(GschemToplevel
*w_current
, int w_x
, int w_y
)
86 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
88 int picture_width
, picture_height
;
89 int picture_left
, picture_top
;
91 g_assert( w_current
->inside_action
!= 0 );
93 /* erase the temporary picture */
94 /* o_picture_draw_rubber(w_current); */
95 w_current
->rubber_visible
= 0;
97 picture_width
= GET_PICTURE_WIDTH (w_current
);
98 picture_height
= GET_PICTURE_HEIGHT(w_current
);
99 picture_left
= GET_PICTURE_LEFT (w_current
);
100 picture_top
= GET_PICTURE_TOP (w_current
);
102 /* pictures with null width or height are not allowed */
103 if ((picture_width
!= 0) && (picture_height
!= 0)) {
105 /* create the object */
106 new_obj
= o_picture_new(toplevel
,
107 NULL
, 0, w_current
->pixbuf_filename
,
109 picture_left
, picture_top
,
110 picture_left
+ picture_width
,
111 picture_top
- picture_height
,
113 s_page_append (toplevel
, toplevel
->page_current
, new_obj
);
115 /* Run %add-objects-hook */
116 g_run_hook_object (w_current
, "%add-objects-hook", new_obj
);
118 gschem_toplevel_page_content_changed (w_current
, toplevel
->page_current
);
119 o_undo_savestate_old (w_current
, UNDO_ALL
, _("Add Picture"));
121 i_action_stop (w_current
);
124 /*! \brief Creates the add image dialog
125 * \par Function Description
126 * This function creates the add image dialog and loads the selected picture.
128 void picture_selection_dialog (GschemToplevel
*w_current
)
132 GError
*error
= NULL
;
134 w_current
->pfswindow
= gtk_file_chooser_dialog_new (_("Select a picture file..."),
135 GTK_WINDOW(w_current
->main_window
),
136 GTK_FILE_CHOOSER_ACTION_OPEN
,
142 /* Set the alternative button order (ok, cancel, help) for other systems */
143 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->pfswindow
),
148 if (w_current
->pixbuf_filename
)
149 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current
->pfswindow
),
150 w_current
->pixbuf_filename
);
152 if (gtk_dialog_run (GTK_DIALOG (w_current
->pfswindow
)) == GTK_RESPONSE_ACCEPT
) {
154 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current
->pfswindow
));
155 gtk_widget_destroy(w_current
->pfswindow
);
156 w_current
->pfswindow
=NULL
;
158 pixbuf
= gdk_pixbuf_new_from_file (filename
, &error
);
163 dialog
= gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
164 GTK_DIALOG_DESTROY_WITH_PARENT
,
167 _("Failed to load picture: %s"),
169 /* Wait for any user response */
170 gtk_dialog_run (GTK_DIALOG (dialog
));
172 g_error_free (error
);
173 gtk_widget_destroy(dialog
);
177 printf("Picture loaded succesfully.\n");
180 o_invalidate_rubber(w_current
);
181 i_update_middle_button (w_current
, action_add_picture
, _("Picture"));
182 i_action_stop (w_current
);
184 o_picture_set_pixbuf(w_current
, pixbuf
, filename
);
186 i_set_state(w_current
, PICTUREMODE
);
191 if (w_current
->pfswindow
) {
192 gtk_widget_destroy(w_current
->pfswindow
);
193 w_current
->pfswindow
=NULL
;
197 /*! \todo Finish function documentation!!!
199 * \par Function Description
202 * used in button cancel code in x_events.c
204 void o_picture_invalidate_rubber (GschemToplevel
*w_current
)
206 g_return_if_fail (w_current
!= NULL
);
208 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
209 g_return_if_fail (page_view
!= NULL
);
211 gschem_page_view_invalidate_world_rect (page_view
,
212 GET_PICTURE_LEFT (w_current
),
213 GET_PICTURE_TOP (w_current
),
214 GET_PICTURE_LEFT (w_current
) + GET_PICTURE_WIDTH (w_current
),
215 GET_PICTURE_TOP (w_current
) + GET_PICTURE_HEIGHT (w_current
));
218 /*! \brief Draw temporary picture while dragging edge.
219 * \par Function Description
220 * This function is used to draw the box while dragging one of its edge or
221 * angle. It erases the previous temporary box drawn before, and draws
222 * a new updated one. <B>w_x</B> and <B>w_y</B> are the new position of the mobile
223 * point, ie the mouse.
225 * The old values are inside the <B>w_current</B> pointed structure. Old
226 * width, height and left and top values are recomputed by the corresponding
229 * \param [in] w_current The GschemToplevel object.
230 * \param [in] w_x Current x coordinate of pointer in world units.
231 * \param [in] w_y Current y coordinate of pointer in world units.
233 void o_picture_motion (GschemToplevel
*w_current
, int w_x
, int w_y
)
236 printf("o_picture_rubberbox called\n");
238 g_assert( w_current
->inside_action
!= 0 );
240 /* erase the previous temporary box */
241 if (w_current
->rubber_visible
)
242 o_picture_invalidate_rubber (w_current
);
245 * New values are fixed according to the <B>w_x</B> and <B>w_y</B> parameters.
246 * These are saved in <B>w_current</B> pointed structure as new temporary values.
247 * The new box is then drawn.
250 /* update the coords of the corner */
251 w_current
->second_wx
= w_x
;
252 w_current
->second_wy
= w_y
;
254 /* draw the new temporary box */
255 o_picture_invalidate_rubber (w_current
);
256 w_current
->rubber_visible
= 1;
259 /*! \brief Draw picture from GschemToplevel object.
260 * \par Function Description
261 * This function draws the box from the variables in the GschemToplevel
262 * structure <B>*w_current</B>.
263 * One corner of the box is at (<B>w_current->first_wx</B>,
264 * <B>w_current->first_wy</B>) and the second corner is at
265 * (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>.
267 * \param [in] w_current The GschemToplevel object.
269 void o_picture_draw_rubber (GschemToplevel
*w_current
, EdaRenderer
*renderer
)
271 int left
, top
, width
, height
;
273 cairo_t
*cr
= eda_renderer_get_cairo_context (renderer
);
274 GArray
*color_map
= eda_renderer_get_color_map (renderer
);
275 int flags
= eda_renderer_get_cairo_flags (renderer
);
277 /* get the width/height and the upper left corner of the picture */
278 left
= GET_PICTURE_LEFT (w_current
);
279 top
= GET_PICTURE_TOP (w_current
);
280 width
= GET_PICTURE_WIDTH (w_current
);
281 height
= GET_PICTURE_HEIGHT (w_current
);
283 eda_cairo_box (cr
, flags
, wwidth
, left
, top
- height
, left
+ width
, top
);
284 eda_cairo_set_source_color (cr
, SELECT_COLOR
, color_map
);
285 eda_cairo_stroke (cr
, flags
, TYPE_SOLID
, END_NONE
, wwidth
, -1, -1);
288 /*! \brief Replace all selected pictures with a new picture
289 * \par Function Description
290 * Replaces all pictures in the current selection with a new image.
292 * \param [in] w_current The GschemToplevel object
293 * \param [in] filename The filename of the new picture
294 * \param [out] error The location to return error information.
295 * \return TRUE on success, FALSE on failure.
298 o_picture_exchange (GschemToplevel
*w_current
,
299 const gchar
*filename
, GError
**error
)
301 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
304 for (iter
= geda_list_get_glist (toplevel
->page_current
->selection_list
);
306 iter
= g_list_next (iter
)) {
308 OBJECT
*object
= (OBJECT
*) iter
->data
;
309 g_assert (object
!= NULL
);
311 if (object
->type
== OBJ_PICTURE
) {
314 /* Erase previous picture */
315 o_invalidate (w_current
, object
);
317 status
= o_picture_set_from_file (toplevel
, object
, filename
, error
);
318 if (!status
) return FALSE
;
320 /* Draw new picture */
321 o_invalidate (w_current
, object
);
327 /*! \brief Create dialog to exchange picture objects
328 * \par Function Description
329 * This function opens a file chooser and replaces all pictures of the selections
330 * with the new picture.
332 * \todo Maybe merge this dialog function with picture_selection_dialog()
334 void picture_change_filename_dialog (GschemToplevel
*w_current
)
336 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
339 GError
*error
= NULL
;
341 w_current
->pfswindow
= gtk_file_chooser_dialog_new (_("Select a picture file..."),
342 GTK_WINDOW(w_current
->main_window
),
343 GTK_FILE_CHOOSER_ACTION_OPEN
,
350 /* Set the alternative button order (ok, cancel, help) for other systems */
351 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->pfswindow
),
356 if (w_current
->pixbuf_filename
)
357 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current
->pfswindow
),
358 w_current
->pixbuf_filename
);
360 if (gtk_dialog_run (GTK_DIALOG (w_current
->pfswindow
)) == GTK_RESPONSE_ACCEPT
) {
362 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current
->pfswindow
));
363 gtk_widget_destroy(w_current
->pfswindow
);
364 w_current
->pfswindow
=NULL
;
366 /* Actually update the pictures */
367 result
= o_picture_exchange (w_current
, filename
, &error
);
372 dialog
= gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
373 GTK_DIALOG_DESTROY_WITH_PARENT
,
376 _("Failed to replace pictures: %s"),
378 /* Wait for any user response */
379 gtk_dialog_run (GTK_DIALOG (dialog
));
381 g_error_free (error
);
382 gtk_widget_destroy(dialog
);
384 gschem_toplevel_page_content_changed (w_current
, toplevel
->page_current
);
385 o_undo_savestate_old (w_current
, UNDO_ALL
, _("Replace Picture"));
390 if (w_current
->pfswindow
) {
391 gtk_widget_destroy(w_current
->pfswindow
);
392 w_current
->pfswindow
=NULL
;
396 /*! \todo Finish function documentation!!!
398 * \par Function Description
400 * \param [in] w_current The GschemToplevel object.
402 * \param [in] filename
404 void o_picture_set_pixbuf(GschemToplevel
*w_current
,
405 GdkPixbuf
*pixbuf
, char *filename
)
408 /* need to put an error messages here */
409 if (pixbuf
== NULL
) {
410 fprintf(stderr
, "error! picture in set pixbuf was NULL\n");
414 if (w_current
->current_pixbuf
!= NULL
) {
415 g_object_unref(w_current
->current_pixbuf
);
416 w_current
->current_pixbuf
=NULL
;
419 if (w_current
->pixbuf_filename
!= NULL
) {
420 g_free(w_current
->pixbuf_filename
);
421 w_current
->pixbuf_filename
=NULL
;
424 w_current
->current_pixbuf
= pixbuf
;
425 w_current
->pixbuf_filename
= (char *) g_strdup(filename
);
427 w_current
->pixbuf_wh_ratio
= (double) gdk_pixbuf_get_width(pixbuf
) /
428 gdk_pixbuf_get_height(pixbuf
);
430 /* be sure to free this pixbuf somewhere */