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
27 #ifdef HAVE_LIBDMALLOC
31 /* Kazu - discuss with Ales
36 /* Kazu on July 8, 1999 - added these macros to simplify the code */
37 /* keep these macros local to this file! KISS! */
39 #define GET_PAGE_WIDTH(w) \
40 ((w)->page_current->right - (w)->page_current->left)
42 #define GET_PAGE_HEIGHT(w) \
43 ((w)->page_current->bottom - (w)->page_current->top )
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!!!
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;
61 double top
, bottom
, right
, left
;
63 /* NB: w_current->zoom_gain is a percentage increase */
66 relativ_zoom_factor
= (100.0 + w_current
->zoom_gain
) / 100.0;
70 relativ_zoom_factor
= 100.0 / (100.0 + w_current
->zoom_gain
);
74 /* indicate the zoom full with a negative zoomfactor */
75 relativ_zoom_factor
= -1;
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
,
85 if ( w_current
->warp_cursor
) {
86 world_pan_center_x
= start_x
;
87 world_pan_center_y
= start_y
;
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;
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;
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
);
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
);
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
,
140 x_basic_warp_cursor (w_current
->drawing_area
, start_x
, start_y
);
144 /*! \todo Finish function documentation!!!
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
;
160 if (!world_get_object_glist_bounds (toplevel
, list
,
162 &lright
, &lbottom
)) {
167 printf("in a_zoom_extents: left: %d, right: %d, top: %d, bottom: %d\n",
168 lleft
, lright
, ltop
, lbottom
);
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!!!
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"));
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!!!
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!!!
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!!!
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!!!
284 * \par Function Description
286 void a_zoom_box_invalidate_rubber (GSCHEM_TOPLEVEL
*w_current
)
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!!!
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!!!
316 * \par Function Description
319 void correct_aspect(GSCHEM_TOPLEVEL
*w_current
)
321 TOPLEVEL
*toplevel
= w_current
->toplevel
;
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
)) {
329 if (new_aspect
> toplevel
->page_current
->coord_aspectratio
) {
331 printf("new larger then coord\n");
332 printf("implies that height is too large\n");
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
;
342 printf("new smaller then coord\n");
343 printf("implies that width is too small\n");
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
;
352 printf("invalid aspectratio corrected\n");
356 new_aspect
= GET_PAGE_ASPECT_RATIO(toplevel
);
359 printf("final %f\n", new_aspect
);