Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / x_grid.c
blob0f85e4de3e1e4edbc507612aa17c8a7203b3c101
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 <math.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
27 #include "gschem.h"
29 #ifdef HAVE_LIBDMALLOC
30 #include <dmalloc.h>
31 #endif
33 #define DOTS_POINTS_ARRAY_SIZE 5000
34 #define DOTS_VARIABLE_MODE_SPACING 30
36 #define MESH_COARSE_GRID_MULTIPLIER 5
39 /*! \brief Query the spacing in world coordinates at which the dots grid is drawn.
41 * \par Function Description
42 * Returns the world spacing of the rendered grid, taking into account where
43 * the grid drawing code may drop elelments which are too densly packed for a
44 * given zoom level.
46 * \param [in] w_current The GSCHEM_TOPLEVEL.
47 * \returns The grid spacing in world units of the grid as rendered, or -1
48 * if there are no items drawn.
50 static int query_dots_grid_spacing (GSCHEM_TOPLEVEL *w_current)
52 TOPLEVEL *toplevel = w_current->toplevel;
53 int incr, screen_incr;
55 if (w_current->dots_grid_mode == DOTS_GRID_VARIABLE_MODE) {
56 /* In the variable mode around every (DOTS_VARIABLE_MODE_SPACING)'th
57 * screenpixel will be grid-point. */
58 /* adding 0.1 for correct cast*/
59 incr = round_5_2_1 (toplevel->page_current->to_world_x_constant *
60 DOTS_VARIABLE_MODE_SPACING) + 0.1;
62 /* limit minimum grid spacing to grid to snap_size */
63 if (incr < toplevel->snap_size) {
64 incr = toplevel->snap_size;
66 } else {
67 /* Fixed size grid in world coorinates */
68 incr = toplevel->snap_size;
69 screen_incr = SCREENabs (w_current, incr);
70 if (screen_incr < w_current->dots_grid_fixed_threshold) {
71 /* No grid drawn if the on-screen spacing is less than the threshold */
72 incr = -1;
75 return incr;
79 /*! \brief Draw an area of the screen with a dotted grid pattern
81 * \par Function Description
82 * Draws the dotted grid pattern over a given region of the screen.
84 * \param [in] w_current The GSCHEM_TOPLEVEL.
85 * \param [in] x The left screen coordinate for the drawing.
86 * \param [in] y The top screen coordinate for the drawing.
87 * \param [in] width The width of the region to draw.
88 * \param [in] height The height of the region to draw.
90 static void draw_dots_grid_region (GSCHEM_TOPLEVEL *w_current,
91 int x, int y, int width, int height)
93 TOPLEVEL *toplevel = w_current->toplevel;
94 int i, j;
95 int dot_x, dot_y;
96 int x_start, y_start, x_end, y_end;
97 int count = 0;
98 GdkPoint points[DOTS_POINTS_ARRAY_SIZE];
100 int incr = query_dots_grid_spacing (w_current);
102 if (incr == -1)
103 return;
105 gdk_gc_set_foreground (w_current->gc, x_get_color (DOTS_GRID_COLOR));
107 SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start);
108 SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end);
110 /* figure starting grid coordinates, work by taking the start
111 * and end coordinates and rounding down to the nearest
112 * increment */
113 x_start -= (x_start % incr);
114 y_start -= (y_start % incr);
116 for (i = x_start; i <= x_end; i = i + incr) {
117 for(j = y_start; j <= y_end; j = j + incr) {
118 WORLDtoSCREEN (w_current, i,j, &dot_x, &dot_y);
119 if (inside_region (toplevel->page_current->left,
120 toplevel->page_current->top,
121 toplevel->page_current->right,
122 toplevel->page_current->bottom, i, j)) {
124 if (w_current->dots_grid_dot_size == 1) {
125 points[count].x = dot_x;
126 points[count].y = dot_y;
127 count++;
129 /* get out of loop if we're hit the end of the array */
130 if (count == DOTS_POINTS_ARRAY_SIZE) {
131 gdk_draw_points (w_current->drawable,
132 w_current->gc, points, count);
133 count = 0;
135 } else {
136 gdk_draw_arc (w_current->drawable, w_current->gc,
137 TRUE, dot_x, dot_y,
138 w_current->dots_grid_dot_size,
139 w_current->dots_grid_dot_size, 0, FULL_CIRCLE);
145 /* now draw all the points in one step */
146 if(count != 0) {
147 gdk_draw_points (w_current->drawable, w_current->gc, points, count);
152 /*! \brief Helper function for draw_mesh_grid_regin
154 static void draw_mesh (GSCHEM_TOPLEVEL *w_current, int color,
155 int x_start, int y_start, int x_end, int y_end,
156 int incr, int coarse_mult)
158 int i, j;
159 int x1, y1, x2, y2;
160 int next_coarse_x, next_coarse_y;
161 int coarse_incr = incr * coarse_mult;
163 /* figure starting grid coordinates, work by taking the start
164 * and end coordinates and rounding down to the nearest increment */
165 x_start -= (x_start % incr);
166 y_start -= (y_start % incr);
168 if (coarse_incr == 0) {
169 next_coarse_x = x_start - 1; /* Ensures we never hit this when looping */
170 next_coarse_y = y_start - 1; /* Ensures we never hit this when looping */
171 } else {
172 next_coarse_x = x_start - (x_start % coarse_incr);
173 next_coarse_y = y_start - (y_start % coarse_incr);
174 if (next_coarse_x < x_start) next_coarse_x += coarse_incr;
175 if (next_coarse_y < y_start) next_coarse_y += coarse_incr;
178 gschem_cairo_set_source_color (w_current, x_color_lookup (color));
179 cairo_set_line_width (w_current->cr, 1.);
180 cairo_set_line_cap (w_current->cr, CAIRO_LINE_CAP_SQUARE);
182 cairo_translate (w_current->cr, 0.5, 0.5);
184 for (j = y_start; j < y_end; j = j + incr) {
186 /* Skip lines which will be drawn in the coarser grid */
187 if (j == next_coarse_y) {
188 next_coarse_y += coarse_incr;
189 continue;
191 WORLDtoSCREEN (w_current, x_start, j, &x1, &y1);
192 WORLDtoSCREEN (w_current, x_end, j, &x2, &y2);
193 cairo_move_to (w_current->cr, x1, y1);
194 cairo_line_to (w_current->cr, x2, y2);
196 cairo_stroke (w_current->cr);
198 for (i = x_start; i < x_end; i = i + incr) {
200 /* Skip lines which will be drawn in the coarser grid */
201 if (j == next_coarse_y) {
202 next_coarse_y += coarse_incr;
203 continue;
205 WORLDtoSCREEN (w_current, i, y_start, &x1, &y1);
206 WORLDtoSCREEN (w_current, i, y_end, &x2, &y2);
207 cairo_move_to (w_current->cr, x1, y1);
208 cairo_line_to (w_current->cr, x2, y2);
210 cairo_stroke (w_current->cr);
212 cairo_translate (w_current->cr, -0.5, -0.5);
216 /*! \brief Query the spacing in world coordinates at which the mesh grid is drawn.
218 * \par Function Description
219 * Returns the world spacing of the rendered grid, taking into account where
220 * the grid drawing code may drop elelments which are too densly packed for a
221 * given zoom level.
223 * \param [in] w_current The GSCHEM_TOPLEVEL.
224 * \returns The grid spacing in world units of the grid as rendered, or -1
225 * if there are no items drawn.
227 static int query_mesh_grid_spacing (GSCHEM_TOPLEVEL *w_current)
229 TOPLEVEL *toplevel = w_current->toplevel;
230 int incr, screen_incr;
232 incr = toplevel->snap_size;
233 screen_incr = SCREENabs (w_current, incr);
235 /* We draw a fine grid if its on-screen spacing is large enough */
236 if (screen_incr >= w_current->mesh_grid_display_threshold) {
237 return incr;
240 incr *= MESH_COARSE_GRID_MULTIPLIER;
241 screen_incr = SCREENabs (w_current, incr);
243 /* We draw a coarse grid if its on-screen spacing is large enough */
244 if (screen_incr >= w_current->mesh_grid_display_threshold)
245 return incr;
247 return -1;
250 /*! \brief Draw an area of the screen with a mesh grid pattern
252 * \par Function Description
253 * Draws the mesh grid pattern over a given region of the screen.
255 * \param [in] w_current The GSCHEM_TOPLEVEL.
256 * \param [in] x The left screen coordinate for the drawing.
257 * \param [in] y The top screen coordinate for the drawing.
258 * \param [in] width The width of the region to draw.
259 * \param [in] height The height of the region to draw.
261 static void draw_mesh_grid_region (GSCHEM_TOPLEVEL *w_current,
262 int x, int y, int width, int height)
264 TOPLEVEL *toplevel = w_current->toplevel;
265 int x_start, y_start, x_end, y_end;
266 int incr;
267 int screen_incr;
269 incr = toplevel->snap_size;
270 screen_incr = SCREENabs (w_current, incr);
272 SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start);
273 SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end);
275 /* Draw the fine grid if its on-screen spacing is large enough */
276 if (screen_incr >= w_current->mesh_grid_display_threshold) {
277 draw_mesh (w_current, MESH_GRID_MINOR_COLOR, x_start, y_start,
278 x_end, y_end, incr, MESH_COARSE_GRID_MULTIPLIER);
281 incr *= MESH_COARSE_GRID_MULTIPLIER;
282 screen_incr = SCREENabs (w_current, incr);
284 /* Draw the coarse grid if its on-screen spacing is large enough */
285 if (screen_incr >= w_current->mesh_grid_display_threshold) {
286 draw_mesh (w_current, MESH_GRID_MAJOR_COLOR,
287 x_start, y_start, x_end, y_end, incr, 0);
292 /*! \brief Draw an area of the screen with the current grid pattern.
294 * \par Function Description
295 * Draws the desired grid pattern over a given region of the screen.
297 * \param [in] w_current The GSCHEM_TOPLEVEL.
298 * \param [in] x The left screen coordinate for the drawing.
299 * \param [in] y The top screen coordinate for the drawing.
300 * \param [in] width The width of the region to draw.
301 * \param [in] height The height of the region to draw.
303 void x_grid_draw_region (GSCHEM_TOPLEVEL *w_current,
304 int x, int y, int width, int height)
306 switch (w_current->grid) {
307 case GRID_NONE:
308 return;
310 case GRID_DOTS:
311 draw_dots_grid_region (w_current, x, y, width, height);
312 break;
314 case GRID_MESH:
315 draw_mesh_grid_region (w_current, x, y, width, height);
316 break;
319 #if DEBUG
320 /* highly temp, just for diag purposes */
321 x_draw_tiles(w_current);
322 #endif
326 /*! \brief Query the spacing in world coordinates at which the grid is drawn.
328 * \par Function Description
329 * Returns the world spacing of the rendered grid, taking into account where
330 * the grid drawing code may drop elelments which are too densly packed for a
331 * given zoom level.
333 * \param [in] w_current The GSCHEM_TOPLEVEL.
334 * \returns The grid spacing in world units of the grid as rendered, or -1
335 * if there are no items drawn.
337 int x_grid_query_drawn_spacing (GSCHEM_TOPLEVEL *w_current)
339 switch (w_current->grid) {
340 default:
341 case GRID_NONE: return -1;
342 case GRID_DOTS: return query_dots_grid_spacing (w_current);
343 case GRID_MESH: return query_mesh_grid_spacing (w_current);
348 /*! \todo Finish function documentation!!!
349 * \brief
350 * \par Function Description
353 void x_draw_tiles(GSCHEM_TOPLEVEL *w_current)
355 TOPLEVEL *toplevel = w_current->toplevel;
356 TILE *t_current;
357 GdkFont *font;
358 int i,j;
359 int x1, y1, x2, y2;
360 int screen_x, screen_y;
361 int width, height;
362 char *tempstring;
364 gdk_gc_set_foreground (w_current->gc, x_get_color (LOCK_COLOR));
366 font = gdk_fontset_load ("fixed");
367 for (j = 0; j < MAX_TILES_Y; j++) {
368 for (i = 0; i < MAX_TILES_X; i++) {
369 t_current = &toplevel->page_current->world_tiles[i][j];
370 WORLDtoSCREEN (w_current, t_current->left, t_current->top, &x1, &y1);
371 WORLDtoSCREEN (w_current, t_current->right, t_current->bottom, &x2, &y2);
373 screen_x = min(x1, x2);
374 screen_y = min(y1, y2);
376 width = abs(x1 - x2);
377 height = abs(y1 - y2);
379 #if DEBUG
380 printf("x, y: %d %d\n", screen_x, screen_y);
381 printf("w x h: %d %d\n", width, height);
382 #endif
383 gdk_draw_rectangle (w_current->drawable,
384 w_current->gc,
385 FALSE, screen_x, screen_y,
386 width, height);
388 tempstring = g_strdup_printf("%d %d", i, j);
390 gdk_draw_text (w_current->drawable,
391 font,
392 w_current->gc,
393 screen_x+10, screen_y+10,
394 tempstring,
395 strlen(tempstring));
396 g_free(tempstring);
400 gdk_font_unref(font);