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
29 #ifdef HAVE_LIBDMALLOC
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
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
;
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 */
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
;
96 int x_start
, y_start
, x_end
, y_end
;
98 GdkPoint points
[DOTS_POINTS_ARRAY_SIZE
];
100 int incr
= query_dots_grid_spacing (w_current
);
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
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
;
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
);
136 gdk_draw_arc (w_current
->drawable
, w_current
->gc
,
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 */
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
)
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 */
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
;
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
;
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
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
) {
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
)
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
;
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
) {
311 draw_dots_grid_region (w_current
, x
, y
, width
, height
);
315 draw_mesh_grid_region (w_current
, x
, y
, width
, height
);
320 /* highly temp, just for diag purposes */
321 x_draw_tiles(w_current
);
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
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
) {
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!!!
350 * \par Function Description
353 void x_draw_tiles(GSCHEM_TOPLEVEL
*w_current
)
355 TOPLEVEL
*toplevel
= w_current
->toplevel
;
360 int screen_x
, screen_y
;
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
);
380 printf("x, y: %d %d\n", screen_x
, screen_y
);
381 printf("w x h: %d %d\n", width
, height
);
383 gdk_draw_rectangle (w_current
->drawable
,
385 FALSE
, screen_x
, screen_y
,
388 tempstring
= g_strdup_printf("%d %d", i
, j
);
390 gdk_draw_text (w_current
->drawable
,
393 screen_x
+10, screen_y
+10,
400 gdk_font_unref(font
);