gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 #include <config.h> 00021 #include <math.h> 00022 #include <stdio.h> 00023 00024 #include "gschem.h" 00025 00026 /* This works, but using one macro inside of other doesn't */ 00027 #define GET_PICTURE_WIDTH(w) \ 00028 abs((w)->second_wx - (w)->first_wx) 00029 #define GET_PICTURE_HEIGHT(w) \ 00030 (w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio 00031 #define GET_PICTURE_LEFT(w) \ 00032 min((w)->first_wx, (w)->second_wx) 00033 #define GET_PICTURE_TOP(w) \ 00034 (w)->first_wy > (w)->second_wy ? (w)->first_wy : \ 00035 (w)->first_wy+abs((w)->second_wx - (w)->first_wx)/(w)->pixbuf_wh_ratio 00036 00056 void o_picture_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00057 { 00058 /* init first_w[x|y], second_w[x|y] to describe box */ 00059 w_current->first_wx = w_current->second_wx = w_x; 00060 w_current->first_wy = w_current->second_wy = w_y; 00061 00062 /* start to draw the box */ 00063 o_picture_invalidate_rubber (w_current); 00064 w_current->rubber_visible = 1; 00065 } 00066 00081 void o_picture_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00082 { 00083 TOPLEVEL *toplevel = w_current->toplevel; 00084 OBJECT *new_obj; 00085 int picture_width, picture_height; 00086 int picture_left, picture_top; 00087 00088 g_assert( w_current->inside_action != 0 ); 00089 00090 /* erase the temporary picture */ 00091 /* o_picture_draw_rubber(w_current); */ 00092 w_current->rubber_visible = 0; 00093 00094 picture_width = GET_PICTURE_WIDTH (w_current); 00095 picture_height = GET_PICTURE_HEIGHT(w_current); 00096 picture_left = GET_PICTURE_LEFT (w_current); 00097 picture_top = GET_PICTURE_TOP (w_current); 00098 00099 /* pictures with null width and height are not allowed */ 00100 if ((picture_width == 0) && (picture_height == 0)) { 00101 /* cancel the object creation */ 00102 return; 00103 } 00104 00105 /* create the object */ 00106 new_obj = o_picture_new(toplevel, 00107 NULL, 0, w_current->pixbuf_filename, 00108 OBJ_PICTURE, 00109 picture_left, picture_top, 00110 picture_left + picture_width, 00111 picture_top - picture_height, 00112 0, FALSE, FALSE); 00113 s_page_append (toplevel, toplevel->page_current, new_obj); 00114 00115 /* Run %add-objects-hook */ 00116 g_run_hook_object (w_current, "%add-objects-hook", new_obj); 00117 00118 toplevel->page_current->CHANGED = 1; 00119 o_undo_savestate(w_current, UNDO_ALL); 00120 } 00121 00126 void picture_selection_dialog (GSCHEM_TOPLEVEL *w_current) 00127 { 00128 TOPLEVEL *toplevel = w_current->toplevel; 00129 gchar *filename; 00130 GdkPixbuf *pixbuf; 00131 GError *error = NULL; 00132 00133 w_current->pfswindow = gtk_file_chooser_dialog_new ("Select a picture file...", 00134 GTK_WINDOW(w_current->main_window), 00135 GTK_FILE_CHOOSER_ACTION_OPEN, 00136 GTK_STOCK_CANCEL, 00137 GTK_RESPONSE_CANCEL, 00138 GTK_STOCK_OPEN, 00139 GTK_RESPONSE_ACCEPT, 00140 NULL); 00141 /* Set the alternative button order (ok, cancel, help) for other systems */ 00142 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->pfswindow), 00143 GTK_RESPONSE_ACCEPT, 00144 GTK_RESPONSE_CANCEL, 00145 -1); 00146 00147 if (w_current->pixbuf_filename) 00148 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current->pfswindow), 00149 w_current->pixbuf_filename); 00150 00151 if (gtk_dialog_run (GTK_DIALOG (w_current->pfswindow)) == GTK_RESPONSE_ACCEPT) { 00152 00153 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current->pfswindow)); 00154 gtk_widget_destroy(w_current->pfswindow); 00155 w_current->pfswindow=NULL; 00156 00157 pixbuf = gdk_pixbuf_new_from_file (filename, &error); 00158 00159 if (!pixbuf) { 00160 GtkWidget *dialog; 00161 00162 dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), 00163 GTK_DIALOG_DESTROY_WITH_PARENT, 00164 GTK_MESSAGE_ERROR, 00165 GTK_BUTTONS_CLOSE, 00166 _("Failed to load picture: %s"), 00167 error->message); 00168 /* Wait for any user response */ 00169 gtk_dialog_run (GTK_DIALOG (dialog)); 00170 00171 g_error_free (error); 00172 gtk_widget_destroy(dialog); 00173 } 00174 else { 00175 #if DEBUG 00176 printf("Picture loaded succesfully.\n"); 00177 #endif 00178 00179 o_invalidate_rubber(w_current); 00180 i_update_middle_button(w_current, i_callback_add_picture, _("Picture")); 00181 w_current->inside_action = 0; 00182 00183 o_picture_set_pixbuf(w_current, pixbuf, filename); 00184 00185 toplevel->page_current->CHANGED=1; 00186 i_set_state(w_current, DRAWPICTURE); 00187 } 00188 g_free (filename); 00189 } 00190 00191 i_update_toolbar(w_current); 00192 if (w_current->pfswindow) { 00193 gtk_widget_destroy(w_current->pfswindow); 00194 w_current->pfswindow=NULL; 00195 } 00196 } 00197 00205 void o_picture_invalidate_rubber (GSCHEM_TOPLEVEL *w_current) 00206 { 00207 int left, top, width, height; 00208 00209 WORLDtoSCREEN (w_current, 00210 GET_PICTURE_LEFT(w_current), GET_PICTURE_TOP(w_current), 00211 &left, &top); 00212 width = SCREENabs (w_current, GET_PICTURE_WIDTH (w_current)); 00213 height = SCREENabs (w_current, GET_PICTURE_HEIGHT(w_current)); 00214 00215 o_invalidate_rect (w_current, left, top, left + width, top); 00216 o_invalidate_rect (w_current, left, top, left, top + height); 00217 o_invalidate_rect (w_current, left + width, top, left + width, top + height); 00218 o_invalidate_rect (w_current, left, top + height, left + width, top + height); 00219 } 00220 00236 void o_picture_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00237 { 00238 #if DEBUG 00239 printf("o_picture_rubberbox called\n"); 00240 #endif 00241 g_assert( w_current->inside_action != 0 ); 00242 00243 /* erase the previous temporary box */ 00244 if (w_current->rubber_visible) 00245 o_picture_invalidate_rubber (w_current); 00246 00247 /* 00248 * New values are fixed according to the <B>w_x</B> and <B>w_y</B> parameters. 00249 * These are saved in <B>w_current</B> pointed structure as new temporary values. 00250 * The new box is then drawn. 00251 */ 00252 00253 /* update the coords of the corner */ 00254 w_current->second_wx = w_x; 00255 w_current->second_wy = w_y; 00256 00257 /* draw the new temporary box */ 00258 o_picture_invalidate_rubber (w_current); 00259 w_current->rubber_visible = 1; 00260 } 00261 00272 void o_picture_draw_rubber (GSCHEM_TOPLEVEL *w_current) 00273 { 00274 int left, top, width, height; 00275 00276 /* get the width/height and the upper left corner of the picture */ 00277 left = GET_PICTURE_LEFT (w_current); 00278 top = GET_PICTURE_TOP (w_current); 00279 width = GET_PICTURE_WIDTH (w_current); 00280 height = GET_PICTURE_HEIGHT (w_current); 00281 00282 gschem_cairo_box (w_current, 0, left, top - height, left + width, top); 00283 00284 gschem_cairo_set_source_color (w_current, 00285 x_color_lookup_dark (SELECT_COLOR)); 00286 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00287 } 00288 00302 void o_picture_draw (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00303 { 00304 int s_upper_x, s_upper_y, s_lower_x, s_lower_y; 00305 GdkPixbuf *pixbuf; 00306 00307 g_return_if_fail (w_current != NULL); 00308 g_return_if_fail (w_current->toplevel != NULL); 00309 g_return_if_fail (o_current != NULL); 00310 g_return_if_fail (o_current->picture != NULL); 00311 00312 pixbuf = o_picture_get_pixbuf (w_current->toplevel, o_current); 00313 00314 /* If the image failed to load, get the fallback image. */ 00315 if (pixbuf == NULL) pixbuf = o_picture_get_fallback_pixbuf (w_current->toplevel); 00316 /* If the fallback image failed to load, draw a box with a cross in it. */ 00317 if (pixbuf == NULL) { 00318 int line_width = (w_current->toplevel->line_style == THICK) ? LINE_WIDTH : 2; 00319 gschem_cairo_set_source_color (w_current, 00320 o_drawing_color (w_current, o_current)); 00321 gschem_cairo_box (w_current, line_width, 00322 o_current->picture->lower_x, o_current->picture->lower_y, 00323 o_current->picture->upper_x, o_current->picture->upper_y); 00324 gschem_cairo_line (w_current, END_ROUND, line_width, 00325 o_current->picture->lower_x, o_current->picture->lower_y, 00326 o_current->picture->upper_x, o_current->picture->upper_y); 00327 gschem_cairo_line (w_current, END_ROUND, line_width, 00328 o_current->picture->lower_x, o_current->picture->upper_y, 00329 o_current->picture->upper_x, o_current->picture->lower_y); 00330 gschem_cairo_stroke (w_current, TYPE_SOLID, END_ROUND, line_width, -1, -1); 00331 return; 00332 } 00333 00334 g_assert (GDK_IS_PIXBUF (pixbuf)); 00335 00336 WORLDtoSCREEN (w_current, o_current->picture->upper_x, 00337 o_current->picture->upper_y, &s_upper_x, &s_upper_y); 00338 WORLDtoSCREEN (w_current, o_current->picture->lower_x, 00339 o_current->picture->lower_y, &s_lower_x, &s_lower_y); 00340 00341 cairo_save (w_current->cr); 00342 00343 int swap_wh = (o_current->picture->angle == 90 || o_current->picture->angle == 270); 00344 float orig_width = swap_wh ? gdk_pixbuf_get_height (pixbuf) : 00345 gdk_pixbuf_get_width (pixbuf); 00346 float orig_height = swap_wh ? gdk_pixbuf_get_width (pixbuf) : 00347 gdk_pixbuf_get_height (pixbuf); 00348 00349 cairo_translate (w_current->cr, s_upper_x, s_upper_y); 00350 cairo_scale (w_current->cr, 00351 (float)SCREENabs (w_current, abs (o_current->picture->upper_x - 00352 o_current->picture->lower_x)) / orig_width, 00353 (float)SCREENabs (w_current, abs (o_current->picture->upper_y - 00354 o_current->picture->lower_y)) / orig_height); 00355 00356 /* Evil magic translates picture origin to the right position for a given rotation */ 00357 switch (o_current->picture->angle) { 00358 case 0: break; 00359 case 90: cairo_translate (w_current->cr, 0, orig_height); break; 00360 case 180: cairo_translate (w_current->cr, orig_width, orig_height); break; 00361 case 270: cairo_translate (w_current->cr, orig_width, 0 ); break; 00362 } 00363 cairo_rotate (w_current->cr, -o_current->picture->angle * M_PI / 180.); 00364 if (o_current->picture->mirrored) { 00365 cairo_translate (w_current->cr, gdk_pixbuf_get_width (pixbuf), 0); 00366 cairo_scale (w_current->cr, -1, 1); 00367 } 00368 00369 gdk_cairo_set_source_pixbuf (w_current->cr, 00370 pixbuf, 0,0); 00371 cairo_rectangle (w_current->cr, 0, 0, 00372 gdk_pixbuf_get_width (pixbuf), 00373 gdk_pixbuf_get_height (pixbuf)); 00374 00375 cairo_clip (w_current->cr); 00376 cairo_paint (w_current->cr); 00377 cairo_restore (w_current->cr); 00378 00379 /* Grip specific stuff */ 00380 if (o_current->selected && w_current->draw_grips) { 00381 o_picture_draw_grips (w_current, o_current); 00382 } 00383 00384 g_object_unref (pixbuf); 00385 } 00386 00395 void o_picture_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00396 { 00397 if (w_current->draw_grips == FALSE) 00398 return; 00399 00400 /* grip on upper left corner (whichone = PICTURE_UPPER_LEFT) */ 00401 o_grips_draw (w_current, o_current->picture->upper_x, 00402 o_current->picture->upper_y); 00403 00404 /* grip on upper right corner (whichone = PICTURE_UPPER_RIGHT) */ 00405 o_grips_draw (w_current, o_current->picture->lower_x, 00406 o_current->picture->upper_y); 00407 00408 /* grip on lower left corner (whichone = PICTURE_LOWER_LEFT) */ 00409 o_grips_draw (w_current, o_current->picture->upper_x, 00410 o_current->picture->lower_y); 00411 00412 /* grip on lower right corner (whichone = PICTURE_LOWER_RIGHT) */ 00413 o_grips_draw (w_current, o_current->picture->lower_x, 00414 o_current->picture->lower_y); 00415 00416 /* Box surrounding the picture */ 00417 gschem_cairo_box (w_current, 0, 00418 o_current->picture->upper_x, o_current->picture->upper_y, 00419 o_current->picture->lower_x, o_current->picture->lower_y); 00420 00421 gschem_cairo_set_source_color (w_current, 00422 x_color_lookup_dark (SELECT_COLOR)); 00423 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00424 } 00425 00426 00440 void o_picture_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current) 00441 { 00442 if (o_current->picture == NULL) { 00443 return; 00444 } 00445 00446 gschem_cairo_box (w_current, 0, o_current->picture->upper_x + dx, 00447 o_current->picture->upper_y + dy, 00448 o_current->picture->lower_x + dx, 00449 o_current->picture->lower_y + dy); 00450 00451 gschem_cairo_set_source_color (w_current, 00452 x_color_lookup_dark (o_current->color)); 00453 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00454 } 00455 00465 gboolean 00466 o_picture_exchange (GSCHEM_TOPLEVEL *w_current, 00467 const gchar *filename, GError **error) 00468 { 00469 TOPLEVEL *toplevel = w_current->toplevel; 00470 GList *iter; 00471 00472 for (iter = geda_list_get_glist (toplevel->page_current->selection_list); 00473 iter != NULL; 00474 iter = g_list_next (iter)) { 00475 00476 OBJECT *object = (OBJECT *) iter->data; 00477 g_assert (object != NULL); 00478 00479 if (object->type == OBJ_PICTURE) { 00480 gboolean status; 00481 00482 /* Erase previous picture */ 00483 o_invalidate (w_current, object); 00484 00485 status = o_picture_set_from_file (toplevel, object, filename, error); 00486 if (!status) return FALSE; 00487 00488 /* Draw new picture */ 00489 o_invalidate (w_current, object); 00490 } 00491 } 00492 return TRUE; 00493 } 00494 00502 void picture_change_filename_dialog (GSCHEM_TOPLEVEL *w_current) 00503 { 00504 TOPLEVEL *toplevel = w_current->toplevel; 00505 gchar *filename; 00506 gboolean result; 00507 GError *error = NULL; 00508 00509 w_current->pfswindow = gtk_file_chooser_dialog_new ("Select a picture file...", 00510 GTK_WINDOW(w_current->main_window), 00511 GTK_FILE_CHOOSER_ACTION_OPEN, 00512 GTK_STOCK_CANCEL, 00513 GTK_RESPONSE_CANCEL, 00514 GTK_STOCK_OPEN, 00515 GTK_RESPONSE_ACCEPT, 00516 NULL); 00517 00518 /* Set the alternative button order (ok, cancel, help) for other systems */ 00519 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->pfswindow), 00520 GTK_RESPONSE_ACCEPT, 00521 GTK_RESPONSE_CANCEL, 00522 -1); 00523 00524 if (w_current->pixbuf_filename) 00525 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w_current->pfswindow), 00526 w_current->pixbuf_filename); 00527 00528 if (gtk_dialog_run (GTK_DIALOG (w_current->pfswindow)) == GTK_RESPONSE_ACCEPT) { 00529 00530 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current->pfswindow)); 00531 gtk_widget_destroy(w_current->pfswindow); 00532 w_current->pfswindow=NULL; 00533 00534 /* Actually update the pictures */ 00535 result = o_picture_exchange (w_current, filename, &error); 00536 00537 if (!result) { 00538 GtkWidget *dialog; 00539 00540 dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), 00541 GTK_DIALOG_DESTROY_WITH_PARENT, 00542 GTK_MESSAGE_ERROR, 00543 GTK_BUTTONS_CLOSE, 00544 _("Failed to replace pictures: %s"), 00545 error->message); 00546 /* Wait for any user response */ 00547 gtk_dialog_run (GTK_DIALOG (dialog)); 00548 00549 g_error_free (error); 00550 gtk_widget_destroy(dialog); 00551 } else { 00552 toplevel->page_current->CHANGED=1; 00553 } 00554 g_free (filename); 00555 } 00556 00557 i_update_toolbar(w_current); 00558 if (w_current->pfswindow) { 00559 gtk_widget_destroy(w_current->pfswindow); 00560 w_current->pfswindow=NULL; 00561 } 00562 } 00563 00572 void o_picture_set_pixbuf(GSCHEM_TOPLEVEL *w_current, 00573 GdkPixbuf *pixbuf, char *filename) 00574 { 00575 00576 /* need to put an error messages here */ 00577 if (pixbuf == NULL) { 00578 fprintf(stderr, "error! picture in set pixbuf was NULL\n"); 00579 return; 00580 } 00581 00582 if (w_current->current_pixbuf != NULL) { 00583 g_object_unref(w_current->current_pixbuf); 00584 w_current->current_pixbuf=NULL; 00585 } 00586 00587 if (w_current->pixbuf_filename != NULL) { 00588 g_free(w_current->pixbuf_filename); 00589 w_current->pixbuf_filename=NULL; 00590 } 00591 00592 w_current->current_pixbuf = pixbuf; 00593 w_current->pixbuf_filename = (char *) g_strdup(filename); 00594 00595 w_current->pixbuf_wh_ratio = (double) gdk_pixbuf_get_width(pixbuf) / 00596 gdk_pixbuf_get_height(pixbuf); 00597 00598 /* be sure to free this pixbuf somewhere */ 00599 }