Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / a_zoom.c
blob3bc50d01d03738b873a326c9c1ce9801b8130830
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "gschem.h"
27 #ifdef HAVE_LIBDMALLOC
28 #include <dmalloc.h>
29 #endif
31 /* Kazu - discuss with Ales
32 * 1) rint
33 * 2) SWAP & SORT
36 /* Kazu on July 8, 1999 - added these macros to simplify the code */
37 /* keep these macros local to this file! KISS! */
38 /*! \brief */
39 #define GET_PAGE_WIDTH(w) \
40 ((w)->page_current->right - (w)->page_current->left)
41 /*! \brief */
42 #define GET_PAGE_HEIGHT(w) \
43 ((w)->page_current->bottom - (w)->page_current->top )
44 /*! \brief */
45 #define GET_PAGE_ASPECT_RATIO(w) \
46 ((float) fabs(GET_PAGE_WIDTH (w)) / \
47 (float) fabs(GET_PAGE_HEIGHT(w)))
50 /*! \todo Finish function documentation!!!
51 * \brief
52 * \par Function Description
55 /* dir is either ZOOM_IN, ZOOM_OUT or ZOOM_FULL which are defined in globals.h */
56 void a_zoom(GSCHEM_TOPLEVEL *w_current, int dir, int selected_from, int pan_flags)
58 TOPLEVEL *toplevel = w_current->toplevel;
59 double world_pan_center_x,world_pan_center_y,relativ_zoom_factor = - 1;
60 int start_x, start_y;
61 double top, bottom, right, left;
63 /* NB: w_current->zoom_gain is a percentage increase */
64 switch(dir) {
65 case(ZOOM_IN):
66 relativ_zoom_factor = (100.0 + w_current->zoom_gain) / 100.0;
67 break;
69 case(ZOOM_OUT):
70 relativ_zoom_factor = 100.0 / (100.0 + w_current->zoom_gain);
71 break;
73 case(ZOOM_FULL):
74 /* indicate the zoom full with a negative zoomfactor */
75 relativ_zoom_factor = -1;
76 break;
79 /* calc center: either "mouse_to_world" or center=center or a
80 virtual center if warp_cursor is disabled */
81 if (w_current->zoom_with_pan == TRUE && selected_from == HOTKEY) {
82 if (!x_event_get_pointer_position(w_current, FALSE,
83 &start_x, &start_y))
84 return;
85 if ( w_current->warp_cursor ) {
86 world_pan_center_x = start_x;
87 world_pan_center_y = start_y;
88 } else {
89 left = ((toplevel->page_current->left - start_x)
90 * (1/relativ_zoom_factor) + start_x);
91 right = ((toplevel->page_current->right - start_x)
92 * (1/relativ_zoom_factor) + start_x);
93 top = ((toplevel->page_current->top - start_y)
94 * (1/relativ_zoom_factor) + start_y);
95 bottom = ((toplevel->page_current->bottom - start_y)
96 * (1/relativ_zoom_factor) + start_y);
97 world_pan_center_x = (right + left) / 2;
98 world_pan_center_y = (top + bottom) / 2;
100 } else {
101 world_pan_center_x = (double) (toplevel->page_current->left +
102 toplevel->page_current->right ) / 2;
103 world_pan_center_y = (double) (toplevel->page_current->top +
104 toplevel->page_current->bottom ) / 2;
107 #if DEBUG
108 printf("relative zoomfactor: %E\n", relativ_zoom_factor);
109 printf("new center: x: %E, y: %E \n",
110 world_pan_center_x, world_pan_center_y);
111 #endif
114 /* calculate new window and draw it */
115 a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
116 relativ_zoom_factor, pan_flags);
118 /* Before warping the cursor, filter out any consecutive scroll events
119 * from the event queue. If the program receives more than one scroll
120 * event before it can process the first one, then the globals mouse_x
121 * and mouse_y won't contain the proper mouse position,
122 * because the handler for the mouse moved event needs to
123 * run first to set these values.
125 GdkEvent *topEvent = gdk_event_get();
126 while( topEvent != NULL ) {
127 if( topEvent->type != GDK_SCROLL ) {
128 gdk_event_put( topEvent );
129 gdk_event_free( topEvent );
130 break;
132 gdk_event_free( topEvent );
133 topEvent = gdk_event_get();
136 /* warp the cursor to the right position */
137 if (w_current->warp_cursor) {
138 WORLDtoSCREEN (w_current, world_pan_center_x, world_pan_center_y,
139 &start_x, &start_y);
140 x_basic_warp_cursor (w_current->drawing_area, start_x, start_y);
144 /*! \todo Finish function documentation!!!
145 * \brief
146 * \par Function Description
149 void a_zoom_extents (GSCHEM_TOPLEVEL *w_current, const GList *list, int pan_flags)
151 TOPLEVEL *toplevel = w_current->toplevel;
152 int lleft, lright, ltop, lbottom;
153 double zx, zy, relativ_zoom_factor;
154 double world_pan_center_x,world_pan_center_y;
156 if (list == NULL) {
157 return;
160 if (!world_get_object_glist_bounds (toplevel, list,
161 &lleft, &ltop,
162 &lright, &lbottom)) {
163 return;
166 #if DEBUG
167 printf("in a_zoom_extents: left: %d, right: %d, top: %d, bottom: %d\n",
168 lleft, lright, ltop, lbottom);
169 #endif
171 /* Calc the necessary zoomfactor to show everything
172 * Start with the windows width and height, then scale back to world
173 * coordinates with the to_screen_y_constant as the initial page data
174 * may not have the correct aspect ratio. */
175 zx = (double)toplevel->width / (lright-lleft);
176 zy = (double)toplevel->height / (lbottom-ltop);
177 /* choose the smaller one, 0.9 for paddings on all side*/
178 relativ_zoom_factor = (zx < zy ? zx : zy) * 0.9
179 / toplevel->page_current->to_screen_y_constant;
181 /*get the center of the objects*/
182 world_pan_center_x = (double) (lright + lleft) /2.0;
183 world_pan_center_y = (double) (lbottom + ltop) /2.0;
185 /* and create the new window*/
186 a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
187 relativ_zoom_factor, pan_flags );
189 /*! \bug FIXME? trigger a x_event_motion() call without moving the cursor
190 * this will redraw rubberband lines after zooming
191 * removed!, it has side effects in the preview of the part dialog
192 * need to find another way to trigger x_event_motion() (Werner)
194 /* x_basic_warp_cursor(w_current->drawing_area, mouse_x, mouse_y); */
198 /*! \todo Finish function documentation!!!
199 * \brief
200 * \par Function Description
203 void a_zoom_box(GSCHEM_TOPLEVEL *w_current, int pan_flags)
205 TOPLEVEL *toplevel = w_current->toplevel;
206 double zx, zy, relativ_zoom_factor;
207 double world_pan_center_x, world_pan_center_y;
209 /*test if there is really a box*/
210 if (w_current->first_wx == w_current->second_wx ||
211 w_current->first_wy == w_current->second_wy) {
212 s_log_message(_("Zoom too small! Cannot zoom further.\n"));
213 return;
216 /*calc new zoomfactors and choose the smaller one*/
217 zx = (double) abs(toplevel->page_current->left - toplevel->page_current->right) /
218 abs(w_current->first_wx - w_current->second_wx);
219 zy = (double) abs(toplevel->page_current->top - toplevel->page_current->bottom) /
220 abs(w_current->first_wy - w_current->second_wy);
222 relativ_zoom_factor = (zx < zy ? zx : zy);
224 /* calculate the center of the zoom box */
225 world_pan_center_x = (w_current->first_wx + w_current->second_wx) / 2.0;
226 world_pan_center_y = (w_current->first_wy + w_current->second_wy) / 2.0;
228 /* and create the new window*/
229 a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
230 relativ_zoom_factor, pan_flags);
233 /*! \todo Finish function documentation!!!
234 * \brief
235 * \par Function Description
238 void a_zoom_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
240 w_current->first_wx = w_current->second_wx = w_x;
241 w_current->first_wy = w_current->second_wy = w_y;
244 /*! \todo Finish function documentation!!!
245 * \brief
246 * \par Function Description
249 void a_zoom_box_end(GSCHEM_TOPLEVEL *w_current, int x, int y)
251 g_assert( w_current->inside_action != 0 );
253 a_zoom_box_invalidate_rubber (w_current);
254 w_current->rubber_visible = 0;
256 a_zoom_box(w_current, 0);
258 if (w_current->undo_panzoom) {
259 o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
263 /*! \todo Finish function documentation!!!
264 * \brief
265 * \par Function Description
268 void a_zoom_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
270 g_assert( w_current->inside_action != 0 );
272 if (w_current->rubber_visible)
273 a_zoom_box_invalidate_rubber (w_current);
275 w_current->second_wx = w_x;
276 w_current->second_wy = w_y;
278 a_zoom_box_invalidate_rubber (w_current);
279 w_current->rubber_visible = 1;
282 /*! \todo Finish function documentation!!!
283 * \brief
284 * \par Function Description
286 void a_zoom_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
288 int x1, y1, x2, y2;
290 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1);
291 WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2);
293 o_invalidate_rect (w_current, x1, y1, x2, y1);
294 o_invalidate_rect (w_current, x1, y1, x1, y2);
295 o_invalidate_rect (w_current, x2, y1, x2, y2);
296 o_invalidate_rect (w_current, x1, y2, x2, y2);
299 /*! \todo Finish function documentation!!!
300 * \brief
301 * \par Function Description
304 void a_zoom_box_draw_rubber (GSCHEM_TOPLEVEL *w_current)
306 gschem_cairo_box (w_current, 1, w_current->first_wx, w_current->first_wy,
307 w_current->second_wx, w_current->second_wy);
309 gschem_cairo_set_source_color (w_current,
310 x_color_lookup_dark (ZOOM_BOX_COLOR));
311 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
314 /*! \todo Finish function documentation!!!
315 * \brief
316 * \par Function Description
319 void correct_aspect(GSCHEM_TOPLEVEL *w_current)
321 TOPLEVEL *toplevel = w_current->toplevel;
322 double new_aspect;
324 new_aspect = GET_PAGE_ASPECT_RATIO(toplevel);
326 /* Make sure aspect ratio is correct */
327 if (fabs(new_aspect - toplevel->page_current->coord_aspectratio)) {
328 /* sign was > */
329 if (new_aspect > toplevel->page_current->coord_aspectratio) {
330 #if DEBUG
331 printf("new larger then coord\n");
332 printf("implies that height is too large\n");
333 #endif
334 /* calculate neccesary padding on Y */
335 toplevel->page_current->bottom =
336 toplevel->page_current->top +
337 GET_PAGE_WIDTH(toplevel) /
338 toplevel->page_current->coord_aspectratio;
340 } else {
341 #if DEBUG
342 printf("new smaller then coord\n");
343 printf("implies that width is too small\n");
344 #endif
345 /* calculate necessary padding on X */
346 toplevel->page_current->right =
347 toplevel->page_current->left +
348 GET_PAGE_HEIGHT(toplevel) *
349 toplevel->page_current->coord_aspectratio;
351 #if DEBUG
352 printf("invalid aspectratio corrected\n");
353 #endif
356 new_aspect = GET_PAGE_ASPECT_RATIO(toplevel);
358 #if DEBUG
359 printf("final %f\n", new_aspect);
360 #endif