gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 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 00022 #include <stdio.h> 00023 #include <math.h> 00024 00025 #include "gschem.h" 00026 00027 #ifdef HAVE_LIBDMALLOC 00028 #include <dmalloc.h> 00029 #endif 00030 00031 /* Kazu - discuss with Ales 00032 * 1) rint 00033 * 2) SWAP & SORT 00034 */ 00035 00036 /* Kazu on July 8, 1999 - added these macros to simplify the code */ 00037 /* keep these macros local to this file! KISS! */ 00039 #define GET_PAGE_WIDTH(w) \ 00040 ((w)->page_current->right - (w)->page_current->left) 00041 00042 #define GET_PAGE_HEIGHT(w) \ 00043 ((w)->page_current->bottom - (w)->page_current->top ) 00044 00045 #define GET_PAGE_ASPECT_RATIO(w) \ 00046 ((float) fabs(GET_PAGE_WIDTH (w)) / \ 00047 (float) fabs(GET_PAGE_HEIGHT(w))) 00048 00049 00055 /* dir is either ZOOM_IN, ZOOM_OUT or ZOOM_FULL which are defined in globals.h */ 00056 void a_zoom(GSCHEM_TOPLEVEL *w_current, int dir, int selected_from, int pan_flags) 00057 { 00058 TOPLEVEL *toplevel = w_current->toplevel; 00059 double world_pan_center_x,world_pan_center_y,relativ_zoom_factor = - 1; 00060 int start_x, start_y; 00061 double top, bottom, right, left; 00062 00063 /* NB: w_current->zoom_gain is a percentage increase */ 00064 switch(dir) { 00065 case(ZOOM_IN): 00066 relativ_zoom_factor = (100.0 + w_current->zoom_gain) / 100.0; 00067 break; 00068 00069 case(ZOOM_OUT): 00070 relativ_zoom_factor = 100.0 / (100.0 + w_current->zoom_gain); 00071 break; 00072 00073 case(ZOOM_FULL): 00074 /* indicate the zoom full with a negative zoomfactor */ 00075 relativ_zoom_factor = -1; 00076 break; 00077 } 00078 00079 /* calc center: either "mouse_to_world" or center=center or a 00080 virtual center if warp_cursor is disabled */ 00081 if (w_current->zoom_with_pan == TRUE && selected_from == HOTKEY) { 00082 if (!x_event_get_pointer_position(w_current, FALSE, 00083 &start_x, &start_y)) 00084 return; 00085 if ( w_current->warp_cursor ) { 00086 world_pan_center_x = start_x; 00087 world_pan_center_y = start_y; 00088 } else { 00089 left = ((toplevel->page_current->left - start_x) 00090 * (1/relativ_zoom_factor) + start_x); 00091 right = ((toplevel->page_current->right - start_x) 00092 * (1/relativ_zoom_factor) + start_x); 00093 top = ((toplevel->page_current->top - start_y) 00094 * (1/relativ_zoom_factor) + start_y); 00095 bottom = ((toplevel->page_current->bottom - start_y) 00096 * (1/relativ_zoom_factor) + start_y); 00097 world_pan_center_x = (right + left) / 2; 00098 world_pan_center_y = (top + bottom) / 2; 00099 } 00100 } else { 00101 world_pan_center_x = (double) (toplevel->page_current->left + 00102 toplevel->page_current->right ) / 2; 00103 world_pan_center_y = (double) (toplevel->page_current->top + 00104 toplevel->page_current->bottom ) / 2; 00105 } 00106 00107 #if DEBUG 00108 printf("relative zoomfactor: %E\n", relativ_zoom_factor); 00109 printf("new center: x: %E, y: %E \n", 00110 world_pan_center_x, world_pan_center_y); 00111 #endif 00112 00113 00114 /* calculate new window and draw it */ 00115 a_pan_general(w_current, world_pan_center_x, world_pan_center_y, 00116 relativ_zoom_factor, pan_flags); 00117 00118 /* Before warping the cursor, filter out any consecutive scroll events 00119 * from the event queue. If the program receives more than one scroll 00120 * event before it can process the first one, then the globals mouse_x 00121 * and mouse_y won't contain the proper mouse position, 00122 * because the handler for the mouse moved event needs to 00123 * run first to set these values. 00124 */ 00125 GdkEvent *topEvent = gdk_event_get(); 00126 while( topEvent != NULL ) { 00127 if( topEvent->type != GDK_SCROLL ) { 00128 gdk_event_put( topEvent ); 00129 gdk_event_free( topEvent ); 00130 break; 00131 } 00132 gdk_event_free( topEvent ); 00133 topEvent = gdk_event_get(); 00134 } 00135 00136 /* warp the cursor to the right position */ 00137 if (w_current->warp_cursor) { 00138 WORLDtoSCREEN (w_current, world_pan_center_x, world_pan_center_y, 00139 &start_x, &start_y); 00140 x_basic_warp_cursor (w_current->drawing_area, start_x, start_y); 00141 } 00142 } 00143 00149 void a_zoom_extents (GSCHEM_TOPLEVEL *w_current, const GList *list, int pan_flags) 00150 { 00151 TOPLEVEL *toplevel = w_current->toplevel; 00152 int lleft, lright, ltop, lbottom; 00153 double zx, zy, relativ_zoom_factor; 00154 double world_pan_center_x,world_pan_center_y; 00155 00156 if (list == NULL) { 00157 return; 00158 } 00159 00160 if (!world_get_object_glist_bounds (toplevel, list, 00161 &lleft, <op, 00162 &lright, &lbottom)) { 00163 return; 00164 } 00165 00166 #if DEBUG 00167 printf("in a_zoom_extents: left: %d, right: %d, top: %d, bottom: %d\n", 00168 lleft, lright, ltop, lbottom); 00169 #endif 00170 00171 /* Calc the necessary zoomfactor to show everything 00172 * Start with the windows width and height, then scale back to world 00173 * coordinates with the to_screen_y_constant as the initial page data 00174 * may not have the correct aspect ratio. */ 00175 zx = (double)toplevel->width / (lright-lleft); 00176 zy = (double)toplevel->height / (lbottom-ltop); 00177 /* choose the smaller one, 0.9 for paddings on all side*/ 00178 relativ_zoom_factor = (zx < zy ? zx : zy) * 0.9 00179 / toplevel->page_current->to_screen_y_constant; 00180 00181 /*get the center of the objects*/ 00182 world_pan_center_x = (double) (lright + lleft) /2.0; 00183 world_pan_center_y = (double) (lbottom + ltop) /2.0; 00184 00185 /* and create the new window*/ 00186 a_pan_general(w_current, world_pan_center_x, world_pan_center_y, 00187 relativ_zoom_factor, pan_flags ); 00188 00194 /* x_basic_warp_cursor(w_current->drawing_area, mouse_x, mouse_y); */ 00195 00196 } 00197 00203 void a_zoom_box(GSCHEM_TOPLEVEL *w_current, int pan_flags) 00204 { 00205 TOPLEVEL *toplevel = w_current->toplevel; 00206 double zx, zy, relativ_zoom_factor; 00207 double world_pan_center_x, world_pan_center_y; 00208 00209 /*test if there is really a box*/ 00210 if (w_current->first_wx == w_current->second_wx || 00211 w_current->first_wy == w_current->second_wy) { 00212 s_log_message(_("Zoom too small! Cannot zoom further.\n")); 00213 return; 00214 } 00215 00216 /*calc new zoomfactors and choose the smaller one*/ 00217 zx = (double) abs(toplevel->page_current->left - toplevel->page_current->right) / 00218 abs(w_current->first_wx - w_current->second_wx); 00219 zy = (double) abs(toplevel->page_current->top - toplevel->page_current->bottom) / 00220 abs(w_current->first_wy - w_current->second_wy); 00221 00222 relativ_zoom_factor = (zx < zy ? zx : zy); 00223 00224 /* calculate the center of the zoom box */ 00225 world_pan_center_x = (w_current->first_wx + w_current->second_wx) / 2.0; 00226 world_pan_center_y = (w_current->first_wy + w_current->second_wy) / 2.0; 00227 00228 /* and create the new window*/ 00229 a_pan_general(w_current, world_pan_center_x, world_pan_center_y, 00230 relativ_zoom_factor, pan_flags); 00231 } 00232 00238 void a_zoom_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00239 { 00240 w_current->first_wx = w_current->second_wx = w_x; 00241 w_current->first_wy = w_current->second_wy = w_y; 00242 } 00243 00249 void a_zoom_box_end(GSCHEM_TOPLEVEL *w_current, int x, int y) 00250 { 00251 g_assert( w_current->inside_action != 0 ); 00252 00253 a_zoom_box_invalidate_rubber (w_current); 00254 w_current->rubber_visible = 0; 00255 00256 a_zoom_box(w_current, 0); 00257 00258 if (w_current->undo_panzoom) { 00259 o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY); 00260 } 00261 } 00262 00268 void a_zoom_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00269 { 00270 g_assert( w_current->inside_action != 0 ); 00271 00272 if (w_current->rubber_visible) 00273 a_zoom_box_invalidate_rubber (w_current); 00274 00275 w_current->second_wx = w_x; 00276 w_current->second_wy = w_y; 00277 00278 a_zoom_box_invalidate_rubber (w_current); 00279 w_current->rubber_visible = 1; 00280 } 00281 00286 void a_zoom_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current) 00287 { 00288 int x1, y1, x2, y2; 00289 00290 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1); 00291 WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2); 00292 00293 o_invalidate_rect (w_current, x1, y1, x2, y1); 00294 o_invalidate_rect (w_current, x1, y1, x1, y2); 00295 o_invalidate_rect (w_current, x2, y1, x2, y2); 00296 o_invalidate_rect (w_current, x1, y2, x2, y2); 00297 } 00298 00304 void a_zoom_box_draw_rubber (GSCHEM_TOPLEVEL *w_current) 00305 { 00306 gschem_cairo_box (w_current, 1, w_current->first_wx, w_current->first_wy, 00307 w_current->second_wx, w_current->second_wy); 00308 00309 gschem_cairo_set_source_color (w_current, 00310 x_color_lookup_dark (ZOOM_BOX_COLOR)); 00311 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00312 } 00313 00319 void correct_aspect(GSCHEM_TOPLEVEL *w_current) 00320 { 00321 TOPLEVEL *toplevel = w_current->toplevel; 00322 double new_aspect; 00323 00324 new_aspect = GET_PAGE_ASPECT_RATIO(toplevel); 00325 00326 /* Make sure aspect ratio is correct */ 00327 if (fabs(new_aspect - toplevel->page_current->coord_aspectratio)) { 00328 /* sign was > */ 00329 if (new_aspect > toplevel->page_current->coord_aspectratio) { 00330 #if DEBUG 00331 printf("new larger then coord\n"); 00332 printf("implies that height is too large\n"); 00333 #endif 00334 /* calculate neccesary padding on Y */ 00335 toplevel->page_current->bottom = 00336 toplevel->page_current->top + 00337 GET_PAGE_WIDTH(toplevel) / 00338 toplevel->page_current->coord_aspectratio; 00339 00340 } else { 00341 #if DEBUG 00342 printf("new smaller then coord\n"); 00343 printf("implies that width is too small\n"); 00344 #endif 00345 /* calculate necessary padding on X */ 00346 toplevel->page_current->right = 00347 toplevel->page_current->left + 00348 GET_PAGE_HEIGHT(toplevel) * 00349 toplevel->page_current->coord_aspectratio; 00350 } 00351 #if DEBUG 00352 printf("invalid aspectratio corrected\n"); 00353 #endif 00354 } 00355 00356 new_aspect = GET_PAGE_ASPECT_RATIO(toplevel); 00357 00358 #if DEBUG 00359 printf("final %f\n", new_aspect); 00360 #endif 00361 }