gschem

a_zoom.c

Go to the documentation of this file.
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, &ltop,
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines