gschem
|
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 <math.h> 00023 #ifdef HAVE_STRING_H 00024 #include <string.h> 00025 #endif 00026 00027 #include "gschem.h" 00028 00029 #ifdef HAVE_LIBDMALLOC 00030 #include <dmalloc.h> 00031 #endif 00032 00033 #define DOTS_POINTS_ARRAY_SIZE 5000 00034 #define DOTS_VARIABLE_MODE_SPACING 30 00035 00036 #define MESH_COARSE_GRID_MULTIPLIER 5 00037 00038 00050 static int query_dots_grid_spacing (GSCHEM_TOPLEVEL *w_current) 00051 { 00052 TOPLEVEL *toplevel = w_current->toplevel; 00053 int incr, screen_incr; 00054 00055 if (w_current->dots_grid_mode == DOTS_GRID_VARIABLE_MODE) { 00056 /* In the variable mode around every (DOTS_VARIABLE_MODE_SPACING)'th 00057 * screenpixel will be grid-point. */ 00058 /* adding 0.1 for correct cast*/ 00059 incr = round_5_2_1 (toplevel->page_current->to_world_x_constant * 00060 DOTS_VARIABLE_MODE_SPACING) + 0.1; 00061 00062 /* limit minimum grid spacing to grid to snap_size */ 00063 if (incr < w_current->snap_size) { 00064 incr = w_current->snap_size; 00065 } 00066 } else { 00067 /* Fixed size grid in world coorinates */ 00068 incr = w_current->snap_size; 00069 screen_incr = SCREENabs (w_current, incr); 00070 if (screen_incr < w_current->dots_grid_fixed_threshold) { 00071 /* No grid drawn if the on-screen spacing is less than the threshold */ 00072 incr = -1; 00073 } 00074 } 00075 return incr; 00076 } 00077 00078 00090 static void draw_dots_grid_region (GSCHEM_TOPLEVEL *w_current, 00091 int x, int y, int width, int height) 00092 { 00093 TOPLEVEL *toplevel = w_current->toplevel; 00094 int i, j; 00095 int dot_x, dot_y; 00096 int x_start, y_start, x_end, y_end; 00097 int count = 0; 00098 GdkPoint points[DOTS_POINTS_ARRAY_SIZE]; 00099 00100 int incr = query_dots_grid_spacing (w_current); 00101 00102 if (incr == -1) 00103 return; 00104 00105 gdk_gc_set_foreground (w_current->gc, x_get_color (DOTS_GRID_COLOR)); 00106 00107 SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start); 00108 SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end); 00109 00110 /* figure starting grid coordinates, work by taking the start 00111 * and end coordinates and rounding down to the nearest 00112 * increment */ 00113 x_start -= (x_start % incr); 00114 y_start -= (y_start % incr); 00115 00116 for (i = x_start; i <= x_end; i = i + incr) { 00117 for(j = y_start; j <= y_end; j = j + incr) { 00118 WORLDtoSCREEN (w_current, i,j, &dot_x, &dot_y); 00119 if (inside_region (toplevel->page_current->left, 00120 toplevel->page_current->top, 00121 toplevel->page_current->right, 00122 toplevel->page_current->bottom, i, j)) { 00123 00124 if (w_current->dots_grid_dot_size == 1) { 00125 points[count].x = dot_x; 00126 points[count].y = dot_y; 00127 count++; 00128 00129 /* get out of loop if we're hit the end of the array */ 00130 if (count == DOTS_POINTS_ARRAY_SIZE) { 00131 gdk_draw_points (w_current->drawable, 00132 w_current->gc, points, count); 00133 count = 0; 00134 } 00135 } else { 00136 gdk_draw_arc (w_current->drawable, w_current->gc, 00137 TRUE, dot_x, dot_y, 00138 w_current->dots_grid_dot_size, 00139 w_current->dots_grid_dot_size, 0, FULL_CIRCLE); 00140 } 00141 } 00142 } 00143 } 00144 00145 /* now draw all the points in one step */ 00146 if(count != 0) { 00147 gdk_draw_points (w_current->drawable, w_current->gc, points, count); 00148 } 00149 } 00150 00151 00154 static void draw_mesh (GSCHEM_TOPLEVEL *w_current, int color, 00155 int x_start, int y_start, int x_end, int y_end, 00156 int incr, int coarse_mult) 00157 { 00158 int i, j; 00159 int x1, y1, x2, y2; 00160 int next_coarse_x, next_coarse_y; 00161 int coarse_incr = incr * coarse_mult; 00162 00163 /* figure starting grid coordinates, work by taking the start 00164 * and end coordinates and rounding down to the nearest increment */ 00165 x_start -= (x_start % incr); 00166 y_start -= (y_start % incr); 00167 00168 if (coarse_incr == 0) { 00169 next_coarse_x = x_start - 1; /* Ensures we never hit this when looping */ 00170 next_coarse_y = y_start - 1; /* Ensures we never hit this when looping */ 00171 } else { 00172 next_coarse_x = x_start - (x_start % coarse_incr); 00173 next_coarse_y = y_start - (y_start % coarse_incr); 00174 if (next_coarse_x < x_start) next_coarse_x += coarse_incr; 00175 if (next_coarse_y < y_start) next_coarse_y += coarse_incr; 00176 } 00177 00178 gschem_cairo_set_source_color (w_current, x_color_lookup (color)); 00179 cairo_set_line_width (w_current->cr, 1.); 00180 cairo_set_line_cap (w_current->cr, CAIRO_LINE_CAP_SQUARE); 00181 00182 cairo_translate (w_current->cr, 0.5, 0.5); 00183 00184 for (j = y_start; j < y_end; j = j + incr) { 00185 00186 /* Skip lines which will be drawn in the coarser grid */ 00187 if (j == next_coarse_y) { 00188 next_coarse_y += coarse_incr; 00189 continue; 00190 } 00191 WORLDtoSCREEN (w_current, x_start, j, &x1, &y1); 00192 WORLDtoSCREEN (w_current, x_end, j, &x2, &y2); 00193 cairo_move_to (w_current->cr, x1, y1); 00194 cairo_line_to (w_current->cr, x2, y2); 00195 } 00196 cairo_stroke (w_current->cr); 00197 00198 for (i = x_start; i < x_end; i = i + incr) { 00199 00200 /* Skip lines which will be drawn in the coarser grid */ 00201 if (j == next_coarse_y) { 00202 next_coarse_y += coarse_incr; 00203 continue; 00204 } 00205 WORLDtoSCREEN (w_current, i, y_start, &x1, &y1); 00206 WORLDtoSCREEN (w_current, i, y_end, &x2, &y2); 00207 cairo_move_to (w_current->cr, x1, y1); 00208 cairo_line_to (w_current->cr, x2, y2); 00209 } 00210 cairo_stroke (w_current->cr); 00211 00212 cairo_translate (w_current->cr, -0.5, -0.5); 00213 } 00214 00215 00227 static int query_mesh_grid_spacing (GSCHEM_TOPLEVEL *w_current) 00228 { 00229 int incr, screen_incr; 00230 00231 incr = w_current->snap_size; 00232 screen_incr = SCREENabs (w_current, incr); 00233 00234 /* We draw a fine grid if its on-screen spacing is large enough */ 00235 if (screen_incr >= w_current->mesh_grid_display_threshold) { 00236 return incr; 00237 } 00238 00239 incr *= MESH_COARSE_GRID_MULTIPLIER; 00240 screen_incr = SCREENabs (w_current, incr); 00241 00242 /* We draw a coarse grid if its on-screen spacing is large enough */ 00243 if (screen_incr >= w_current->mesh_grid_display_threshold) 00244 return incr; 00245 00246 return -1; 00247 } 00248 00260 static void draw_mesh_grid_region (GSCHEM_TOPLEVEL *w_current, 00261 int x, int y, int width, int height) 00262 { 00263 int x_start, y_start, x_end, y_end; 00264 int incr; 00265 int screen_incr; 00266 00267 incr = w_current->snap_size; 00268 screen_incr = SCREENabs (w_current, incr); 00269 00270 SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start); 00271 SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end); 00272 00273 /* Draw the fine grid if its on-screen spacing is large enough */ 00274 if (screen_incr >= w_current->mesh_grid_display_threshold) { 00275 draw_mesh (w_current, MESH_GRID_MINOR_COLOR, x_start, y_start, 00276 x_end, y_end, incr, MESH_COARSE_GRID_MULTIPLIER); 00277 } 00278 00279 incr *= MESH_COARSE_GRID_MULTIPLIER; 00280 screen_incr = SCREENabs (w_current, incr); 00281 00282 /* Draw the coarse grid if its on-screen spacing is large enough */ 00283 if (screen_incr >= w_current->mesh_grid_display_threshold) { 00284 draw_mesh (w_current, MESH_GRID_MAJOR_COLOR, 00285 x_start, y_start, x_end, y_end, incr, 0); 00286 } 00287 } 00288 00289 00301 void x_grid_draw_region (GSCHEM_TOPLEVEL *w_current, 00302 int x, int y, int width, int height) 00303 { 00304 switch (w_current->grid) { 00305 case GRID_NONE: 00306 return; 00307 00308 case GRID_DOTS: 00309 draw_dots_grid_region (w_current, x, y, width, height); 00310 break; 00311 00312 case GRID_MESH: 00313 draw_mesh_grid_region (w_current, x, y, width, height); 00314 break; 00315 } 00316 00317 #if DEBUG 00318 /* highly temp, just for diag purposes */ 00319 x_draw_tiles(w_current); 00320 #endif 00321 } 00322 00323 00335 int x_grid_query_drawn_spacing (GSCHEM_TOPLEVEL *w_current) 00336 { 00337 switch (w_current->grid) { 00338 default: 00339 case GRID_NONE: return -1; 00340 case GRID_DOTS: return query_dots_grid_spacing (w_current); 00341 case GRID_MESH: return query_mesh_grid_spacing (w_current); 00342 } 00343 } 00344 00345 00351 void x_draw_tiles(GSCHEM_TOPLEVEL *w_current) 00352 { 00353 TOPLEVEL *toplevel = w_current->toplevel; 00354 TILE *t_current; 00355 GdkFont *font; 00356 int i,j; 00357 int x1, y1, x2, y2; 00358 int screen_x, screen_y; 00359 int width, height; 00360 char *tempstring; 00361 00362 gdk_gc_set_foreground (w_current->gc, x_get_color (LOCK_COLOR)); 00363 00364 font = gdk_fontset_load ("fixed"); 00365 for (j = 0; j < MAX_TILES_Y; j++) { 00366 for (i = 0; i < MAX_TILES_X; i++) { 00367 t_current = &toplevel->page_current->world_tiles[i][j]; 00368 WORLDtoSCREEN (w_current, t_current->left, t_current->top, &x1, &y1); 00369 WORLDtoSCREEN (w_current, t_current->right, t_current->bottom, &x2, &y2); 00370 00371 screen_x = min(x1, x2); 00372 screen_y = min(y1, y2); 00373 00374 width = abs(x1 - x2); 00375 height = abs(y1 - y2); 00376 00377 #if DEBUG 00378 printf("x, y: %d %d\n", screen_x, screen_y); 00379 printf("w x h: %d %d\n", width, height); 00380 #endif 00381 gdk_draw_rectangle (w_current->drawable, 00382 w_current->gc, 00383 FALSE, screen_x, screen_y, 00384 width, height); 00385 00386 tempstring = g_strdup_printf("%d %d", i, j); 00387 00388 gdk_draw_text (w_current->drawable, 00389 font, 00390 w_current->gc, 00391 screen_x+10, screen_y+10, 00392 tempstring, 00393 strlen(tempstring)); 00394 g_free(tempstring); 00395 } 00396 } 00397 00398 gdk_font_unref(font); 00399 }