gschem

o_box.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gschem - gEDA Schematic Capture
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2011 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 #include <math.h>
00022 #include <stdio.h>
00023 
00024 #include "gschem.h"
00025 
00026 #ifdef HAVE_LIBDMALLOC
00027 #include <dmalloc.h>
00028 #endif
00029 
00030 #define GET_BOX_WIDTH(w)            \
00031     abs((w)->second_wx - (w)->first_wx)
00032 #define GET_BOX_HEIGHT(w)           \
00033     abs((w)->second_wy - (w)->first_wy)
00034 #define GET_BOX_LEFT(w)             \
00035     min((w)->first_wx, (w)->second_wx)
00036 #define GET_BOX_TOP(w)              \
00037         max((w)->first_wy, (w)->second_wy)
00038 
00039 typedef void (*FILL_FUNC) (GSCHEM_TOPLEVEL *w_current,
00040                            COLOR *color, BOX *box,
00041                            gint fill_width,
00042                            gint angle1, gint pitch1,
00043                            gint angle2, gint pitch2);
00044 
00060 static void
00061 o_box_fill_hollow (GSCHEM_TOPLEVEL *w_current,
00062                    COLOR *color, BOX *box,
00063                    gint fill_width,
00064                    gint angle1, gint pitch1,
00065                    gint angle2, gint pitch2)
00066 {
00067 }
00068 
00090 static void
00091 o_box_fill_fill (GSCHEM_TOPLEVEL *w_current,
00092                  COLOR *color, BOX *box,
00093                  gint fill_width,
00094                  gint angle1, gint pitch1,
00095                  gint angle2, gint pitch2)
00096 {
00097   /* NOP: We'll fill it when we do the stroking */
00098 }
00099 
00126 static void
00127 o_box_fill_hatch (GSCHEM_TOPLEVEL *w_current,
00128                   COLOR *color, BOX *box,
00129                   gint fill_width,
00130                   gint angle1, gint pitch1,
00131                   gint angle2, gint pitch2)
00132 {
00133   int i;
00134   GArray *lines;
00135 
00136   gschem_cairo_set_source_color (w_current, color);
00137 
00138   lines = g_array_new (FALSE, FALSE, sizeof (LINE));
00139   m_hatch_box (box, angle1, pitch1, lines);
00140 
00141   for (i=0; i < lines->len; i++) {
00142     LINE *line = &g_array_index (lines, LINE, i);
00143 
00144     gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0],
00145                                                         line->x[1], line->y[1]);
00146   }
00147   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1);
00148 
00149   g_array_free (lines, TRUE);
00150 }
00151 
00175 static void
00176 o_box_fill_mesh (GSCHEM_TOPLEVEL *w_current,
00177                  COLOR *color, BOX *box,
00178                  gint fill_width,
00179                  gint angle1, gint pitch1,
00180                  gint angle2, gint pitch2)
00181 {
00182   o_box_fill_hatch (w_current, color, box, fill_width, angle1, pitch1, -1, -1);
00183   o_box_fill_hatch (w_current, color, box, fill_width, angle2, pitch2, -1, -1);
00184 }
00185 
00186 
00200 void o_box_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
00201 {
00202   int angle1, pitch1, angle2, pitch2;
00203   FILL_FUNC fill_func;
00204 
00205   if (o_current->box == NULL) {
00206     return;
00207   }
00208 
00209   /*
00210    * The drawing of the box is divided in two steps : first step is to
00211    * draw the outline, the second is to draw the filling pattern inside
00212    * (if any). Finally the function takes care of the grips.
00213    */
00214   /*
00215    * The values describing the line type are extracted from the <B>o_current</B>
00216    * pointed structure. These are the width of the line, the field called
00217    * length and the field called space and the desired end type for the line.
00218    *
00219    * Depending on the type of the line that has to be used to draw the box
00220    * the appropriate function is called. Values of space and length are
00221    * adapted to the type of line. The possible functions are the following :
00222    * #o_box_draw_solid(), #o_box_draw_dotted(), #o_box_draw_dashed() and
00223    * #o_box_draw_phantom().
00224    *
00225    * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
00226    * lead to an endless loop in function called after. If such a case is
00227    * encountered the box is drawn as a solid box independently of its
00228    * initial type.
00229    */
00230 
00231   /*
00232    * The values needed for the fill operation are taken from the
00233    * <B>o_current</B> pointed OBJECT. It include the type of fill required,
00234    * the width of the lines (if the fill use line) and angles and pitchs
00235    * for hatch based filling.
00236    *
00237    * Once again the width of the line is important as if it is equal to
00238    * 0 it may not be displayed. That is definetely not what we are looking for.
00239    *
00240    * Depending on the type of fill that has to be used inside the box the
00241    * appropriate function is called. Values of <B>angle1</B>,
00242    * <B>angle2</B>, <B>pitch1</B> and <B>pitch2</B> are adapted to the type of
00243    * filling. The possible functions are the following :
00244    * #o_box_fill_hollow(), #o_box_fill_fill(), #o_box_fill_mesh() and
00245    * #o_box_fill_hatch().
00246    *
00247    * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as
00248    * it lead to an endless loop in function called after. It happens when
00249    * the zoom factor is too small for two lines separated by the pitch
00250    * to be distinct. If such a case is encountered the circle is filled
00251    * hollow (e.q. not filled).
00252    */
00253 
00254   angle1 = o_current->fill_angle1;
00255   pitch1 = o_current->fill_pitch1;
00256   angle2 = o_current->fill_angle2;
00257   pitch2 = o_current->fill_pitch2;
00258 
00259   switch (o_current->fill_type) {
00260     case FILLING_HOLLOW:
00261       angle1 = -1; angle2 = -1;
00262       pitch1 = 1; pitch2 = 1;
00263       /* this function is empty ! however if it do not use it we have to add
00264        * a test before the call. Simply putting a return here instead is not
00265        * possible as it would prevent any hollow box from having its grips
00266        * drawn
00267        */
00268       fill_func = o_box_fill_hollow;
00269       break;
00270 
00271     case FILLING_FILL:
00272       angle1 = -1; angle2 = -1;
00273       pitch1 = 1; pitch2 = 1;
00274       fill_func = o_box_fill_fill;
00275       break;
00276 
00277     case FILLING_MESH:
00278       fill_func = o_box_fill_mesh;
00279       break;
00280 
00281     case FILLING_HATCH:
00282       angle2 = -1;
00283       pitch2 = 1;
00284       fill_func = o_box_fill_hatch;
00285       break;
00286 
00287     case FILLING_VOID:
00288     default:
00289       angle1 = -1; angle2 = -1;
00290       pitch1 = 1; pitch2 = 1;
00291       fill_func = o_box_fill_hollow;
00292       fprintf (stderr, _("Unknown type for box (fill)!\n"));
00293   }
00294 
00295   if ((pitch1 <= 0) || (pitch2 <= 0))
00296     fill_func = o_box_fill_fill;
00297 
00298   (*fill_func) (w_current, o_drawing_color (w_current, o_current),
00299                 o_current->box, o_current->fill_width,
00300                 angle1, pitch1, angle2, pitch2);
00301 
00302   gschem_cairo_set_source_color (w_current,
00303                                  o_drawing_color (w_current, o_current));
00304   gschem_cairo_box (w_current, o_current->line_width,
00305                     o_current->box->lower_x, o_current->box->lower_y,
00306                     o_current->box->upper_x, o_current->box->upper_y);
00307 
00308   if (o_current->fill_type == FILLING_FILL)
00309     cairo_fill_preserve (w_current->cr);
00310 
00311   gschem_cairo_stroke (w_current, o_current->line_type,
00312                                   o_current->line_end,
00313                                   o_current->line_width,
00314                                   o_current->line_length,
00315                                   o_current->line_space);
00316 
00317   if (o_current->selected && w_current->draw_grips)
00318     o_box_draw_grips (w_current, o_current);
00319 }
00320 
00321 
00327 void o_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
00328 {
00329   int x1, y1, x2, y2;
00330 
00331   WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1);
00332   WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2);
00333 
00334   o_invalidate_rect (w_current, x1, y1, x2, y1);
00335   o_invalidate_rect (w_current, x1, y1, x1, y2);
00336   o_invalidate_rect (w_current, x2, y1, x2, y2);
00337   o_invalidate_rect (w_current, x1, y2, x2, y2);
00338 }
00339 
00353 void o_box_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
00354 {
00355   if (o_current->box == NULL) {
00356     return;
00357   }
00358 
00359   gschem_cairo_box (w_current, 0, o_current->box->upper_x + dx,
00360                                   o_current->box->upper_y + dy,
00361                                   o_current->box->lower_x + dx,
00362                                   o_current->box->lower_y + dy);
00363   gschem_cairo_set_source_color (w_current,
00364                                  x_color_lookup_dark (o_current->color));
00365   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 1, -1, -1);
00366 }
00367 
00386 void o_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00387 {
00388   /* init first_w[x|y], second_w[x|y] to describe box */
00389   w_current->first_wx = w_current->second_wx = w_x;
00390   w_current->first_wy = w_current->second_wy = w_y;
00391 
00392   /* start to draw the box */
00393   o_box_invalidate_rubber (w_current);
00394 }
00395 
00412 void o_box_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00413 {
00414   TOPLEVEL *toplevel = w_current->toplevel;
00415   OBJECT *new_obj;
00416   int box_width, box_height;
00417   int box_left, box_top;
00418 
00419   g_assert( w_current->inside_action != 0 );
00420 
00421   /* get the last coords of the pointer */
00422   w_current->second_wx = w_x;
00423   w_current->second_wy = w_y;
00424 
00425   /* erase the temporary box */
00426   /* o_box_invalidate_rubber (w_current); */
00427   w_current->rubber_visible = 0;
00428   
00429   box_width  = GET_BOX_WIDTH (w_current);
00430   box_height = GET_BOX_HEIGHT(w_current);
00431   box_left   = GET_BOX_LEFT  (w_current);
00432   box_top    = GET_BOX_TOP   (w_current);
00433 
00434   /* boxes with null width or height are not allowed */
00435   if ((box_width == 0) || (box_height == 0)) {
00436       /* cancel the object creation */
00437       w_current->first_wx = (-1);
00438       w_current->first_wy = (-1);
00439       w_current->second_wx  = (-1);
00440       w_current->second_wy  = (-1);
00441       return;
00442   }
00443 
00444   /* create the object */
00445   new_obj = o_box_new (toplevel, OBJ_BOX, GRAPHIC_COLOR,
00446                        box_left, box_top,
00447                        box_left + box_width, box_top - box_height);
00448   s_page_append (toplevel, toplevel->page_current, new_obj);
00449 
00450 #if DEBUG
00451   printf("coords: %d %d %d %d\n", box_left, box_top, box_width, box_height);
00452 #endif
00453     
00454   w_current->first_wx = (-1);
00455   w_current->first_wy = (-1);
00456   w_current->second_wx  = (-1);
00457   w_current->second_wy  = (-1);
00458     
00459   /* Call add-objects-hook */
00460   g_run_hook_object (w_current, "%add-objects-hook", new_obj);
00461 
00462   toplevel->page_current->CHANGED = 1;
00463 
00464   o_undo_savestate(w_current, UNDO_ALL);
00465 }
00466 
00481 void o_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00482 {
00483 
00484   g_assert( w_current->inside_action != 0 );
00485 
00486   /* erase the previous temporary box if it is visible */
00487   if (w_current->rubber_visible)
00488     o_box_invalidate_rubber (w_current);
00489 
00490   /*
00491    * New values are fixed according to the <B>w_x</B> and <B>w_y</B> parameters.
00492    * These are saved in <B>w_current</B> pointed structure as new temporary
00493    * values. The new box is then drawn.
00494    */
00495 
00496   /* update the coords of the corner */
00497   w_current->second_wx = w_x;
00498   w_current->second_wy = w_y;
00499 
00500   /* draw the new temporary box */
00501   o_box_invalidate_rubber (w_current);
00502   w_current->rubber_visible = 1;
00503 }
00504 
00515 void o_box_draw_rubber (GSCHEM_TOPLEVEL *w_current)
00516 {
00517   gschem_cairo_box (w_current, 0, w_current->first_wx,  w_current->first_wy,
00518                                   w_current->second_wx, w_current->second_wy);
00519   gschem_cairo_set_source_color (w_current,
00520                                  x_color_lookup_dark (SELECT_COLOR));
00521   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
00522 }
00523 
00532 void o_box_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
00533 {
00534   if (w_current->draw_grips == FALSE)
00535     return;
00536 
00537   /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */
00538   o_grips_draw (w_current, o_current->box->upper_x, o_current->box->upper_y);
00539 
00540   /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */
00541   o_grips_draw (w_current, o_current->box->lower_x, o_current->box->upper_y);
00542 
00543   /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */
00544   o_grips_draw (w_current, o_current->box->upper_x, o_current->box->lower_y);
00545 
00546   /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */
00547   o_grips_draw (w_current, o_current->box->lower_x, o_current->box->lower_y);
00548 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines