~ubuntu-branches/ubuntu/precise/pcb/precise

« back to all changes in this revision

Viewing changes to src/misc.c

  • Committer: Bazaar Package Importer
  • Author(s): Hamish Moffatt
  • Date: 2005-02-20 13:14:00 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050220131400-pfz66g5vhx0azl8f
Tags: 1.99j+20050127-2
* Improved package description: (closes: #295405)
* Fixed dependency: tk84 -> tk8.4 (closes: #295404)
* Updated README.debian (closes: #269578)
* Applied patch to src/djopt.c to allow compilation with gcc-4.0
  (closes: #294319), thanks to Andreas Jochens for the patch.
* Prevent example files from being compressed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: misc.c,v 1.33 2005/01/03 12:56:59 danmc Exp $ */
 
2
 
1
3
/*
2
4
 *                            COPYRIGHT
3
5
 *
4
6
 *  PCB, interactive printed circuit board design
5
 
 *  Copyright (C) 1994,1995,1996 Thomas Nau
 
7
 *  Copyright (C) 1994,1995,1996, 2004 Thomas Nau
6
8
 *
7
9
 *  This program is free software; you can redistribute it and/or modify
8
10
 *  it under the terms of the GNU General Public License as published by
24
26
 *
25
27
 */
26
28
 
27
 
static  char    *rcsid = "$Id: misc.c,v 1.2 1998/02/21 10:27:14 cad Exp $";
28
29
 
29
30
/* misc functions used by several modules
30
31
 */
31
32
 
 
33
#ifdef HAVE_CONFIG_H
 
34
#include "config.h"
 
35
#endif
 
36
 
32
37
#include <stdlib.h>
 
38
#include <stdarg.h>
 
39
#ifdef HAVE_STRING_H
33
40
#include <string.h>
 
41
#endif
34
42
#include <memory.h>
35
43
#include <ctype.h>
36
44
#include <signal.h>
38
46
#include <sys/stat.h>
39
47
#include <sys/types.h>
40
48
#include <math.h>
 
49
#ifdef HAVE_UNISTD_H
41
50
#include <unistd.h>
 
51
#endif
42
52
 
43
53
#include "global.h"
44
54
 
 
55
#include "crosshair.h"
45
56
#include "create.h"
46
 
#include "crosshair.h"
47
57
#include "data.h"
48
58
#include "dialog.h"
49
59
#include "draw.h"
50
60
#include "file.h"
 
61
#include "gui.h"
51
62
#include "error.h"
52
63
#include "mymem.h"
53
64
#include "misc.h"
54
65
#include "move.h"
55
66
#include "output.h"
56
67
#include "remove.h"
 
68
#include "rtree.h"
57
69
#include "rotate.h"
58
70
#include "rubberband.h"
59
71
#include "search.h"
60
72
#include "set.h"
61
 
 
62
 
#include <X11/cursorfont.h>
63
 
#include <X11/Shell.h>
64
 
#include <X11/Xaw/Scrollbar.h>
65
 
#include <X11/Xaw/Simple.h>
 
73
#include "action.h"
 
74
 
 
75
#ifdef HAVE_LIBDMALLOC
 
76
#include <dmalloc.h>
 
77
#endif
 
78
 
 
79
RCSID ("$Id: misc.c,v 1.33 2005/01/03 12:56:59 danmc Exp $");
 
80
 
 
81
 
 
82
 
66
83
 
67
84
/*      forward declarations    */
68
 
static char *BumpName(char *);
69
 
static void RightAngles( int, float *, float *);
70
 
static void GetGridLockCoordinates(int, void *, void *, void *, Position *, Position *);
 
85
static char *BumpName (char *);
 
86
static void RightAngles (int, float *, float *);
 
87
static void GetGridLockCoordinates (int, void *, void *, void *, LocationType *,
 
88
                                    LocationType *);
 
89
 
 
90
 
 
91
/* Local variables */
 
92
 
 
93
/* 
 
94
 * Used by SaveStackAndVisibility() and 
 
95
 * RestoreStackAndVisibility()
 
96
 */
 
97
 
 
98
static struct
 
99
{
 
100
  Boolean ElementOn, InvisibleObjectsOn, PinOn, ViaOn, RatOn;
 
101
  int LayerStack[MAX_LAYER];
 
102
  Boolean LayerOn[MAX_LAYER];
 
103
  int cnt;
 
104
} SavedStack;
71
105
 
72
106
/* ---------------------------------------------------------------------------
73
107
 * prints copyright information
74
108
 */
75
 
void Copyright(void)
 
109
void
 
110
Copyright (void)
76
111
{
77
 
        printf("\n"
78
 
                "                COPYRIGHT for %s version %s\n\n"
79
 
                "    PCB, interactive printed circuit board design\n"
80
 
                "    Copyright (C) 1994,1995,1996 Thomas Nau\n\n"
81
 
                "    This program is free software; you can redistribute it and/or modify\n"
82
 
                "    it under the terms of the GNU General Public License as published by\n"
83
 
                "    the Free Software Foundation; either version 2 of the License, or\n"
84
 
                "    (at your option) any later version.\n\n"
85
 
                "    This program is distributed in the hope that it will be useful,\n"
86
 
                "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
87
 
                "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
88
 
                "    GNU General Public License for more details.\n\n"
89
 
                "    You should have received a copy of the GNU General Public License\n"
90
 
                "    along with this program; if not, write to the Free Software\n"
91
 
                "    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
92
 
                Progname, RELEASE);
93
 
        exit(0);
 
112
  printf ("\n"
 
113
          "                COPYRIGHT for %s version %s\n\n"
 
114
          "    PCB, interactive printed circuit board design\n"
 
115
          "    Copyright (C) 1994,1995,1996,1997 Thomas Nau\n"
 
116
          "    Copyright (C) 1998, 1999, 2000 Harry Eaton\n\n"
 
117
          "    This program is free software; you can redistribute it and/or modify\n"
 
118
          "    it under the terms of the GNU General Public License as published by\n"
 
119
          "    the Free Software Foundation; either version 2 of the License, or\n"
 
120
          "    (at your option) any later version.\n\n"
 
121
          "    This program is distributed in the hope that it will be useful,\n"
 
122
          "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
 
123
          "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 
124
          "    GNU General Public License for more details.\n\n"
 
125
          "    You should have received a copy of the GNU General Public License\n"
 
126
          "    along with this program; if not, write to the Free Software\n"
 
127
          "    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
 
128
          Progname, VERSION);
 
129
  exit (0);
94
130
}
95
131
 
96
132
/* ---------------------------------------------------------------------------
97
133
 * prints usage message
98
134
 */
99
 
void Usage(void)
100
 
{
101
 
        fprintf(stderr, "\nUSAGE: %s [standard X options] [standard options] [layout]\n"
102
 
                "or   : %s [standard X options] <exactly one special option>\n\n"
103
 
                "standard options are:\n"
104
 
                "  -alldirections:           enable 'all-direction' lines\n"
105
 
                "  +alldirections:           force 45 degree lines\n"
106
 
                "  +rubberband:              enable rubberband move and rotate\n"
107
 
                "  -rubberband:              turn off rubberband move and rotate\n"
108
 
                "  -backup <seconds>:        time between two backups\n"
109
 
                "  -c <number>:              characters per output-line\n"
110
 
                "  -fontfile <file>:         read default font from this file\n"
111
 
                "  -lelement <command>:      command to copy element files to stdout,\n"
112
 
                "                            %%f is set to the filename\n"
113
 
                "                            %%p is set to the seachpath\n"
114
 
                "  -lfile <command>:         command to copy layout files to stdout,\n"
115
 
                "                            %%f is set to the filename\n"
116
 
                "                            %%p is set to the seachpath\n"
117
 
                "  -lfont <command>:         command to copy font files to stdout,\n"
118
 
                "                            %%f is set to the filename\n"
119
 
                "                            %%p is set to the seachpath\n"
120
 
                "  -lg <layergroups>:        set layergroups of new layouts to this\n"
121
 
                "  -libname <file>:          the name of the library\n"
122
 
                "  -libpath <path>:          the library search-path\n"
123
 
                "  -llib <command>:          command to copy elements from library to stdout,\n"
124
 
                "                            %%a is set to 'template value package'\n"
125
 
                "                            %%f is set to the filename\n"
126
 
                "                            %%p is set to the searchpath\n"
127
 
                "  -llibcont <command>:      command to list library contents,\n"
128
 
                "                            %%f is set to the filename\n"
129
 
                "                            %%p is set to the searchpath\n"
130
 
                "  -loggeometry <geometry>:  set the geometry of the logging window\n"
131
 
                "  -log:                     don't use the log window\n"
132
 
                "  -pnl <value>:             maximum display length of pin names\n"
133
 
                "  -pz <value>:              zoom factor for pinout windows\n"
134
 
                "  -reset:                   reset connections after each element\n"
135
 
                "  +reset:                   negation of '-reset'\n"
136
 
                "  -ring:                    ring bell when connection lookup is done\n"
137
 
                "  +ring:                    negation of '-r'\n"
138
 
                "  -s:                       save the last command entered by user\n"
139
 
                "  +s:                       negation of '-s'\n"
140
 
                "  -save:                    always save data before it is lost\n"
141
 
                "  +save:                    override data if required by command\n"
142
 
                "  -sfile <command>:         command to copy stdin to layout file,\n"
143
 
                "                            %%f is set to the filename\n"
144
 
                "  -size <width>x<height>    size of a layout\n"
145
 
                "  -v <value>:               sets the volume of the X speaker\n"
146
 
                "special options are:\n"
147
 
                "  -copyright:               prints copyright information\n"
148
 
                "  -help:                    prints this message\n"
149
 
                "  -version:                 prints the current version number\n",
150
 
                Progname, Progname);
151
 
        exit(1);
 
135
void
 
136
Usage (void)
 
137
{
 
138
  /*
 
139
   * since we're going to exit, we want to make sure this message goes
 
140
   * to the original stderr 
 
141
   */
 
142
  RestoreStderr ();
 
143
 
 
144
  fprintf (stderr,
 
145
           "\nUSAGE: %s [standard X options] [standard options] [layout]\n"
 
146
           "or   : %s [standard X options] <exactly one special option>\n\n"
 
147
           "standard options are:\n"
 
148
           "  -alldirections:           enable 'all-direction' lines\n"
 
149
           "  +alldirections:           force 45 degree lines\n"
 
150
           "  +rubberband:              enable rubberband move and rotate\n"
 
151
           "  -rubberband:              turn off rubberband move and rotate\n"
 
152
           "  -background <file>:       PPM file to display as board background\n"
 
153
           "  -backup <seconds>:        time between two backups\n"
 
154
           "  -c <number>:              characters per output-line\n"
 
155
           "  -fontfile <file>:         read default font from this file\n"
 
156
           "  -lelement <command>:      command to copy element files to stdout,\n"
 
157
           "                            %%f is set to the filename\n"
 
158
           "                            %%p is set to the seachpath\n"
 
159
           "  -lfile <command>:         command to copy layout files to stdout,\n"
 
160
           "                            %%f is set to the filename\n"
 
161
           "                            %%p is set to the seachpath\n"
 
162
           "  -lfont <command>:         command to copy font files to stdout,\n"
 
163
           "                            %%f is set to the filename\n"
 
164
           "                            %%p is set to the seachpath\n"
 
165
           "  -lg <layergroups>:        set layergroups of new layouts to this\n"
 
166
           "  -libname <file>:          the name of the library\n"
 
167
           "  -libpath <path>:          the library search-path\n"
 
168
           "  -llib <command>:          command to copy elements from library to stdout,\n"
 
169
           "                            %%a is set to 'template value package'\n"
 
170
           "                            %%f is set to the filename\n"
 
171
           "                            %%p is set to the searchpath\n"
 
172
           "  -llibcont <command>:      command to list library contents,\n"
 
173
           "                            %%f is set to the filename\n"
 
174
           "                            %%p is set to the searchpath\n"
 
175
           "  -loggeometry <geometry>:  set the geometry of the logging window\n"
 
176
           "  -log:                     don't use the log window\n"
 
177
           "  -pnl <value>:             maximum display length of pin names\n"
 
178
           "  -pz <value>:              zoom factor for pinout windows\n"
 
179
           "  -reset:                   reset connections after each element\n"
 
180
           "  +reset:                   negation of '-reset'\n"
 
181
           "  -ring:                    ring bell when connection lookup is done\n"
 
182
           "  +ring:                    negation of '-r'\n"
 
183
           "  -s:                       save the last command entered by user\n"
 
184
           "  +s:                       negation of '-s'\n"
 
185
           "  -save:                    always save data before it is lost\n"
 
186
           "  +save:                    override data if required by command\n"
 
187
           "  -script <file>:           the name of a PCB actions script to\n"
 
188
           "                            execute on startup\n"
 
189
           "  -sfile <command>:         command to copy stdin to layout file,\n"
 
190
           "                            %%f is set to the filename\n"
 
191
           "  -size <width>x<height>    size of a layout\n"
 
192
           "  -v <value>:               sets the volume of the X speaker\n"
 
193
           "special options are:\n"
 
194
           "  -copyright:               prints copyright information\n"
 
195
           "  --copyright:              prints copyright information\n"
 
196
           "  -help:                    prints this message\n"
 
197
           "  --help:                   prints this message\n"
 
198
           "  -version:                 prints the current version number\n"
 
199
           "  --version:                prints the current version number\n",
 
200
           Progname, Progname);
 
201
  exit (1);
 
202
}
 
203
 
 
204
/* Get Value returns a numeric value passed from the string and sets the
 
205
 * Boolean variable absolute to False if it leads with a +/- character
 
206
 */
 
207
float
 
208
GetValue (String * Params, Boolean * absolute, Cardinal Num)
 
209
{
 
210
  float value;
 
211
  /* if the first character is a sign we have to add the
 
212
   * value to the current one
 
213
   */
 
214
  if (**Params == '=')
 
215
    {
 
216
      *absolute = 1;
 
217
      value = atof (*Params + 1);
 
218
    }
 
219
  else
 
220
    {
 
221
      if (isdigit (**Params))
 
222
        *absolute = True;
 
223
      else
 
224
        *absolute = False;
 
225
      value = atof (*Params);
 
226
    }
 
227
  if (Num == 3)
 
228
    {
 
229
      if (strncasecmp (*(Params + 1), "mm", 2) == 0)
 
230
        value *= MM_TO_COOR;
 
231
      else if (strncasecmp (*(Params + 1), "mil", 3) == 0)
 
232
        value *= 100;
 
233
    }
 
234
  return value;
 
235
}
 
236
 
 
237
/* ---------------------------------------------------------------------------
 
238
 * sets the bounding box of a point (which is silly)
 
239
 */
 
240
void
 
241
SetPointBoundingBox (PointTypePtr Pnt)
 
242
{
 
243
  Pnt->X2 = Pnt->X;
 
244
  Pnt->Y2 = Pnt->Y;
 
245
}
 
246
 
 
247
/* ---------------------------------------------------------------------------
 
248
 * sets the bounding box of a pin or via
 
249
 */
 
250
void
 
251
SetPinBoundingBox (PinTypePtr Pin)
 
252
{
 
253
  BDimension width;
 
254
 
 
255
  /* the bounding box covers the extent of influence
 
256
   * so it must include the clearance values too
 
257
   */
 
258
  width = (Pin->Clearance + 1) / 2 + (Pin->Thickness + 1) / 2;
 
259
  width = MAX (width, (Pin->Mask + 1) / 2);
 
260
  Pin->BoundingBox.X1 = Pin->X - width;
 
261
  Pin->BoundingBox.Y1 = Pin->Y - width;
 
262
  Pin->BoundingBox.X2 = Pin->X + width;
 
263
  Pin->BoundingBox.Y2 = Pin->Y + width;
 
264
}
 
265
 
 
266
/* ---------------------------------------------------------------------------
 
267
 * sets the bounding box of a pad
 
268
 */
 
269
void
 
270
SetPadBoundingBox (PadTypePtr Pad)
 
271
{
 
272
  BDimension width;
 
273
 
 
274
  /* the bounding box covers the extent of influence
 
275
   * so it must include the clearance values too
 
276
   */
 
277
  width = (Pad->Thickness + Pad->Clearance + 1) / 2;
 
278
  width = MAX (width, (Pad->Mask + 1) / 2);
 
279
  Pad->BoundingBox.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - width;
 
280
  Pad->BoundingBox.X2 = MAX (Pad->Point1.X, Pad->Point2.X) + width;
 
281
  Pad->BoundingBox.Y1 = MIN (Pad->Point1.Y, Pad->Point2.Y) - width;
 
282
  Pad->BoundingBox.Y2 = MAX (Pad->Point1.Y, Pad->Point2.Y) + width;
 
283
}
 
284
 
 
285
/* ---------------------------------------------------------------------------
 
286
 * sets the bounding box of a line
 
287
 */
 
288
void
 
289
SetLineBoundingBox (LineTypePtr Line)
 
290
{
 
291
  BDimension width;
 
292
 
 
293
  width = (Line->Thickness + Line->Clearance + 1) / 2;
 
294
 
 
295
  Line->BoundingBox.X1 = MIN (Line->Point1.X, Line->Point2.X) - width;
 
296
  Line->BoundingBox.X2 = MAX (Line->Point1.X, Line->Point2.X) + width;
 
297
  Line->BoundingBox.Y1 = MIN (Line->Point1.Y, Line->Point2.Y) - width;
 
298
  Line->BoundingBox.Y2 = MAX (Line->Point1.Y, Line->Point2.Y) + width;
 
299
  SetPointBoundingBox (&Line->Point1);
 
300
  SetPointBoundingBox (&Line->Point2);
152
301
}
153
302
 
154
303
/* ---------------------------------------------------------------------------
155
304
 * sets the bounding box of a polygons
156
305
 */
157
 
void SetPolygonBoundingBox(PolygonTypePtr Polygon)
 
306
void
 
307
SetPolygonBoundingBox (PolygonTypePtr Polygon)
158
308
{
159
 
        Position        minx, miny,
160
 
                        maxx, maxy;
161
 
 
162
 
        minx = miny = MAX_COORD;
163
 
        maxx = maxy = 0;
164
 
        POLYGONPOINT_LOOP(Polygon,
165
 
                minx = MIN(minx, point->X);
166
 
                miny = MIN(miny, point->Y);
167
 
                maxx = MAX(maxx, point->X);
168
 
                maxy = MAX(maxy, point->Y);
169
 
        );
170
 
        Polygon->BoundingBox.X1 = minx;
171
 
        Polygon->BoundingBox.Y1 = miny;
172
 
        Polygon->BoundingBox.X2 = maxx;
173
 
        Polygon->BoundingBox.Y2 = maxy;
 
309
  Polygon->BoundingBox.X1 = Polygon->BoundingBox.Y1 = MAX_COORD;
 
310
  Polygon->BoundingBox.X2 = Polygon->BoundingBox.Y2 = 0;
 
311
  POLYGONPOINT_LOOP (Polygon);
 
312
  {
 
313
    MAKEMIN (Polygon->BoundingBox.X1, point->X);
 
314
    MAKEMIN (Polygon->BoundingBox.Y1, point->Y);
 
315
    MAKEMAX (Polygon->BoundingBox.X2, point->X);
 
316
    MAKEMAX (Polygon->BoundingBox.Y2, point->Y);
 
317
  }
 
318
  END_LOOP;
174
319
}
175
320
 
176
321
/* ---------------------------------------------------------------------------
177
322
 * sets the bounding box of an elements
178
323
 */
179
 
void SetElementBoundingBox(ElementTypePtr Element, FontTypePtr Font)
 
324
void
 
325
SetElementBoundingBox (DataTypePtr Data, ElementTypePtr Element,
 
326
                       FontTypePtr Font)
180
327
{
181
 
        Position        minx, miny,
182
 
                        maxx, maxy;
183
 
        float           fminx, fminy,
184
 
                        fmaxx, fmaxy;
185
 
        int             angle1,
186
 
                        angle2,
187
 
                        angle;
188
 
 
189
 
                /* first update the text objects */
190
 
        ELEMENTTEXT_LOOP(Element, SetTextBoundingBox(Font, text));
191
 
 
192
 
                /* do not include the elementnames bounding box which
193
 
                 * is handles seperatly
194
 
                 */
195
 
        minx = miny = MAX_COORD;
196
 
        maxx = maxy = 0;
197
 
        ELEMENTLINE_LOOP(Element,
198
 
                minx = MIN(minx, line->Point1.X - line->Thickness/2);
199
 
                miny = MIN(miny, line->Point1.Y - line->Thickness/2);
200
 
                minx = MIN(minx, line->Point2.X - line->Thickness/2);
201
 
                miny = MIN(miny, line->Point2.Y - line->Thickness/2);
202
 
                maxx = MAX(maxx, line->Point1.X + line->Thickness/2);
203
 
                maxy = MAX(maxy, line->Point1.Y + line->Thickness/2);
204
 
                maxx = MAX(maxx, line->Point2.X + line->Thickness/2);
205
 
                maxy = MAX(maxy, line->Point2.Y + line->Thickness/2);
206
 
        );
207
 
        PIN_LOOP(Element,
208
 
                minx = MIN(minx, pin->X - pin->Thickness/2);
209
 
                miny = MIN(miny, pin->Y - pin->Thickness/2);
210
 
                maxx = MAX(maxx, pin->X + pin->Thickness/2);
211
 
                maxy = MAX(maxy, pin->Y + pin->Thickness/2);
212
 
        );
213
 
        PAD_LOOP(Element,
214
 
                minx = MIN(minx, pad->Point1.X - pad->Thickness/2);
215
 
                miny = MIN(miny, pad->Point1.Y - pad->Thickness/2);
216
 
                minx = MIN(minx, pad->Point2.X - pad->Thickness/2);
217
 
                miny = MIN(miny, pad->Point2.Y - pad->Thickness/2);
218
 
                maxx = MAX(maxx, pad->Point1.X + pad->Thickness/2);
219
 
                maxy = MAX(maxy, pad->Point1.Y + pad->Thickness/2);
220
 
                maxx = MAX(maxx, pad->Point2.X + pad->Thickness/2);
221
 
                maxy = MAX(maxy, pad->Point2.Y + pad->Thickness/2);
222
 
        );
223
 
        ARC_LOOP(Element,
224
 
                /* arc->StartAngle is in [0,360], arc->Delta in [0,360] */
225
 
                angle1 = arc->StartAngle;
226
 
                angle2 = arc->StartAngle +arc->Delta;
227
 
 
228
 
                /* initialize limits */
229
 
                fminx = MIN(-cos(M180*(float) angle1),-cos(M180*(float) angle2));
230
 
                fmaxx = MAX(-cos(M180*(float) angle1),-cos(M180*(float) angle2));
231
 
                fminy = MIN(sin(M180*(float) angle1),sin(M180*(float) angle2));
232
 
                fmaxy = MAX(sin(M180*(float) angle1),sin(M180*(float) angle2));
233
 
 
234
 
                /* loop and check all angles n*180
235
 
                 * with angle1 <= a <= angle2
236
 
                 */
237
 
                for (angle = (angle1 /180 +1)*180; angle < angle2; angle += 180)
238
 
                {
239
 
                        fminx = MIN(-cos(M180 *(float) angle), fminx);
240
 
                        fmaxx = MAX(-cos(M180 *(float) angle), fmaxx);
241
 
                }
242
 
 
243
 
                /* loop and check all angles n*180+90
244
 
                 * with angle1 <= a <= angle2
245
 
                 */
246
 
                for (angle = ((angle1+90)/180)*180+90; angle < angle2; angle += 180)
247
 
                {
248
 
                        fminy = MIN(sin(M180 *(float) angle), fminy);
249
 
                        fmaxy = MAX(sin(M180 *(float) angle), fmaxy);
250
 
                }
251
 
                minx = MIN(minx, (int) (fminx *arc->Width) +arc->X);
252
 
                miny = MIN(miny, (int) (fminy *arc->Height) +arc->Y);
253
 
                maxx = MAX(maxx, (int) (fmaxx *arc->Width) +arc->X);
254
 
                maxy = MAX(maxy, (int) (fmaxy *arc->Height) +arc->Y);
255
 
        );
256
 
 
257
 
        Element->BoundingBox.X1 = minx;
258
 
        Element->BoundingBox.Y1 = miny;
259
 
        Element->BoundingBox.X2 = maxx;
260
 
        Element->BoundingBox.Y2 = maxy;
 
328
  BoxTypePtr box, vbox;
 
329
 
 
330
  if (Data && Data->element_tree)
 
331
    r_delete_entry (Data->element_tree, (BoxType *) Element);
 
332
  /* first update the text objects */
 
333
  ELEMENTTEXT_LOOP (Element);
 
334
  {
 
335
    if (Data && Data->name_tree[n])
 
336
      r_delete_entry (Data->name_tree[n], (BoxType *) text);
 
337
    SetTextBoundingBox (Font, text);
 
338
    if (Data && !Data->name_tree[n])
 
339
      Data->name_tree[n] = r_create_tree (NULL, 0, 0);
 
340
    if (Data)
 
341
      r_insert_entry (Data->name_tree[n], (BoxType *) text, 0);
 
342
  }
 
343
  END_LOOP;
 
344
 
 
345
  /* do not include the elementnames bounding box which
 
346
   * is handles seperatly
 
347
   */
 
348
  box = &Element->BoundingBox;
 
349
  vbox = &Element->VBox;
 
350
  box->X1 = box->Y1 = MAX_COORD;
 
351
  box->X2 = box->Y2 = 0;
 
352
  ELEMENTLINE_LOOP (Element);
 
353
  {
 
354
    SetLineBoundingBox (line);
 
355
    MAKEMIN (box->X1, line->Point1.X - (line->Thickness + 1) / 2);
 
356
    MAKEMIN (box->Y1, line->Point1.Y - (line->Thickness + 1) / 2);
 
357
    MAKEMIN (box->X1, line->Point2.X - (line->Thickness + 1) / 2);
 
358
    MAKEMIN (box->Y1, line->Point2.Y - (line->Thickness + 1) / 2);
 
359
    MAKEMAX (box->X2, line->Point1.X + (line->Thickness + 1) / 2);
 
360
    MAKEMAX (box->Y2, line->Point1.Y + (line->Thickness + 1) / 2);
 
361
    MAKEMAX (box->X2, line->Point2.X + (line->Thickness + 1) / 2);
 
362
    MAKEMAX (box->Y2, line->Point2.Y + (line->Thickness + 1) / 2);
 
363
  }
 
364
  END_LOOP;
 
365
  ARC_LOOP (Element);
 
366
  {
 
367
    SetArcBoundingBox (arc);
 
368
    MAKEMIN (box->X1, arc->BoundingBox.X1);
 
369
    MAKEMIN (box->Y1, arc->BoundingBox.Y1);
 
370
    MAKEMAX (box->X2, arc->BoundingBox.X2);
 
371
    MAKEMAX (box->Y2, arc->BoundingBox.Y2);
 
372
  }
 
373
  END_LOOP;
 
374
  *vbox = *box;
 
375
  PIN_LOOP (Element);
 
376
  {
 
377
    if (Data && Data->pin_tree)
 
378
      r_delete_entry (Data->pin_tree, (BoxType *) pin);
 
379
    SetPinBoundingBox (pin);
 
380
    if (Data)
 
381
      {
 
382
        if (!Data->pin_tree)
 
383
          Data->pin_tree = r_create_tree (NULL, 0, 0);
 
384
        r_insert_entry (Data->pin_tree, (BoxType *) pin, 0);
 
385
      }
 
386
    MAKEMIN (box->X1, pin->BoundingBox.X1);
 
387
    MAKEMIN (box->Y1, pin->BoundingBox.Y1);
 
388
    MAKEMAX (box->X2, pin->BoundingBox.X2);
 
389
    MAKEMAX (box->Y2, pin->BoundingBox.Y2);
 
390
    MAKEMIN (vbox->X1, pin->X - pin->Thickness / 2);
 
391
    MAKEMIN (vbox->Y1, pin->Y - pin->Thickness / 2);
 
392
    MAKEMAX (vbox->X2, pin->X + pin->Thickness / 2);
 
393
    MAKEMAX (vbox->Y2, pin->Y + pin->Thickness / 2);
 
394
  }
 
395
  END_LOOP;
 
396
  PAD_LOOP (Element);
 
397
  {
 
398
    if (Data && Data->pad_tree)
 
399
      r_delete_entry (Data->pad_tree, (BoxType *) pad);
 
400
    SetPadBoundingBox (pad);
 
401
    if (Data)
 
402
      {
 
403
        if (!Data->pad_tree)
 
404
          Data->pad_tree = r_create_tree (NULL, 0, 0);
 
405
        r_insert_entry (Data->pad_tree, (BoxType *) pad, 0);
 
406
        MAKEMIN (box->X1, pad->BoundingBox.X1);
 
407
        MAKEMIN (box->Y1, pad->BoundingBox.Y1);
 
408
        MAKEMAX (box->X2, pad->BoundingBox.X2);
 
409
        MAKEMAX (box->Y2, pad->BoundingBox.Y2);
 
410
        MAKEMIN (vbox->X1,
 
411
                 MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2);
 
412
        MAKEMIN (vbox->Y1,
 
413
                 MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness / 2);
 
414
        MAKEMAX (vbox->X2,
 
415
                 MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness / 2);
 
416
        MAKEMAX (vbox->Y2,
 
417
                 MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2);
 
418
      }
 
419
  }
 
420
  END_LOOP;
 
421
  /* now we set the EDGE2FLAG of the pad if Point2
 
422
   * is closer to the outside edge than Point1
 
423
   */
 
424
  PAD_LOOP (Element);
 
425
  {
 
426
    if (pad->Point1.Y == pad->Point2.Y)
 
427
      {
 
428
        /* horizontal pad */
 
429
        if (box->X2 - pad->Point2.X < pad->Point1.X - box->X1)
 
430
          SET_FLAG (EDGE2FLAG, pad);
 
431
        else
 
432
          CLEAR_FLAG (EDGE2FLAG, pad);
 
433
      }
 
434
    else
 
435
      {
 
436
        /* vertical pad */
 
437
        if (box->Y2 - pad->Point2.Y < pad->Point1.Y - box->Y1)
 
438
          SET_FLAG (EDGE2FLAG, pad);
 
439
        else
 
440
          CLEAR_FLAG (EDGE2FLAG, pad);
 
441
      }
 
442
  }
 
443
  END_LOOP;
 
444
 
 
445
  /* mark pins with component orientation */
 
446
  if ((box->X2 - box->X1) > (box->Y2 - box->Y1))
 
447
    {
 
448
      PIN_LOOP (Element);
 
449
      {
 
450
        SET_FLAG (EDGE2FLAG, pin);
 
451
      }
 
452
      END_LOOP;
 
453
    }
 
454
  else
 
455
    {
 
456
      PIN_LOOP (Element);
 
457
      {
 
458
        CLEAR_FLAG (EDGE2FLAG, pin);
 
459
      }
 
460
      END_LOOP;
 
461
    }
 
462
  if (Data && !Data->element_tree)
 
463
    Data->element_tree = r_create_tree (NULL, 0, 0);
 
464
  if (Data)
 
465
    r_insert_entry (Data->element_tree, box, 0);
261
466
}
262
467
 
263
468
/* ---------------------------------------------------------------------------
264
469
 * creates the bounding box of a text object
265
470
 */
266
 
void SetTextBoundingBox(FontTypePtr FontPtr, TextTypePtr Text)
 
471
void
 
472
SetTextBoundingBox (FontTypePtr FontPtr, TextTypePtr Text)
267
473
{
268
 
        SymbolTypePtr   symbol = FontPtr->Symbol;
269
 
        unsigned char   *s = (unsigned char *) Text->TextString;
270
 
        Position        width = 0,
271
 
                        height = 0;
272
 
 
273
 
                /* calculate size of the bounding box */
274
 
        for (; s && *s; s++)
275
 
                if (*s <= MAX_FONTPOSITION && symbol[*s].Valid)
276
 
                {
277
 
                        width  += symbol[*s].Width +symbol[*s].Delta;
278
 
                        height = MAX(height, (Position) symbol[*s].Height);
279
 
                }
280
 
                else
281
 
                {
282
 
                        width += ((FontPtr->DefaultSymbol.X2 -FontPtr->DefaultSymbol.X1) *6/5);
283
 
                        height = (FontPtr->DefaultSymbol.Y2 -FontPtr->DefaultSymbol.Y1);
284
 
                }
285
 
 
286
 
                /* scale values and rotate them */
287
 
        width = width *Text->Scale /100;
288
 
        height = height *Text->Scale /100;
289
 
 
290
 
                /* set upper-left and lower-right corner;
291
 
                 * swap coordinates if necessary (origin is already in 'swapped')
292
 
                 * and rotate box
293
 
                 */
294
 
        Text->BoundingBox.X1 = Text->X;
295
 
        Text->BoundingBox.Y1 = Text->Y;
296
 
        if (TEST_FLAG(ONSOLDERFLAG, Text))
297
 
        {
298
 
                Text->BoundingBox.X2 = Text->BoundingBox.X1 +SWAP_SIGN_X(width);
299
 
                Text->BoundingBox.Y2 = Text->BoundingBox.Y1 +SWAP_SIGN_Y(height);
300
 
                RotateBoxLowLevel(&Text->BoundingBox,
301
 
                        Text->X, Text->Y, (4-Text->Direction) & 0x03);
302
 
        }
303
 
        else
304
 
        {
305
 
                Text->BoundingBox.X2 = Text->BoundingBox.X1 +width;
306
 
                Text->BoundingBox.Y2 = Text->BoundingBox.Y1 +height;
307
 
                RotateBoxLowLevel(&Text->BoundingBox,
308
 
                        Text->X, Text->Y, Text->Direction);
309
 
        }
 
474
  SymbolTypePtr symbol = FontPtr->Symbol;
 
475
  unsigned char *s = (unsigned char *) Text->TextString;
 
476
  LocationType width = 0, height = 0;
 
477
  BDimension maxThick = 0;
 
478
  int i;
 
479
 
 
480
  /* calculate size of the bounding box */
 
481
  for (; s && *s; s++)
 
482
    if (*s <= MAX_FONTPOSITION && symbol[*s].Valid)
 
483
      {
 
484
        LineTypePtr line = symbol[*s].Line;
 
485
        for (i = 0; i < symbol[*s].LineN; line++, i++)
 
486
          if (line->Thickness > maxThick)
 
487
            maxThick = line->Thickness;
 
488
        width += symbol[*s].Width + symbol[*s].Delta;
 
489
        height = MAX (height, (LocationType) symbol[*s].Height);
 
490
      }
 
491
    else
 
492
      {
 
493
        width +=
 
494
          ((FontPtr->DefaultSymbol.X2 - FontPtr->DefaultSymbol.X1) * 6 / 5);
 
495
        height = (FontPtr->DefaultSymbol.Y2 - FontPtr->DefaultSymbol.Y1);
 
496
      }
 
497
 
 
498
  /* scale values */
 
499
  width *= Text->Scale / 100.;
 
500
  height *= Text->Scale / 100.;
 
501
  maxThick *= Text->Scale / 200.;
 
502
  if (maxThick < 400)
 
503
    maxThick = 400;
 
504
 
 
505
  /* set upper-left and lower-right corner;
 
506
   * swap coordinates if necessary (origin is already in 'swapped')
 
507
   * and rotate box
 
508
   */
 
509
  Text->BoundingBox.X1 = Text->X;
 
510
  Text->BoundingBox.Y1 = Text->Y;
 
511
  if (TEST_FLAG (ONSOLDERFLAG, Text))
 
512
    {
 
513
      Text->BoundingBox.X1 -= maxThick;
 
514
      Text->BoundingBox.Y1 -= SWAP_SIGN_Y (maxThick);
 
515
      Text->BoundingBox.X2 =
 
516
        Text->BoundingBox.X1 + SWAP_SIGN_X (width + maxThick);
 
517
      Text->BoundingBox.Y2 =
 
518
        Text->BoundingBox.Y1 + SWAP_SIGN_Y (height + 2 * maxThick);
 
519
      RotateBoxLowLevel (&Text->BoundingBox, Text->X, Text->Y,
 
520
                         (4 - Text->Direction) & 0x03);
 
521
    }
 
522
  else
 
523
    {
 
524
      Text->BoundingBox.X1 -= maxThick;
 
525
      Text->BoundingBox.Y1 -= maxThick;
 
526
      Text->BoundingBox.X2 = Text->BoundingBox.X1 + width + maxThick;
 
527
      Text->BoundingBox.Y2 = Text->BoundingBox.Y1 + height + 2 * maxThick;
 
528
      RotateBoxLowLevel (&Text->BoundingBox,
 
529
                         Text->X, Text->Y, Text->Direction);
 
530
    }
310
531
}
311
532
 
312
533
/* ---------------------------------------------------------------------------
313
534
 * returns True if data area is empty
314
535
 */
315
 
Boolean IsDataEmpty(DataTypePtr Data)
316
 
{
317
 
        Boolean         hasNoObjects;
318
 
        Cardinal        i;
319
 
 
320
 
        hasNoObjects = (Data->ViaN == 0);
321
 
        hasNoObjects &= (Data->ElementN == 0);
322
 
        for (i = 0; i < MAX_LAYER + 2; i++)
323
 
                hasNoObjects = hasNoObjects &&
324
 
                Data->Layer[i].LineN == 0 && 
325
 
                Data->Layer[i].ArcN == 0 &&
326
 
                Data->Layer[i].TextN == 0 &&
327
 
                Data->Layer[i].PolygonN == 0;
328
 
        return(hasNoObjects);
329
 
}
 
536
Boolean
 
537
IsDataEmpty (DataTypePtr Data)
 
538
{
 
539
  Boolean hasNoObjects;
 
540
  Cardinal i;
 
541
 
 
542
  hasNoObjects = (Data->ViaN == 0);
 
543
  hasNoObjects &= (Data->ElementN == 0);
 
544
  for (i = 0; i < MAX_LAYER + 2; i++)
 
545
    hasNoObjects = hasNoObjects &&
 
546
      Data->Layer[i].LineN == 0 &&
 
547
      Data->Layer[i].ArcN == 0 &&
 
548
      Data->Layer[i].TextN == 0 && Data->Layer[i].PolygonN == 0;
 
549
  return (hasNoObjects);
 
550
}
 
551
 
 
552
int
 
553
FlagIsDataEmpty (int parm)
 
554
{
 
555
  int i = IsDataEmpty (PCB->Data);
 
556
  return parm ? !i : i;
 
557
}
 
558
 
 
559
/* FLAG(DataEmpty,FlagIsDataEmpty,0) */
 
560
/* FLAG(DataNonEmpty,FlagIsDataEmpty,1) */
330
561
 
331
562
/* ---------------------------------------------------------------------------
332
563
 * gets minimum and maximum coordinates
333
564
 * returns NULL if layout is empty
334
565
 */
335
 
BoxTypePtr GetDataBoundingBox(DataTypePtr Data)
 
566
BoxTypePtr
 
567
GetDataBoundingBox (DataTypePtr Data)
336
568
{
337
 
        static  BoxType box;
338
 
 
339
 
                /* preset identifiers with highest and lowest possible values */
340
 
        box.X1 = box.Y1 = MAX_COORD;
341
 
        box.X2 = box.Y2 = 0;
342
 
 
343
 
                /* now scan for the lowest/highest X and Y coodinate */
344
 
        VIA_LOOP(Data,
345
 
                box.X1 = MIN(box.X1, via->X -via->Thickness/2);
346
 
                box.Y1 = MIN(box.Y1, via->Y -via->Thickness/2);
347
 
                box.X2 = MAX(box.X2, via->X +via->Thickness/2);
348
 
                box.Y2 = MAX(box.Y2, via->Y +via->Thickness/2);
349
 
        );
350
 
        ELEMENT_LOOP(Data,
351
 
                box.X1 = MIN(box.X1, element->BoundingBox.X1);
352
 
                box.Y1 = MIN(box.Y1, element->BoundingBox.Y1);
353
 
                box.X2 = MAX(box.X2, element->BoundingBox.X2);
354
 
                box.Y2 = MAX(box.Y2, element->BoundingBox.Y2);
355
 
                ELEMENTTEXT_LOOP(element,
356
 
                        box.X1 = MIN(box.X1, text->BoundingBox.X1);
357
 
                        box.Y1 = MIN(box.Y1, text->BoundingBox.Y1);
358
 
                        box.X2 = MAX(box.X2, text->BoundingBox.X2);
359
 
                        box.Y2 = MAX(box.Y2, text->BoundingBox.Y2);
360
 
                );
361
 
        );
362
 
        ALLLINE_LOOP(Data,
363
 
                box.X1 = MIN(box.X1, line->Point1.X - line->Thickness/2);
364
 
                box.Y1 = MIN(box.Y1, line->Point1.Y - line->Thickness/2);
365
 
                box.X1 = MIN(box.X1, line->Point2.X - line->Thickness/2);
366
 
                box.Y1 = MIN(box.Y1, line->Point2.Y - line->Thickness/2);
367
 
                box.X2 = MAX(box.X2, line->Point1.X + line->Thickness/2);
368
 
                box.Y2 = MAX(box.Y2, line->Point1.Y + line->Thickness/2);
369
 
                box.X2 = MAX(box.X2, line->Point2.X + line->Thickness/2);
370
 
                box.Y2 = MAX(box.Y2, line->Point2.Y + line->Thickness/2);
371
 
        );
372
 
        ALLARC_LOOP(Data,
373
 
                box.X1 = MIN(box.X1, arc->BoundingBox.X1);
374
 
                box.Y1 = MIN(box.Y1, arc->BoundingBox.Y1);
375
 
                box.X2 = MAX(box.X2, arc->BoundingBox.X2);
376
 
                box.Y2 = MAX(box.Y2, arc->BoundingBox.Y2);
377
 
        );
378
 
        ALLTEXT_LOOP(Data,
379
 
                box.X1 = MIN(box.X1, text->BoundingBox.X1);
380
 
                box.Y1 = MIN(box.Y1, text->BoundingBox.Y1);
381
 
                box.X2 = MAX(box.X2, text->BoundingBox.X2);
382
 
                box.Y2 = MAX(box.Y2, text->BoundingBox.Y2);
383
 
        );
384
 
        ALLPOLYGON_LOOP(Data,
385
 
                box.X1 = MIN(box.X1, polygon->BoundingBox.X1);
386
 
                box.Y1 = MIN(box.Y1, polygon->BoundingBox.Y1);
387
 
                box.X2 = MAX(box.X2, polygon->BoundingBox.X2);
388
 
                box.Y2 = MAX(box.Y2, polygon->BoundingBox.Y2);
389
 
        );
390
 
        return(IsDataEmpty(Data) ? NULL : &box);
 
569
  static BoxType box;
 
570
 
 
571
  /* preset identifiers with highest and lowest possible values */
 
572
  box.X1 = box.Y1 = MAX_COORD;
 
573
  box.X2 = box.Y2 = -MAX_COORD;
 
574
 
 
575
  /* now scan for the lowest/highest X and Y coodinate */
 
576
  VIA_LOOP (Data);
 
577
  {
 
578
    box.X1 = MIN (box.X1, via->X - via->Thickness / 2);
 
579
    box.Y1 = MIN (box.Y1, via->Y - via->Thickness / 2);
 
580
    box.X2 = MAX (box.X2, via->X + via->Thickness / 2);
 
581
    box.Y2 = MAX (box.Y2, via->Y + via->Thickness / 2);
 
582
  }
 
583
  END_LOOP;
 
584
  ELEMENT_LOOP (Data);
 
585
  {
 
586
    box.X1 = MIN (box.X1, element->BoundingBox.X1);
 
587
    box.Y1 = MIN (box.Y1, element->BoundingBox.Y1);
 
588
    box.X2 = MAX (box.X2, element->BoundingBox.X2);
 
589
    box.Y2 = MAX (box.Y2, element->BoundingBox.Y2);
 
590
    {
 
591
      TextTypePtr text = &NAMEONPCB_TEXT (element);
 
592
      box.X1 = MIN (box.X1, text->BoundingBox.X1);
 
593
      box.Y1 = MIN (box.Y1, text->BoundingBox.Y1);
 
594
      box.X2 = MAX (box.X2, text->BoundingBox.X2);
 
595
      box.Y2 = MAX (box.Y2, text->BoundingBox.Y2);
 
596
    };
 
597
  }
 
598
  END_LOOP;
 
599
  ALLLINE_LOOP (Data);
 
600
  {
 
601
    box.X1 = MIN (box.X1, line->Point1.X - line->Thickness / 2);
 
602
    box.Y1 = MIN (box.Y1, line->Point1.Y - line->Thickness / 2);
 
603
    box.X1 = MIN (box.X1, line->Point2.X - line->Thickness / 2);
 
604
    box.Y1 = MIN (box.Y1, line->Point2.Y - line->Thickness / 2);
 
605
    box.X2 = MAX (box.X2, line->Point1.X + line->Thickness / 2);
 
606
    box.Y2 = MAX (box.Y2, line->Point1.Y + line->Thickness / 2);
 
607
    box.X2 = MAX (box.X2, line->Point2.X + line->Thickness / 2);
 
608
    box.Y2 = MAX (box.Y2, line->Point2.Y + line->Thickness / 2);
 
609
  }
 
610
  ENDALL_LOOP;
 
611
  ALLARC_LOOP (Data);
 
612
  {
 
613
    box.X1 = MIN (box.X1, arc->BoundingBox.X1);
 
614
    box.Y1 = MIN (box.Y1, arc->BoundingBox.Y1);
 
615
    box.X2 = MAX (box.X2, arc->BoundingBox.X2);
 
616
    box.Y2 = MAX (box.Y2, arc->BoundingBox.Y2);
 
617
  }
 
618
  ENDALL_LOOP;
 
619
  ALLTEXT_LOOP (Data);
 
620
  {
 
621
    box.X1 = MIN (box.X1, text->BoundingBox.X1);
 
622
    box.Y1 = MIN (box.Y1, text->BoundingBox.Y1);
 
623
    box.X2 = MAX (box.X2, text->BoundingBox.X2);
 
624
    box.Y2 = MAX (box.Y2, text->BoundingBox.Y2);
 
625
  }
 
626
  ENDALL_LOOP;
 
627
  ALLPOLYGON_LOOP (Data);
 
628
  {
 
629
    box.X1 = MIN (box.X1, polygon->BoundingBox.X1);
 
630
    box.Y1 = MIN (box.Y1, polygon->BoundingBox.Y1);
 
631
    box.X2 = MAX (box.X2, polygon->BoundingBox.X2);
 
632
    box.Y2 = MAX (box.Y2, polygon->BoundingBox.Y2);
 
633
  }
 
634
  ENDALL_LOOP;
 
635
  return (IsDataEmpty (Data) ? NULL : &box);
391
636
}
392
637
 
393
638
/* ---------------------------------------------------------------------------
394
 
 * centers the displayed PCB around the specified point
395
 
 * (X,Y) in screen coordinates.
396
 
 * if Delta is true, simply move the center by X, Y
 
639
 * centers the displayed PCB around the specified point (X,Y)
 
640
 * if Delta is false, X,Y are in absolute PCB coordinates
 
641
 * if Delta is true, simply move the center by an amount X, Y in screen
 
642
 * coordinates
397
643
 */
398
 
void CenterDisplay(Position X, Position Y, Boolean Delta)
 
644
void
 
645
CenterDisplay (LocationType X, LocationType Y, Boolean Delta)
399
646
{
 
647
  LocationType x, y;
 
648
 
400
649
#ifdef DEBUGDISP
401
 
        Message("CenterDisplay(%d, %d, %s)\n", X, Y, Delta ? "True" : "False" );
 
650
  Message ("CenterDisplay(%d, %d, %s)\n", X, Y, Delta ? "True" : "False");
402
651
#endif
403
 
        X -= Xorig;
404
 
        Y -= Yorig;
405
 
                /* move origin half a screen width/height to get display centered */
406
 
        if (!Delta)
407
 
                X -= Output.Width/2; 
408
 
 
409
 
        if (!Delta)
410
 
                Y -= Output.Height/2;
411
 
        Pan(X, Y, True, True);
 
652
  if (!Delta)
 
653
    {
 
654
      x = X - TO_PCB (Output.Width / 2);
 
655
      if (SWAP_IDENT)
 
656
        y = PCB->MaxHeight - Y - TO_PCB (Output.Height / 2);
 
657
      else
 
658
        y = Y - TO_PCB (Output.Height / 2);
 
659
    }
 
660
  else
 
661
    {
 
662
      x = Xorig + TO_PCB (X);
 
663
      y = Yorig + TO_PCB (Y);
 
664
    }
 
665
  Pan (x, y, True, True);
412
666
}
413
667
 
414
668
/* ---------------------------------------------------------------------------
416
670
 * is at the zero position. The y coordinates are moved so that min(y) = 0
417
671
 * 
418
672
 */
419
 
void SetFontInfo(FontTypePtr Ptr)
 
673
void
 
674
SetFontInfo (FontTypePtr Ptr)
420
675
{
421
 
        Cardinal        i, j;
422
 
        SymbolTypePtr   symbol;
423
 
        LineTypePtr     line;
424
 
        Position        totalminy = MAX_COORD;
425
 
 
426
 
                /* calculate cell with and height (is at least DEFAULT_CELLSIZE)
427
 
                 * maximum cell width and height
428
 
                 * minimum x and y position of all lines
429
 
                 */
430
 
        Ptr->MaxWidth = DEFAULT_CELLSIZE;
431
 
        Ptr->MaxHeight = DEFAULT_CELLSIZE;
432
 
        for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
 
676
  Cardinal i, j;
 
677
  SymbolTypePtr symbol;
 
678
  LineTypePtr line;
 
679
  LocationType totalminy = MAX_COORD;
 
680
 
 
681
  /* calculate cell with and height (is at least DEFAULT_CELLSIZE)
 
682
   * maximum cell width and height
 
683
   * minimum x and y position of all lines
 
684
   */
 
685
  Ptr->MaxWidth = DEFAULT_CELLSIZE;
 
686
  Ptr->MaxHeight = DEFAULT_CELLSIZE;
 
687
  for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
 
688
    {
 
689
      LocationType minx, miny, maxx, maxy;
 
690
 
 
691
      /* next one if the index isn't used or symbol is empty (SPACE) */
 
692
      if (!symbol->Valid || !symbol->LineN)
 
693
        continue;
 
694
 
 
695
      minx = miny = MAX_COORD;
 
696
      maxx = maxy = 0;
 
697
      for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
433
698
        {
434
 
                Position        minx, miny,
435
 
                                maxx, maxy;
436
 
 
437
 
                        /* next one if the index isn't used or symbol is empty (SPACE) */
438
 
                if (!symbol->Valid || !symbol->LineN)
439
 
                        continue;
440
 
 
441
 
                minx = miny = MAX_COORD;
442
 
                maxx = maxy = 0;
443
 
                for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
444
 
                {
445
 
                        minx = MIN(minx, line->Point1.X);
446
 
                        miny = MIN(miny, line->Point1.Y);
447
 
                        minx = MIN(minx, line->Point2.X);
448
 
                        miny = MIN(miny, line->Point2.Y);
449
 
                        maxx = MAX(maxx, line->Point1.X);
450
 
                        maxy = MAX(maxy, line->Point1.Y);
451
 
                        maxx = MAX(maxx, line->Point2.X);
452
 
                        maxy = MAX(maxy, line->Point2.Y);
453
 
                }
454
 
 
455
 
                        /* move symbol to left edge */
456
 
                for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
457
 
                        MOVE_LINE_LOWLEVEL(line, -minx, 0);
458
 
 
459
 
                        /* set symbol bounding box with a minimum cell size of (1,1) */
460
 
                symbol->Width = maxx -minx +1;
461
 
                symbol->Height = maxy +1;
462
 
 
463
 
                        /* check total min/max  */
464
 
                Ptr->MaxWidth = MAX(Ptr->MaxWidth, symbol->Width);
465
 
                Ptr->MaxHeight = MAX(Ptr->MaxHeight, symbol->Height);
466
 
                totalminy = MIN(totalminy, miny);
 
699
          minx = MIN (minx, line->Point1.X);
 
700
          miny = MIN (miny, line->Point1.Y);
 
701
          minx = MIN (minx, line->Point2.X);
 
702
          miny = MIN (miny, line->Point2.Y);
 
703
          maxx = MAX (maxx, line->Point1.X);
 
704
          maxy = MAX (maxy, line->Point1.Y);
 
705
          maxx = MAX (maxx, line->Point2.X);
 
706
          maxy = MAX (maxy, line->Point2.Y);
467
707
        }
468
708
 
469
 
                /* move coordinate system to the upper edge (lowest y on screen) */
470
 
        for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
471
 
                if (symbol->Valid)
472
 
                {
473
 
                        symbol->Height -= totalminy;
474
 
                        for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
475
 
                                MOVE_LINE_LOWLEVEL(line, 0, -totalminy);
476
 
                }
477
 
 
478
 
                /* setup the box for the default symbol */
479
 
        Ptr->DefaultSymbol.X1 = Ptr->DefaultSymbol.Y1 = 0;
480
 
        Ptr->DefaultSymbol.X2 = Ptr->DefaultSymbol.X1 +Ptr->MaxWidth;
481
 
        Ptr->DefaultSymbol.Y2 = Ptr->DefaultSymbol.Y1 +Ptr->MaxHeight;
482
 
483
 
 
484
 
static void GetNum(char **s, Dimension *num)
 
709
      /* move symbol to left edge */
 
710
      for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
 
711
        MOVE_LINE_LOWLEVEL (line, -minx, 0);
 
712
 
 
713
      /* set symbol bounding box with a minimum cell size of (1,1) */
 
714
      symbol->Width = maxx - minx + 1;
 
715
      symbol->Height = maxy + 1;
 
716
 
 
717
      /* check total min/max  */
 
718
      Ptr->MaxWidth = MAX (Ptr->MaxWidth, symbol->Width);
 
719
      Ptr->MaxHeight = MAX (Ptr->MaxHeight, symbol->Height);
 
720
      totalminy = MIN (totalminy, miny);
 
721
    }
 
722
 
 
723
  /* move coordinate system to the upper edge (lowest y on screen) */
 
724
  for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
 
725
    if (symbol->Valid)
 
726
      {
 
727
        symbol->Height -= totalminy;
 
728
        for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
 
729
          MOVE_LINE_LOWLEVEL (line, 0, -totalminy);
 
730
      }
 
731
 
 
732
  /* setup the box for the default symbol */
 
733
  Ptr->DefaultSymbol.X1 = Ptr->DefaultSymbol.Y1 = 0;
 
734
  Ptr->DefaultSymbol.X2 = Ptr->DefaultSymbol.X1 + Ptr->MaxWidth;
 
735
  Ptr->DefaultSymbol.Y2 = Ptr->DefaultSymbol.Y1 + Ptr->MaxHeight;
 
736
}
 
737
 
 
738
static void
 
739
GetNum (char **s, BDimension * num)
485
740
{
486
 
        *num = atoi(*s);
487
 
        while (isdigit(**s))
488
 
                (*s)++;
 
741
  *num = atoi (*s);
 
742
  while (isdigit (**s))
 
743
    (*s)++;
489
744
}
490
745
 
491
746
 
492
747
/* ----------------------------------------------------------------------
493
748
 * parses the routes definition string which is a colon seperated list of
494
 
 * comma seperated Name, Dimension, Dimension, Dimension
495
 
 * e.g. Signal,20,40,20:Power,40,60,28:...
 
749
 * comma seperated Name, Dimension, Dimension, Dimension, Dimension
 
750
 * e.g. Signal,20,40,20,10:Power,40,60,28,10:...
496
751
 */
497
 
int ParseRouteString(char *s, RouteStyleTypePtr routeStyle)
 
752
int
 
753
ParseRouteString (char *s, RouteStyleTypePtr routeStyle, int scale)
498
754
{
499
 
        int             i, style;
500
 
        char            Name[256];
 
755
  int i, style;
 
756
  char Name[256];
501
757
 
502
 
        memset(routeStyle, 0, NUM_STYLES * sizeof(RouteStyleType));
503
 
        for (style = 0; style < NUM_STYLES; style++, routeStyle++)
504
 
        {
505
 
                while(*s && isspace(*s))
506
 
                        s++;
507
 
                for (i = 0; *s && *s != ','; i++)       
508
 
                        Name[i] = *s++;
509
 
                Name[i] = '\0';
510
 
                routeStyle->Name = MyStrdup(Name, "ParseRouteString()");
511
 
                if (!isdigit(*++s))
512
 
                        goto error;
513
 
                GetNum(&s, &routeStyle->Thick);
514
 
                while(*s && isspace(*s))
515
 
                        s++;
516
 
                if (*s++ != ',')
517
 
                        goto error;
518
 
                while(*s && isspace(*s))
519
 
                        s++;
520
 
                if (!isdigit(*s))
521
 
                        goto error;
522
 
                GetNum(&s, &routeStyle->Diameter);
523
 
                while(*s && isspace(*s))
524
 
                        s++;
525
 
                if (*s++ != ',')
526
 
                        goto error;
527
 
                while(*s && isspace(*s))
528
 
                        s++;
529
 
                if (!isdigit(*s))
530
 
                        goto error;
531
 
                GetNum(&s, &routeStyle->Hole);
532
 
                if (style < NUM_STYLES - 1)
533
 
                {
534
 
                        while(*s && isspace(*s))
535
 
                                s++;
536
 
                        if (*s++ != ':')
537
 
                                goto error;
538
 
                }
539
 
        }
540
 
        return(0);
 
758
  memset (routeStyle, 0, NUM_STYLES * sizeof (RouteStyleType));
 
759
  for (style = 0; style < NUM_STYLES; style++, routeStyle++)
 
760
    {
 
761
      while (*s && isspace (*s))
 
762
        s++;
 
763
      for (i = 0; *s && *s != ','; i++)
 
764
        Name[i] = *s++;
 
765
      Name[i] = '\0';
 
766
      routeStyle->Name = MyStrdup (Name, "ParseRouteString()");
 
767
      if (!isdigit (*++s))
 
768
        goto error;
 
769
      GetNum (&s, &routeStyle->Thick);
 
770
      routeStyle->Thick *= scale;
 
771
      while (*s && isspace (*s))
 
772
        s++;
 
773
      if (*s++ != ',')
 
774
        goto error;
 
775
      while (*s && isspace (*s))
 
776
        s++;
 
777
      if (!isdigit (*s))
 
778
        goto error;
 
779
      GetNum (&s, &routeStyle->Diameter);
 
780
      routeStyle->Diameter *= scale;
 
781
      while (*s && isspace (*s))
 
782
        s++;
 
783
      if (*s++ != ',')
 
784
        goto error;
 
785
      while (*s && isspace (*s))
 
786
        s++;
 
787
      if (!isdigit (*s))
 
788
        goto error;
 
789
      GetNum (&s, &routeStyle->Hole);
 
790
      routeStyle->Hole *= scale;
 
791
      /* for backwards-compatibilty, we use a 10-mil default
 
792
       * for styles which omit the keepaway specification. */
 
793
      if (*s != ',')
 
794
        routeStyle->Keepaway = 1000;
 
795
      else
 
796
        {
 
797
          s++;
 
798
          while (*s && isspace (*s))
 
799
            s++;
 
800
          if (!isdigit (*s))
 
801
            goto error;
 
802
          GetNum (&s, &routeStyle->Keepaway);
 
803
          routeStyle->Keepaway *= scale;
 
804
          while (*s && isspace (*s))
 
805
            s++;
 
806
        }
 
807
      if (style < NUM_STYLES - 1)
 
808
        {
 
809
          while (*s && isspace (*s))
 
810
            s++;
 
811
          if (*s++ != ':')
 
812
            goto error;
 
813
        }
 
814
    }
 
815
  return (0);
541
816
error:
542
 
        memset(routeStyle, 0, NUM_STYLES * sizeof(RouteStyleType));
543
 
        return(1);
 
817
  memset (routeStyle, 0, NUM_STYLES * sizeof (RouteStyleType));
 
818
  return (1);
544
819
}
545
820
 
546
821
/* ----------------------------------------------------------------------
547
822
 * parses the group definition string which is a colon seperated list of
548
823
 * comma seperated layer numbers (1,2,b:4,6,8,t)
549
824
 */
550
 
int ParseGroupString(char *s, LayerGroupTypePtr LayerGroup)
 
825
int
 
826
ParseGroupString (char *s, LayerGroupTypePtr LayerGroup)
551
827
{
552
 
        int     group,
553
 
                member,
554
 
                layer;
555
 
        Boolean c_set = False,  /* flags for the two special layers to */
556
 
                s_set = False;  /* provide a default setting for old formats */
557
 
 
558
 
                /* clear struct */
559
 
        memset(LayerGroup, 0, sizeof (LayerGroupType));
560
 
 
561
 
                /* loop over all groups */
562
 
        for (group = 0; s && *s && group < MAX_LAYER; group++)
 
828
  int group, member, layer;
 
829
  Boolean c_set = False,        /* flags for the two special layers to */
 
830
    s_set = False;              /* provide a default setting for old formats */
 
831
 
 
832
  /* clear struct */
 
833
  memset (LayerGroup, 0, sizeof (LayerGroupType));
 
834
 
 
835
  /* loop over all groups */
 
836
  for (group = 0; s && *s && group < MAX_LAYER; group++)
 
837
    {
 
838
      while (*s && isspace (*s))
 
839
        s++;
 
840
 
 
841
      /* loop over all group members */
 
842
      for (member = 0; *s; s++)
563
843
        {
564
 
                while (*s && isspace(*s))
565
 
                        s++;
566
 
 
567
 
                        /* loop over all group members */
568
 
                for (member = 0; *s; s++)
569
 
                {
570
 
                                /* ignore white spaces and get layernumber */
571
 
                        while(*s && isspace(*s))
572
 
                                s++;
573
 
                        switch (*s)
574
 
                        {
575
 
                                case 'c':
576
 
                                case 'C':       layer = MAX_LAYER +COMPONENT_LAYER;
577
 
                                                        c_set = True;
578
 
                                                        break;
579
 
 
580
 
                                case 's':
581
 
                                case 'S':       layer = MAX_LAYER +SOLDER_LAYER;
582
 
                                                        s_set = True;
583
 
                                                        break;
584
 
 
585
 
                                default:        if (!isdigit(*s))
586
 
                                                                goto error;
587
 
                                                        layer = atoi(s) -1;
588
 
                                                        break;
589
 
                        }
590
 
                        if (layer > MAX_LAYER+ MAX(SOLDER_LAYER, COMPONENT_LAYER) ||
591
 
                                member >= MAX_LAYER+1)
592
 
                                goto error;
593
 
                        LayerGroup->Entries[group][member++] = layer;
594
 
                        while (*++s && isdigit(*s));
595
 
 
596
 
                                /* ignore white spaces and check for seperator */
597
 
                        while (*s && isspace(*s))
598
 
                                s++;
599
 
                        if (!*s || *s == ':')
600
 
                                break;
601
 
                        if (*s != ',')
602
 
                                goto error;
603
 
                }
604
 
                LayerGroup->Number[group] = member;
605
 
                if (*s == ':')
606
 
                        s++;
 
844
          /* ignore white spaces and get layernumber */
 
845
          while (*s && isspace (*s))
 
846
            s++;
 
847
          switch (*s)
 
848
            {
 
849
            case 'c':
 
850
            case 'C':
 
851
              layer = MAX_LAYER + COMPONENT_LAYER;
 
852
              c_set = True;
 
853
              break;
 
854
 
 
855
            case 's':
 
856
            case 'S':
 
857
              layer = MAX_LAYER + SOLDER_LAYER;
 
858
              s_set = True;
 
859
              break;
 
860
 
 
861
            default:
 
862
              if (!isdigit (*s))
 
863
                goto error;
 
864
              layer = atoi (s) - 1;
 
865
              break;
 
866
            }
 
867
          if (layer > MAX_LAYER + MAX (SOLDER_LAYER, COMPONENT_LAYER) ||
 
868
              member >= MAX_LAYER + 1)
 
869
            goto error;
 
870
          LayerGroup->Entries[group][member++] = layer;
 
871
          while (*++s && isdigit (*s));
 
872
 
 
873
          /* ignore white spaces and check for seperator */
 
874
          while (*s && isspace (*s))
 
875
            s++;
 
876
          if (!*s || *s == ':')
 
877
            break;
 
878
          if (*s != ',')
 
879
            goto error;
607
880
        }
608
 
        if (!s_set)
609
 
                LayerGroup->Entries[SOLDER_LAYER][LayerGroup->Number[SOLDER_LAYER]++] =
610
 
                        MAX_LAYER +SOLDER_LAYER;
611
 
        if (!c_set)
612
 
                LayerGroup->Entries[COMPONENT_LAYER][LayerGroup->Number[COMPONENT_LAYER]++] =
613
 
                        MAX_LAYER +COMPONENT_LAYER;
614
 
        return(0);
 
881
      LayerGroup->Number[group] = member;
 
882
      if (*s == ':')
 
883
        s++;
 
884
    }
 
885
  if (!s_set)
 
886
    LayerGroup->Entries[SOLDER_LAYER][LayerGroup->Number[SOLDER_LAYER]++] =
 
887
      MAX_LAYER + SOLDER_LAYER;
 
888
  if (!c_set)
 
889
    LayerGroup->
 
890
      Entries[COMPONENT_LAYER][LayerGroup->Number[COMPONENT_LAYER]++] =
 
891
      MAX_LAYER + COMPONENT_LAYER;
 
892
  return (0);
615
893
 
616
 
                        /* reset structure on error */
617
 
        error:
618
 
                memset(LayerGroup, 0, sizeof (LayerGroupType));
619
 
                return(1);
 
894
  /* reset structure on error */
 
895
error:
 
896
  memset (LayerGroup, 0, sizeof (LayerGroupType));
 
897
  return (1);
620
898
}
621
899
 
622
900
/* ---------------------------------------------------------------------------
623
901
 * quits application
624
902
 */
625
 
void QuitApplication(void)
 
903
void
 
904
QuitApplication (void)
626
905
{
627
 
                /* save data if necessary */
628
 
        if (PCB->Changed && Settings.SaveInTMP)
629
 
                EmergencySave();
630
 
        exit(0);
 
906
  /* save data if necessary */
 
907
  if (PCB->Changed && Settings.SaveInTMP)
 
908
    EmergencySave ();
 
909
  exit (0);
631
910
}
632
911
 
633
912
/* ---------------------------------------------------------------------------
635
914
 * %f is replaced by the filename 
636
915
 * %p by the searchpath
637
916
 */
638
 
char *EvaluateFilename(char *Template, char *Path, char *Filename,
639
 
        char *Parameter)
 
917
char *
 
918
EvaluateFilename (char *Template, char *Path, char *Filename, char *Parameter)
640
919
{
641
 
        static  DynamicStringType       command;
642
 
        char                            *p;
 
920
  static DynamicStringType command;
 
921
  char *p;
643
922
 
644
 
        DSClearString(&command);
645
 
        for (p = Template; *p; p++)
646
 
        {
647
 
                        /* copy character or add string to command */
648
 
                if (*p == '%' && (*(p+1) == 'f' || *(p+1) == 'p' || *(p+1) == 'a'))
649
 
                        switch(*(++p))
650
 
                        {
651
 
                                case 'a': DSAddString(&command, Parameter); break;
652
 
                                case 'f': DSAddString(&command, Filename); break;
653
 
                                case 'p': DSAddString(&command, Path); break;
654
 
                        }
655
 
                else
656
 
                        DSAddCharacter(&command, *p);
657
 
        }
658
 
        DSAddCharacter(&command, '\0');
659
 
        return(MyStrdup(command.Data, "EvaluateFilename()"));
 
923
  DSClearString (&command);
 
924
  for (p = Template; *p; p++)
 
925
    {
 
926
      /* copy character or add string to command */
 
927
      if (*p == '%'
 
928
          && (*(p + 1) == 'f' || *(p + 1) == 'p' || *(p + 1) == 'a'))
 
929
        switch (*(++p))
 
930
          {
 
931
          case 'a':
 
932
            DSAddString (&command, Parameter);
 
933
            break;
 
934
          case 'f':
 
935
            DSAddString (&command, Filename);
 
936
            break;
 
937
          case 'p':
 
938
            DSAddString (&command, Path);
 
939
            break;
 
940
          }
 
941
      else
 
942
        DSAddCharacter (&command, *p);
 
943
    }
 
944
  DSAddCharacter (&command, '\0');
 
945
  return (MyStrdup (command.Data, "EvaluateFilename()"));
660
946
}
661
947
 
662
948
/* ---------------------------------------------------------------------------
663
949
 * concatenates directory and filename if directory != NULL,
664
950
 * expands them with a shell and returns the found name(s) or NULL
665
951
 */
666
 
char *ExpandFilename(char *Dirname, char *Filename)
667
 
{
668
 
        static  DynamicStringType       answer;
669
 
        char                            *command;
670
 
        FILE                            *pipe;
671
 
        int                             c;
672
 
 
673
 
                /* allocate memory for commandline and build it */
674
 
        DSClearString(&answer);
675
 
        if (Dirname)
676
 
        {
677
 
                command = MyCalloc(strlen(Filename) +strlen(Dirname) +7,
678
 
                        sizeof(char), "ExpandFilename()");
679
 
                sprintf(command, "echo %s/%s", Dirname, Filename);
680
 
        }
681
 
        else
682
 
        {
683
 
                command = MyCalloc(strlen(Filename) +6, sizeof(char), "Expand()");
684
 
                sprintf(command, "echo %s", Filename);
685
 
        }
686
 
 
687
 
                /* execute it with shell */
688
 
        if ((pipe = popen(command, "r")) != NULL)
689
 
        {
690
 
                        /* discard all but the first returned line */
691
 
                for(;;)
692
 
                {
693
 
                        if ((c = fgetc(pipe)) == EOF || c == '\n' || c == '\r')
694
 
                                break;
695
 
                        else
696
 
                                DSAddCharacter(&answer, c);
697
 
                }
698
 
 
699
 
                SaveFree(command);
700
 
                return (pclose(pipe) ? NULL : answer.Data);
701
 
        }
702
 
 
703
 
                /* couldn't be expanded by the shell */
704
 
        PopenErrorMessage(command);
705
 
        SaveFree(command);
706
 
        return(NULL);   
707
 
}
708
 
 
709
 
/* ---------------------------------------------------------------------------
710
 
 * wait for a button of key event in output window and calls the
711
 
 * action when a button event has been detected
712
 
 * cursor key events are handled
713
 
 */
714
 
Boolean GetPosition(char *MessageText)
715
 
{
716
 
        XEvent          event;
717
 
        XAnyEvent       *any = (XAnyEvent *) &event;
718
 
        KeySym          keysym;
719
 
        char            buffer[10];
720
 
        Cursor          oldCursor;
721
 
        int             oldObjState;
722
 
        int             oldLineState;
723
 
        int             oldBoxState;
724
 
 
725
 
        MessagePrompt(MessageText);
726
 
        oldObjState = Crosshair.AttachedObject.State;
727
 
        oldLineState = Crosshair.AttachedLine.State;
728
 
        oldBoxState = Crosshair.AttachedBox.State;
729
 
        HideCrosshair(True);
730
 
        Crosshair.AttachedObject.State = STATE_FIRST;
731
 
        Crosshair.AttachedLine.State = STATE_FIRST;
732
 
        Crosshair.AttachedBox.State = STATE_FIRST;
733
 
        oldCursor = SetOutputXCursor(XC_hand2);
734
 
        RestoreCrosshair(True);
735
 
 
736
 
                /* eat up all events that would cause actions to be performed */
737
 
        for(;;)
738
 
        {
739
 
                XtAppNextEvent(Context, &event);
740
 
                switch(any->type)
741
 
                {
742
 
                        case KeyRelease:
743
 
                        case KeyPress:
744
 
                        case ButtonPress:
745
 
                                        /* first check if we are inside the output window */
746
 
                                if (any->window != Output.OutputWindow)
747
 
                                        break;
748
 
 
749
 
                                        /* evaluate cursor keys and modifier keys;
750
 
                                         * dispatch the event if true
751
 
                                         */
752
 
                                XLookupString((XKeyEvent *) &event, buffer, sizeof(buffer),
753
 
                                        &keysym, NULL);
754
 
                                if (IsCursorKey(keysym) || IsModifierKey(keysym))
755
 
                                        XtDispatchEvent(&event);
756
 
                                else
757
 
                                {
758
 
                                                /* abort on any other key;
759
 
                                                 * restore cursor and clear message line
760
 
                                                 */
761
 
                                        HideCrosshair(True);
762
 
                                        Crosshair.AttachedObject.State = oldObjState;
763
 
                                        Crosshair.AttachedLine.State = oldLineState;
764
 
                                        Crosshair.AttachedBox.State = oldBoxState;
765
 
                                        RestoreCrosshair(True);
766
 
                                        SetOutputXCursor(oldCursor);
767
 
                                        MessagePrompt(NULL);
768
 
                                        return(any->type == ButtonPress);
769
 
                                }
770
 
                                break;
771
 
 
772
 
                        default:
773
 
                                XtDispatchEvent(&event);
774
 
                }
775
 
        }
 
952
char *
 
953
ExpandFilename (char *Dirname, char *Filename)
 
954
{
 
955
  static DynamicStringType answer;
 
956
  char *command;
 
957
  FILE *pipe;
 
958
  int c;
 
959
 
 
960
  /* allocate memory for commandline and build it */
 
961
  DSClearString (&answer);
 
962
  if (Dirname)
 
963
    {
 
964
      command = MyCalloc (strlen (Filename) + strlen (Dirname) + 7,
 
965
                          sizeof (char), "ExpandFilename()");
 
966
      sprintf (command, "echo %s/%s", Dirname, Filename);
 
967
    }
 
968
  else
 
969
    {
 
970
      command = MyCalloc (strlen (Filename) + 6, sizeof (char), "Expand()");
 
971
      sprintf (command, "echo %s", Filename);
 
972
    }
 
973
 
 
974
  /* execute it with shell */
 
975
  if ((pipe = popen (command, "r")) != NULL)
 
976
    {
 
977
      /* discard all but the first returned line */
 
978
      for (;;)
 
979
        {
 
980
          if ((c = fgetc (pipe)) == EOF || c == '\n' || c == '\r')
 
981
            break;
 
982
          else
 
983
            DSAddCharacter (&answer, c);
 
984
        }
 
985
 
 
986
      SaveFree (command);
 
987
      return (pclose (pipe) ? NULL : answer.Data);
 
988
    }
 
989
 
 
990
  /* couldn't be expanded by the shell */
 
991
  PopenErrorMessage (command);
 
992
  SaveFree (command);
 
993
  return (NULL);
776
994
}
777
995
 
778
996
/* ----------------------------------------------------------------------
779
997
 * releases pixmap used to draw output data
780
998
 */
781
 
void ReleaseOffscreenPixmap(void)
782
 
{
783
 
        render = True;
784
 
        if (VALID_PIXMAP(Offscreen))
785
 
                XFreePixmap(Dpy, Offscreen);
786
 
 
787
 
                /* mark pixmap unusable */
788
 
        Offscreen = BadAlloc;
789
 
}
790
 
 
791
 
/* ---------------------------------------------------------------------------
792
 
 * sets the X cursor for the output window (uses cursorfont)
793
 
 * XSync() is used to force a cursor change, old memory is released
794
 
 */
795
 
unsigned int SetOutputXCursor(unsigned int Shape)
796
 
{
797
 
        unsigned int    oldShape = Output.XCursorShape;
798
 
        Cursor          oldCursor = Output.XCursor;
799
 
 
800
 
                /* check if window exists to prevent from fatal errors */
801
 
        if (Output.OutputWindow)
802
 
        {
803
 
                Output.XCursorShape = Shape;
804
 
                if (Shape == XC_Clockwise)
805
 
                {
806
 
                        Screen *screen;
807
 
                        XColor blk, wht;
808
 
 
809
 
                        screen = XtScreen(Output.Toplevel);
810
 
                        blk.pixel = BlackPixelOfScreen(screen);
811
 
                        wht.pixel = WhitePixelOfScreen(screen);
812
 
                        blk.red = 0; blk.green = 0; blk.blue = 0;
813
 
                        wht.red = 65535; wht.green = 65535; wht.blue = 65535;
814
 
                        blk.flags = DoRed | DoGreen | DoBlue;
815
 
                        wht.flags = DoRed | DoGreen | DoBlue;
816
 
                        Output.XCursor = XCreatePixmapCursor(Dpy, XC_clock_source,
817
 
                                XC_clock_mask, &blk, &wht, rotateIcon_x_hot,
818
 
                                rotateIcon_y_hot);
819
 
                }
820
 
                else
821
 
                        Output.XCursor= XCreateFontCursor(Dpy, Shape);
822
 
                XDefineCursor(Dpy, Output.OutputWindow, Output.XCursor);
823
 
                XSync(Dpy, False);
824
 
 
825
 
                        /* release old cursor and return old shape */
826
 
                if (oldCursor)
827
 
                        XFreeCursor(Dpy, oldCursor);
828
 
                return(oldShape);
829
 
        }
830
 
        return(DEFAULT_CURSORSHAPE);
 
999
void
 
1000
ReleaseOffscreenPixmap (void)
 
1001
{
 
1002
  render = True;
 
1003
  if (VALID_PIXMAP (Offscreen))
 
1004
    XFreePixmap (Dpy, Offscreen);
 
1005
 
 
1006
  /* mark pixmap unusable */
 
1007
  Offscreen = BadAlloc;
831
1008
}
832
1009
 
833
1010
/* ---------------------------------------------------------------------------
834
1011
 * returns the layer number for the passed pointer
835
1012
 */
836
 
int GetLayerNumber(DataTypePtr Data, LayerTypePtr Layer)
 
1013
int
 
1014
GetLayerNumber (DataTypePtr Data, LayerTypePtr Layer)
837
1015
{
838
 
        int     i;
 
1016
  int i;
839
1017
 
840
 
        for (i = 0; i < MAX_LAYER + 2; i++)
841
 
                if (Layer == &Data->Layer[i])
842
 
                        break;
843
 
        return(i);
 
1018
  for (i = 0; i < MAX_LAYER + 2; i++)
 
1019
    if (Layer == &Data->Layer[i])
 
1020
      break;
 
1021
  return (i);
844
1022
}
845
1023
 
846
1024
/* ---------------------------------------------------------------------------
847
1025
 * returns the layergroup number for the passed pointer
848
1026
 */
849
 
int GetLayerGroupNumberByPointer(LayerTypePtr Layer)
 
1027
int
 
1028
GetLayerGroupNumberByPointer (LayerTypePtr Layer)
850
1029
{
851
 
        return(GetLayerGroupNumberByNumber(GetLayerNumber(PCB->Data, Layer)));
 
1030
  return (GetLayerGroupNumberByNumber (GetLayerNumber (PCB->Data, Layer)));
852
1031
}
853
1032
 
854
1033
/* ---------------------------------------------------------------------------
855
1034
 * returns the layergroup number for the passed layernumber
856
1035
 */
857
 
int GetLayerGroupNumberByNumber(Cardinal Layer)
 
1036
int
 
1037
GetLayerGroupNumberByNumber (Cardinal Layer)
858
1038
{
859
 
        int     group,
860
 
                entry;
861
 
 
862
 
        for (group = 0; group < MAX_LAYER; group++)
863
 
                for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
864
 
                        if (PCB->LayerGroups.Entries[group][entry] == Layer)
865
 
                                return(group);
866
 
 
867
 
                /* since every layer belongs to a group it is safe to return
868
 
                 * the value without boundary checking
869
 
                 */
870
 
        return(group);
 
1039
  int group, entry;
 
1040
 
 
1041
  for (group = 0; group < MAX_LAYER; group++)
 
1042
    for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
 
1043
      if (PCB->LayerGroups.Entries[group][entry] == Layer)
 
1044
        return (group);
 
1045
 
 
1046
  /* since every layer belongs to a group it is safe to return
 
1047
   * the value without boundary checking
 
1048
   */
 
1049
  return (group);
871
1050
}
872
1051
 
873
1052
/* ---------------------------------------------------------------------------
874
1053
 * returns a pointer to an objects bounding box;
875
1054
 * data is valid until the routine is called again
876
1055
 */
877
 
BoxTypePtr GetObjectBoundingBox(int Type, void *Ptr1, void *Ptr2, void *Ptr3)
 
1056
BoxTypePtr
 
1057
GetObjectBoundingBox (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
878
1058
{
879
 
        static  BoxType box;
880
 
 
881
 
        switch(Type)
882
 
        {
883
 
                case VIA_TYPE:
884
 
                {
885
 
                        PinTypePtr      via = (PinTypePtr) Ptr1;
886
 
 
887
 
                        box.X1 = via->X -via->Thickness/2;
888
 
                        box.Y1 = via->Y -via->Thickness/2;
889
 
                        box.X2 = via->X +via->Thickness/2;
890
 
                        box.Y2 = via->Y +via->Thickness/2;
891
 
                        break;
892
 
                }
893
 
 
894
 
                case LINE_TYPE:
895
 
                {
896
 
                        LineTypePtr     line = (LineTypePtr) Ptr2;
897
 
 
898
 
                        box.X1 = MIN(line->Point1.X, line->Point2.X);
899
 
                        box.Y1 = MIN(line->Point1.Y, line->Point2.Y);
900
 
                        box.X2 = MAX(line->Point1.X, line->Point2.X);
901
 
                        box.Y2 = MAX(line->Point1.Y, line->Point2.Y);
902
 
                        break;
903
 
                }
904
 
 
905
 
                case ARC_TYPE:
906
 
                        box = ((ArcTypePtr) Ptr2)->BoundingBox; 
907
 
                        break;
908
 
 
909
 
                case TEXT_TYPE:
910
 
                case ELEMENTNAME_TYPE:
911
 
                        box = ((TextTypePtr) Ptr2)->BoundingBox;
912
 
                        break;
913
 
 
914
 
                case POLYGON_TYPE:
915
 
                        box = ((PolygonTypePtr) Ptr2)->BoundingBox;
916
 
                        break;
917
 
 
918
 
                case ELEMENT_TYPE:
919
 
                        box = ((ElementTypePtr) Ptr1)->BoundingBox;
920
 
                        break;
921
 
 
922
 
                case PAD_TYPE:
923
 
                {
924
 
                        PadTypePtr      pad = (PadTypePtr) Ptr2;
925
 
 
926
 
                        box.X1 = MIN(pad->Point1.X, pad->Point2.X);
927
 
                        box.Y1 = MIN(pad->Point1.Y, pad->Point2.Y);
928
 
                        box.X2 = MAX(pad->Point1.X, pad->Point2.X);
929
 
                        box.Y2 = MAX(pad->Point1.Y, pad->Point2.Y);
930
 
                        break;
931
 
                }
932
 
 
933
 
                case PIN_TYPE:
934
 
                {
935
 
                        PinTypePtr      pin = (PinTypePtr) Ptr2;
936
 
 
937
 
                        box.X1 = pin->X -pin->Thickness/2;
938
 
                        box.Y1 = pin->Y -pin->Thickness/2;
939
 
                        box.X2 = pin->X +pin->Thickness/2;
940
 
                        box.Y2 = pin->Y +pin->Thickness/2;
941
 
                        break;
942
 
                }
943
 
 
944
 
                case LINEPOINT_TYPE:
945
 
                {
946
 
                        PointTypePtr    point = (PointTypePtr) Ptr3;
947
 
 
948
 
                        box.X1 = box.X2 = point->X;
949
 
                        box.Y1 = box.Y2 = point->Y;
950
 
                        break;
951
 
                }
952
 
 
953
 
                case POLYGONPOINT_TYPE:
954
 
                {
955
 
                        PointTypePtr    point = (PointTypePtr) Ptr3;
956
 
 
957
 
                        box.X1 = box.X2 = point->X;
958
 
                        box.Y1 = box.Y2 = point->Y;
959
 
                        break;
960
 
                }
961
 
 
962
 
                default:
963
 
                        Message("Request for bounding box of unsupported typ %d\n",Type);
964
 
                        box.X1 = box.X2 = box.Y1 = box.Y2 = 0;
965
 
                        break;
966
 
        }
967
 
        return(&box);
 
1059
  static BoxType box;
 
1060
 
 
1061
  switch (Type)
 
1062
    {
 
1063
    case VIA_TYPE:
 
1064
      {
 
1065
        PinTypePtr via = (PinTypePtr) Ptr1;
 
1066
 
 
1067
        box.X1 = via->X - via->Thickness / 2;
 
1068
        box.Y1 = via->Y - via->Thickness / 2;
 
1069
        box.X2 = via->X + via->Thickness / 2;
 
1070
        box.Y2 = via->Y + via->Thickness / 2;
 
1071
        break;
 
1072
      }
 
1073
 
 
1074
    case LINE_TYPE:
 
1075
      {
 
1076
        LineTypePtr line = (LineTypePtr) Ptr2;
 
1077
 
 
1078
        box.X1 = MIN (line->Point1.X, line->Point2.X);
 
1079
        box.Y1 = MIN (line->Point1.Y, line->Point2.Y);
 
1080
        box.X2 = MAX (line->Point1.X, line->Point2.X);
 
1081
        box.Y2 = MAX (line->Point1.Y, line->Point2.Y);
 
1082
        box.X1 -= line->Thickness / 2;
 
1083
        box.Y1 -= line->Thickness / 2;
 
1084
        box.X2 += line->Thickness / 2;
 
1085
        box.Y2 += line->Thickness / 2;
 
1086
        break;
 
1087
      }
 
1088
 
 
1089
    case ARC_TYPE:
 
1090
      box = ((ArcTypePtr) Ptr2)->BoundingBox;
 
1091
      break;
 
1092
 
 
1093
    case TEXT_TYPE:
 
1094
    case ELEMENTNAME_TYPE:
 
1095
      box = ((TextTypePtr) Ptr2)->BoundingBox;
 
1096
      break;
 
1097
 
 
1098
    case POLYGON_TYPE:
 
1099
      box = ((PolygonTypePtr) Ptr2)->BoundingBox;
 
1100
      break;
 
1101
 
 
1102
    case ELEMENT_TYPE:
 
1103
      box = ((ElementTypePtr) Ptr1)->BoundingBox;
 
1104
      {
 
1105
        TextTypePtr text = &NAMEONPCB_TEXT ((ElementTypePtr) Ptr1);
 
1106
        if (text->BoundingBox.X1 < box.X1)
 
1107
          box.X1 = text->BoundingBox.X1;
 
1108
        if (text->BoundingBox.Y1 < box.Y1)
 
1109
          box.Y1 = text->BoundingBox.Y1;
 
1110
        if (text->BoundingBox.X2 > box.X2)
 
1111
          box.X2 = text->BoundingBox.X2;
 
1112
        if (text->BoundingBox.Y2 > box.Y2)
 
1113
          box.Y2 = text->BoundingBox.Y2;
 
1114
      }
 
1115
      break;
 
1116
 
 
1117
    case PAD_TYPE:
 
1118
      {
 
1119
        PadTypePtr pad = (PadTypePtr) Ptr2;
 
1120
 
 
1121
        box.X1 = MIN (pad->Point1.X, pad->Point2.X);
 
1122
        box.Y1 = MIN (pad->Point1.Y, pad->Point2.Y);
 
1123
        box.X2 = MAX (pad->Point1.X, pad->Point2.X);
 
1124
        box.Y2 = MAX (pad->Point1.Y, pad->Point2.Y);
 
1125
        box.X1 -= pad->Thickness;
 
1126
        box.Y1 -= pad->Thickness;
 
1127
        box.Y2 += pad->Thickness;
 
1128
        box.X2 += pad->Thickness;
 
1129
        break;
 
1130
      }
 
1131
 
 
1132
    case PIN_TYPE:
 
1133
      {
 
1134
        PinTypePtr pin = (PinTypePtr) Ptr2;
 
1135
 
 
1136
        box.X1 = pin->X - pin->Thickness / 2;
 
1137
        box.Y1 = pin->Y - pin->Thickness / 2;
 
1138
        box.X2 = pin->X + pin->Thickness / 2;
 
1139
        box.Y2 = pin->Y + pin->Thickness / 2;
 
1140
        break;
 
1141
      }
 
1142
 
 
1143
    case LINEPOINT_TYPE:
 
1144
      {
 
1145
        PointTypePtr point = (PointTypePtr) Ptr3;
 
1146
 
 
1147
        box.X1 = box.X2 = point->X;
 
1148
        box.Y1 = box.Y2 = point->Y;
 
1149
        break;
 
1150
      }
 
1151
 
 
1152
    case POLYGONPOINT_TYPE:
 
1153
      {
 
1154
        PointTypePtr point = (PointTypePtr) Ptr3;
 
1155
 
 
1156
        box.X1 = box.X2 = point->X;
 
1157
        box.Y1 = box.Y2 = point->Y;
 
1158
        break;
 
1159
      }
 
1160
 
 
1161
    default:
 
1162
      Message ("Request for bounding box of unsupported typ %d\n", Type);
 
1163
      box.X1 = box.X2 = box.Y1 = box.Y2 = 0;
 
1164
      break;
 
1165
    }
 
1166
  return (&box);
968
1167
}
969
1168
 
970
1169
/* ---------------------------------------------------------------------------
971
1170
 * computes the bounding box of an arc
972
1171
 */
973
 
void SetArcBoundingBox(ArcTypePtr Arc)
 
1172
void
 
1173
SetArcBoundingBox (ArcTypePtr Arc)
974
1174
{
975
 
        BoxTypePtr              box;
976
 
        register Position       temp, width;
977
 
 
978
 
        box = GetArcEnds(Arc);
979
 
        temp = box->X1;
980
 
        box->X1 = MIN(box->X1, box->X2);
981
 
        box->X2 = MAX(box->X2, temp);
982
 
        temp = box->Y1;
983
 
        box->Y1 = MIN(box->Y1, box->Y2);
984
 
        box->Y2 = MAX(box->Y2, temp);
985
 
        width = Arc->Thickness/2;
986
 
        box->X1 -= width;
987
 
        box->X2 += width;
988
 
        box->Y1 -= width;
989
 
        box->Y2 += width;
990
 
        Arc->BoundingBox = *box;
 
1175
  register double ca1, ca2, sa1, sa2;
 
1176
  register LocationType ang1, ang2;
 
1177
  register LocationType width;
 
1178
 
 
1179
  /* first put angles into standard form */
 
1180
  if (Arc->Delta > 360)
 
1181
    Arc->Delta = 360;
 
1182
  ang1 = Arc->StartAngle;
 
1183
  ang2 = Arc->StartAngle + Arc->Delta;
 
1184
  if (Arc->Delta < 0)
 
1185
    {
 
1186
      LocationType temp;
 
1187
      temp = ang1;
 
1188
      ang1 = ang2;
 
1189
      ang2 = temp;
 
1190
    }
 
1191
  if (ang1 < 0)
 
1192
    {
 
1193
      ang1 += 360;
 
1194
      ang2 += 360;
 
1195
    }
 
1196
  /* calculate sines, cosines */
 
1197
  switch (ang1)
 
1198
    {
 
1199
    case 0:
 
1200
      ca1 = 1.0;
 
1201
      sa1 = 0;
 
1202
      break;
 
1203
    case 90:
 
1204
      ca1 = 0;
 
1205
      sa1 = 1.0;
 
1206
      break;
 
1207
    case 180:
 
1208
      ca1 = -1.0;
 
1209
      sa1 = 0;
 
1210
      break;
 
1211
    case 270:
 
1212
      ca1 = 0;
 
1213
      sa1 = -1.0;
 
1214
      break;
 
1215
    default:
 
1216
      ca1 = M180 * (double) ang1;
 
1217
      sa1 = sin (ca1);
 
1218
      ca1 = cos (ca1);
 
1219
    }
 
1220
  switch (ang2)
 
1221
    {
 
1222
    case 0:
 
1223
      ca2 = 1.0;
 
1224
      sa2 = 0;
 
1225
      break;
 
1226
    case 90:
 
1227
      ca2 = 0;
 
1228
      sa2 = 1.0;
 
1229
      break;
 
1230
    case 180:
 
1231
      ca2 = -1.0;
 
1232
      sa2 = 0;
 
1233
      break;
 
1234
    case 270:
 
1235
      ca2 = 0;
 
1236
      sa2 = -1.0;
 
1237
      break;
 
1238
    default:
 
1239
      ca2 = M180 * (double) ang2;
 
1240
      sa2 = sin (ca2);
 
1241
      ca2 = cos (ca2);
 
1242
    }
 
1243
 
 
1244
  Arc->BoundingBox.X2 = Arc->X - Arc->Width *
 
1245
    ((ang1 < 180 && ang2 > 180) ? -1 : MIN (ca1, ca2));
 
1246
 
 
1247
  Arc->BoundingBox.X1 = Arc->X - Arc->Width *
 
1248
    ((ang1 < 360 && ang2 > 360) ? 1 : MAX (ca1, ca2));
 
1249
 
 
1250
  Arc->BoundingBox.Y2 = Arc->Y + Arc->Height *
 
1251
    ((ang1 < 90 && ang2 > 90) ? 1 : MAX (sa1, sa2));
 
1252
 
 
1253
  Arc->BoundingBox.Y1 = Arc->Y + Arc->Height *
 
1254
    ((ang1 < 270 && ang2 > 270) ? -1 : MIN (sa1, sa2));
 
1255
 
 
1256
  width = (Arc->Thickness + Arc->Clearance) / 2;
 
1257
  Arc->BoundingBox.X1 -= width;
 
1258
  Arc->BoundingBox.X2 += width;
 
1259
  Arc->BoundingBox.Y1 -= width;
 
1260
  Arc->BoundingBox.Y2 += width;
991
1261
}
992
1262
 
993
1263
/* ---------------------------------------------------------------------------
994
1264
 * resets the layerstack setting
995
1265
 */
996
 
void ResetStackAndVisibility(void)
997
 
{
998
 
        Cardinal        i;
999
 
 
1000
 
        for (i = 0; i < MAX_LAYER + 2; i++)
1001
 
        {
1002
 
                if (i < MAX_LAYER)
1003
 
                        LayerStack[i] = i;
1004
 
                PCB->Data->Layer[i].On = True;
1005
 
        }
1006
 
        PCB->ElementOn = True;
1007
 
        PCB->InvisibleObjectsOn = True;
1008
 
        PCB->PinOn = True;
1009
 
        PCB->ViaOn = True;
1010
 
        PCB->RatOn = True;
 
1266
void
 
1267
ResetStackAndVisibility (void)
 
1268
{
 
1269
  Cardinal i;
 
1270
 
 
1271
  for (i = 0; i < MAX_LAYER + 2; i++)
 
1272
    {
 
1273
      if (i < MAX_LAYER)
 
1274
        LayerStack[i] = i;
 
1275
      PCB->Data->Layer[i].On = True;
 
1276
    }
 
1277
  PCB->ElementOn = True;
 
1278
  PCB->InvisibleObjectsOn = True;
 
1279
  PCB->PinOn = True;
 
1280
  PCB->ViaOn = True;
 
1281
  PCB->RatOn = True;
 
1282
}
 
1283
 
 
1284
/* ---------------------------------------------------------------------------
 
1285
 * saves the layerstack setting
 
1286
 */
 
1287
void
 
1288
SaveStackAndVisibility (void)
 
1289
{
 
1290
  Cardinal i;
 
1291
  static Boolean run = False;
 
1292
 
 
1293
  if (run == False)
 
1294
    {
 
1295
      SavedStack.cnt = 0;
 
1296
      run = True;
 
1297
    }
 
1298
 
 
1299
  if (SavedStack.cnt != 0)
 
1300
    {
 
1301
      fprintf (stderr,
 
1302
               "SaveStackAndVisibility()  layerstack was already saved and not"
 
1303
               "yet restored.  cnt = %d\n", SavedStack.cnt);
 
1304
    }
 
1305
 
 
1306
  for (i = 0; i < MAX_LAYER + 2; i++)
 
1307
    {
 
1308
      if (i < MAX_LAYER)
 
1309
        SavedStack.LayerStack[i] = LayerStack[i];
 
1310
      SavedStack.LayerOn[i] = PCB->Data->Layer[i].On;
 
1311
    }
 
1312
  SavedStack.ElementOn = PCB->ElementOn;
 
1313
  SavedStack.InvisibleObjectsOn = PCB->InvisibleObjectsOn;
 
1314
  SavedStack.PinOn = PCB->PinOn;
 
1315
  SavedStack.ViaOn = PCB->ViaOn;
 
1316
  SavedStack.RatOn = PCB->RatOn;
 
1317
  SavedStack.cnt++;
 
1318
}
 
1319
 
 
1320
/* ---------------------------------------------------------------------------
 
1321
 * restores the layerstack setting
 
1322
 */
 
1323
void
 
1324
RestoreStackAndVisibility (void)
 
1325
{
 
1326
  Cardinal i;
 
1327
 
 
1328
  if (SavedStack.cnt == 0)
 
1329
    {
 
1330
      fprintf (stderr, "RestoreStackAndVisibility()  layerstack has not"
 
1331
               " been saved.  cnt = %d\n", SavedStack.cnt);
 
1332
      return;
 
1333
    }
 
1334
  else if (SavedStack.cnt != 1)
 
1335
    {
 
1336
      fprintf (stderr, "RestoreStackAndVisibility()  layerstack save count is"
 
1337
               " wrong.  cnt = %d\n", SavedStack.cnt);
 
1338
    }
 
1339
 
 
1340
  for (i = 0; i < MAX_LAYER + 2; i++)
 
1341
    {
 
1342
      if (i < MAX_LAYER)
 
1343
        LayerStack[i] = SavedStack.LayerStack[i];
 
1344
      PCB->Data->Layer[i].On = SavedStack.LayerOn[i];
 
1345
    }
 
1346
  PCB->ElementOn = SavedStack.ElementOn;
 
1347
  PCB->InvisibleObjectsOn = SavedStack.InvisibleObjectsOn;
 
1348
  PCB->PinOn = SavedStack.PinOn;
 
1349
  PCB->ViaOn = SavedStack.ViaOn;
 
1350
  PCB->RatOn = SavedStack.RatOn;
 
1351
 
 
1352
  SavedStack.cnt--;
1011
1353
}
1012
1354
 
1013
1355
/* ----------------------------------------------------------------------
1014
 
 * returns pointer to current working directory
 
1356
 * returns pointer to current working directory.  If 'path' is not
 
1357
 * NULL, then the current working directory is copied to the array
 
1358
 * pointed to by 'path'
1015
1359
 */
1016
 
char *GetWorkingDirectory(void)
 
1360
char *
 
1361
GetWorkingDirectory (char *path)
1017
1362
{
1018
 
        static  char    path[MAXPATHLEN+1];
1019
 
 
1020
 
#if defined(SYSV) || defined(linux) 
1021
 
        return(getcwd(path, MAXPATHLEN));
 
1363
#if defined(SYSV) || defined(linux) || defined(__NetBSD__)
 
1364
  return getcwd (path, MAXPATHLEN);
1022
1365
#else
1023
 
                /* seems that some BSD releases lack of a prototype for getwd() */
1024
 
        return((char *) getwd(path));
 
1366
  /* seems that some BSD releases lack of a prototype for getwd() */
 
1367
  return getwd (path);
1025
1368
#endif
 
1369
 
1026
1370
}
1027
1371
 
1028
1372
/* ---------------------------------------------------------------------------
1029
1373
 * writes a string to the passed file pointer
1030
1374
 * some special characters are quoted
1031
1375
 */
1032
 
void CreateQuotedString(DynamicStringTypePtr DS, char *S)
 
1376
void
 
1377
CreateQuotedString (DynamicStringTypePtr DS, char *S)
1033
1378
{
1034
 
        DSClearString(DS);
1035
 
        DSAddCharacter(DS, '"');
1036
 
        while (*S)
1037
 
        {
1038
 
                if (*S == '"' || *S == '\\')
1039
 
                        DSAddCharacter(DS, '\\');
1040
 
                DSAddCharacter(DS, *S++);
1041
 
        }
1042
 
        DSAddCharacter(DS, '"');
 
1379
  DSClearString (DS);
 
1380
  DSAddCharacter (DS, '"');
 
1381
  while (*S)
 
1382
    {
 
1383
      if (*S == '"' || *S == '\\')
 
1384
        DSAddCharacter (DS, '\\');
 
1385
      DSAddCharacter (DS, *S++);
 
1386
    }
 
1387
  DSAddCharacter (DS, '"');
1043
1388
}
1044
1389
 
1045
1390
/* ---------------------------------------------------------------------------
1046
1391
 * returns the current possible grid factor or zero
1047
1392
 */
1048
 
int GetGridFactor(void)
 
1393
int
 
1394
GetGridFactor (void)
1049
1395
{
1050
 
        static  int     factor[] = { 1, 2, 5, 10 };
1051
 
                int     i,
1052
 
                        delta;
 
1396
  static int factor[] = { 1, 2, 5, 10 };
 
1397
  int i, delta;
1053
1398
 
1054
 
                /* check to see if we have to draw every point,
1055
 
                 * every 2nd, 5th or 10th
1056
 
                 */
1057
 
        for (i = 0; i < ENTRIES(factor); i++)
 
1399
  /* check to see if we have to draw every point,
 
1400
   * every 2nd, 5th or 10th
 
1401
   */
 
1402
  for (i = 0; i < ENTRIES (factor); i++)
 
1403
    {
 
1404
      delta = PCB->Grid * factor[i];
 
1405
      if (TO_SCREEN (delta) >= MIN_GRID_DISTANCE)
1058
1406
        {
1059
 
                delta = PCB->Grid *factor[i];
1060
 
                if (TO_SCREEN(delta) >= MIN_GRID_DISTANCE)
1061
 
                {
1062
 
                        if (Settings.GridFactor != factor[i])
1063
 
                        {
1064
 
                                Settings.GridFactor = factor[i];
1065
 
                                SetStatusLine();
1066
 
                        }
1067
 
                        return(factor[i]);
1068
 
                }
 
1407
          if (Settings.GridFactor != factor[i])
 
1408
            {
 
1409
              Settings.GridFactor = factor[i];
 
1410
              SetStatusLine ();
 
1411
            }
 
1412
          return (factor[i]);
1069
1413
        }
1070
 
        Settings.GridFactor = 0;
1071
 
        SetStatusLine();
1072
 
        return(0);
1073
 
}
1074
 
 
1075
 
static  void RightAngles(int Angle, float *cosa, float *sina)
1076
 
{
1077
 
        *cosa = (float) cos((double) Angle * M180);
1078
 
        *sina = (float) sin((double) Angle * M180);
1079
 
}
1080
 
 
1081
 
BoxTypePtr GetArcEnds(ArcTypePtr Arc)
1082
 
{
1083
 
        static  BoxType box;
1084
 
        float   ca, sa;
1085
 
 
1086
 
        RightAngles(Arc->StartAngle, &ca, &sa);
1087
 
        box.X1 = Arc->X - Arc->Width * ca;
1088
 
        box.Y1 = Arc->Y + Arc->Width * sa;
1089
 
        RightAngles(Arc->StartAngle + Arc->Delta, &ca, &sa);
1090
 
        box.X2 = Arc->X - Arc->Width * ca;
1091
 
        box.Y2 = Arc->Y + Arc->Width * sa;
1092
 
        return(&box);
1093
 
}
1094
 
 
1095
 
static char *BumpName(char *Name)
1096
 
{
1097
 
        int     num;
1098
 
        char    c, *start;
1099
 
        static  char temp[256];
1100
 
 
1101
 
        start = Name;
1102
 
                /* seek end of string */
1103
 
        while (*Name != 0)
1104
 
                Name++;
1105
 
                /* back up to potential number */
1106
 
        for (Name--; isdigit(*Name); Name--);
1107
 
        Name++;
1108
 
        if (*Name)
1109
 
                num = atoi(Name) + 1;
1110
 
        else
1111
 
                num = 1;
1112
 
        c = *Name;
1113
 
        *Name = 0;
1114
 
        sprintf(temp, "%s%d", start, num);
1115
 
                /* if this is not our string, put back the blown character */
1116
 
        if (start != temp)
1117
 
                *Name = c;
1118
 
        return(temp);
 
1414
    }
 
1415
  Settings.GridFactor = 0;
 
1416
  SetStatusLine ();
 
1417
  return (0);
 
1418
}
 
1419
 
 
1420
static void
 
1421
RightAngles (int Angle, float *cosa, float *sina)
 
1422
{
 
1423
  *cosa = (float) cos ((double) Angle * M180);
 
1424
  *sina = (float) sin ((double) Angle * M180);
 
1425
}
 
1426
 
 
1427
BoxTypePtr
 
1428
GetArcEnds (ArcTypePtr Arc)
 
1429
{
 
1430
  static BoxType box;
 
1431
  float ca, sa;
 
1432
 
 
1433
  RightAngles (Arc->StartAngle, &ca, &sa);
 
1434
  box.X1 = Arc->X - Arc->Width * ca;
 
1435
  box.Y1 = Arc->Y + Arc->Height * sa;
 
1436
  RightAngles (Arc->StartAngle + Arc->Delta, &ca, &sa);
 
1437
  box.X2 = Arc->X - Arc->Width * ca;
 
1438
  box.Y2 = Arc->Y + Arc->Height * sa;
 
1439
  return (&box);
 
1440
}
 
1441
 
 
1442
static char *
 
1443
BumpName (char *Name)
 
1444
{
 
1445
  int num;
 
1446
  char c, *start;
 
1447
  static char temp[256];
 
1448
 
 
1449
  start = Name;
 
1450
  /* seek end of string */
 
1451
  while (*Name != 0)
 
1452
    Name++;
 
1453
  /* back up to potential number */
 
1454
  for (Name--; isdigit (*Name); Name--);
 
1455
  Name++;
 
1456
  if (*Name)
 
1457
    num = atoi (Name) + 1;
 
1458
  else
 
1459
    num = 1;
 
1460
  c = *Name;
 
1461
  *Name = 0;
 
1462
  sprintf (temp, "%s%d", start, num);
 
1463
  /* if this is not our string, put back the blown character */
 
1464
  if (start != temp)
 
1465
    *Name = c;
 
1466
  return (temp);
1119
1467
}
1120
1468
 
1121
1469
/*
1122
1470
 * make a unique name for the name on board 
1123
1471
 * this can alter the contents of the input string
1124
1472
 */
1125
 
char    *UniqueElementName(DataTypePtr Data, char *Name)
1126
 
{
1127
 
        Boolean unique = True;
1128
 
                /* null strings are ok */
1129
 
        if (!Name || !*Name)
1130
 
                return (Name);
1131
 
 
1132
 
        for ( ; ; )
1133
 
        {
1134
 
                ELEMENT_LOOP(Data,
1135
 
                        if (NAMEONPCB_NAME(element) && 
1136
 
                                strcmp(NAMEONPCB_NAME(element), Name) == 0)
1137
 
                        {
1138
 
                                Name = BumpName(Name);
1139
 
                                unique = False;
1140
 
                                break;
1141
 
                        }
1142
 
                );
1143
 
                if (unique)
1144
 
                        return(Name);
1145
 
                unique = True;
1146
 
        }
1147
 
}
1148
 
 
1149
 
static void GetGridLockCoordinates(int type, void *ptr1,
1150
 
                 void *ptr2, void *ptr3, Position *x, Position *y)
1151
 
{
1152
 
        switch (type)
1153
 
        {
1154
 
                case VIA_TYPE:
1155
 
                                *x = ((PinTypePtr) ptr2)->X;
1156
 
                                *y = ((PinTypePtr) ptr2)->Y;
1157
 
                                break;
1158
 
                case LINE_TYPE:
1159
 
                                *x = ((LineTypePtr) ptr2)->Point1.X;
1160
 
                                *y = ((LineTypePtr) ptr2)->Point1.Y;
1161
 
                                break;
1162
 
                case TEXT_TYPE:
1163
 
                case ELEMENTNAME_TYPE:
1164
 
                                *x = ((TextTypePtr) ptr2)->X;
1165
 
                                *y = ((TextTypePtr) ptr2)->Y;
1166
 
                                break;
1167
 
                case ELEMENT_TYPE:
1168
 
                                *x = ((ElementTypePtr) ptr2)->MarkX;
1169
 
                                *y = ((ElementTypePtr) ptr2)->MarkY;
1170
 
                                break;
1171
 
                case POLYGON_TYPE:
1172
 
                                *x = ((PolygonTypePtr) ptr2)->Points[0].X;
1173
 
                                *y = ((PolygonTypePtr) ptr2)->Points[0].Y;
1174
 
                                break;
1175
 
                                
1176
 
                case LINEPOINT_TYPE:
1177
 
                case POLYGONPOINT_TYPE:
1178
 
                                *x = ((PointTypePtr) ptr3)->X;
1179
 
                                *y = ((PointTypePtr) ptr3)->Y;
1180
 
                                break;
1181
 
                case ARC_TYPE:
1182
 
                        {
1183
 
                                BoxTypePtr      box;
1184
 
 
1185
 
                                box = GetArcEnds((ArcTypePtr) ptr2);
1186
 
                                *x = box->X1;
1187
 
                                *y = box->Y1;
1188
 
                                break;
1189
 
                        }
1190
 
        }
1191
 
}
1192
 
 
1193
 
void    AttachForCopy(Position PlaceX, Position PlaceY)
1194
 
{
1195
 
        BoxTypePtr      box;
1196
 
        Position        mx, my;
1197
 
 
1198
 
        Crosshair.AttachedObject.RubberbandN = 0;
1199
 
                /* dither the grab point so that the mark, center, etc
1200
 
                 * will end up on a grid coordinate
1201
 
                 */
1202
 
        GetGridLockCoordinates(Crosshair.AttachedObject.Type,
1203
 
                Crosshair.AttachedObject.Ptr1,
1204
 
                Crosshair.AttachedObject.Ptr2,
1205
 
                Crosshair.AttachedObject.Ptr3,
1206
 
                &mx, &my);
1207
 
        mx = GRIDFIT_X(mx, PCB->Grid) - mx;
1208
 
        my = GRIDFIT_Y(my, PCB->Grid) - my;
1209
 
        if (2 * abs(mx) > PCB->Grid)
1210
 
                mx = (mx < 0) ? mx + PCB->Grid : mx - PCB->Grid;
1211
 
        if (2 * abs(my) > PCB->Grid)
1212
 
                my = (my < 0) ? my + PCB->Grid : my - PCB->Grid;
1213
 
        Crosshair.AttachedObject.X = PlaceX - mx;
1214
 
        Crosshair.AttachedObject.Y = PlaceY - my;
1215
 
        Crosshair.AttachedObject.State = STATE_SECOND;
1216
 
 
1217
 
                /* get boundingbox of object and set cursor range */
1218
 
        box= GetObjectBoundingBox(Crosshair.AttachedObject.Type,
1219
 
                Crosshair.AttachedObject.Ptr1,
1220
 
                Crosshair.AttachedObject.Ptr2,
1221
 
                Crosshair.AttachedObject.Ptr3);
1222
 
        SetCrosshairRange(Crosshair.X -box->X1,
1223
 
                Crosshair.Y -box->Y1,
1224
 
                PCB->MaxWidth -(box->X2 -Crosshair.X),
1225
 
                PCB->MaxHeight -(box->Y2 -Crosshair.Y));
1226
 
 
1227
 
                /* get all attached objects if necessary */
1228
 
        if ((Settings.Mode != COPY_MODE) && TEST_FLAG(RUBBERBANDFLAG, PCB))
1229
 
                LookupRubberbandLines(Crosshair.AttachedObject.Type,
1230
 
                        Crosshair.AttachedObject.Ptr1,
1231
 
                        Crosshair.AttachedObject.Ptr2,
1232
 
                        Crosshair.AttachedObject.Ptr3);
1233
 
        if (Settings.Mode != COPY_MODE &&
1234
 
                (Crosshair.AttachedObject.Type == ELEMENT_TYPE ||
1235
 
                Crosshair.AttachedObject.Type == VIA_TYPE ||
1236
 
                Crosshair.AttachedObject.Type == LINE_TYPE ||
1237
 
                Crosshair.AttachedObject.Type == LINEPOINT_TYPE))
1238
 
                        LookupRatLines(Crosshair.AttachedObject.Type,
1239
 
                                Crosshair.AttachedObject.Ptr1,
1240
 
                                Crosshair.AttachedObject.Ptr2,
1241
 
                                Crosshair.AttachedObject.Ptr3);
1242
 
}
1243
 
 
1244
 
Boolean ShiftPressed(void)
1245
 
{
1246
 
       char    keys[32];
1247
 
 
1248
 
       XQueryKeymap(Dpy, keys);
1249
 
       if (keys[ShiftKeyIndex] & ShiftKeyMask)
1250
 
               return(True);
1251
 
       else
1252
 
               return(False);
1253
 
}
1254
 
 
 
1473
char *
 
1474
UniqueElementName (DataTypePtr Data, char *Name)
 
1475
{
 
1476
  Boolean unique = True;
 
1477
  /* null strings are ok */
 
1478
  if (!Name || !*Name)
 
1479
    return (Name);
 
1480
 
 
1481
  for (;;)
 
1482
    {
 
1483
      ELEMENT_LOOP (Data);
 
1484
      {
 
1485
        if (NAMEONPCB_NAME (element) &&
 
1486
            NSTRCMP (NAMEONPCB_NAME (element), Name) == 0)
 
1487
          {
 
1488
            Name = BumpName (Name);
 
1489
            unique = False;
 
1490
            break;
 
1491
          }
 
1492
      }
 
1493
      END_LOOP;
 
1494
      if (unique)
 
1495
        return (Name);
 
1496
      unique = True;
 
1497
    }
 
1498
}
 
1499
 
 
1500
static void
 
1501
GetGridLockCoordinates (int type, void *ptr1,
 
1502
                        void *ptr2, void *ptr3, LocationType * x, LocationType * y)
 
1503
{
 
1504
  switch (type)
 
1505
    {
 
1506
    case VIA_TYPE:
 
1507
      *x = ((PinTypePtr) ptr2)->X;
 
1508
      *y = ((PinTypePtr) ptr2)->Y;
 
1509
      break;
 
1510
    case LINE_TYPE:
 
1511
      *x = ((LineTypePtr) ptr2)->Point1.X;
 
1512
      *y = ((LineTypePtr) ptr2)->Point1.Y;
 
1513
      break;
 
1514
    case TEXT_TYPE:
 
1515
    case ELEMENTNAME_TYPE:
 
1516
      *x = ((TextTypePtr) ptr2)->X;
 
1517
      *y = ((TextTypePtr) ptr2)->Y;
 
1518
      break;
 
1519
    case ELEMENT_TYPE:
 
1520
      *x = ((ElementTypePtr) ptr2)->MarkX;
 
1521
      *y = ((ElementTypePtr) ptr2)->MarkY;
 
1522
      break;
 
1523
    case POLYGON_TYPE:
 
1524
      *x = ((PolygonTypePtr) ptr2)->Points[0].X;
 
1525
      *y = ((PolygonTypePtr) ptr2)->Points[0].Y;
 
1526
      break;
 
1527
 
 
1528
    case LINEPOINT_TYPE:
 
1529
    case POLYGONPOINT_TYPE:
 
1530
      *x = ((PointTypePtr) ptr3)->X;
 
1531
      *y = ((PointTypePtr) ptr3)->Y;
 
1532
      break;
 
1533
    case ARC_TYPE:
 
1534
      {
 
1535
        BoxTypePtr box;
 
1536
 
 
1537
        box = GetArcEnds ((ArcTypePtr) ptr2);
 
1538
        *x = box->X1;
 
1539
        *y = box->Y1;
 
1540
        break;
 
1541
      }
 
1542
    }
 
1543
}
 
1544
 
 
1545
void
 
1546
AttachForCopy (LocationType PlaceX, LocationType PlaceY)
 
1547
{
 
1548
  BoxTypePtr box;
 
1549
  LocationType mx, my;
 
1550
 
 
1551
  Crosshair.AttachedObject.RubberbandN = 0;
 
1552
  if (TEST_FLAG (SNAPPINFLAG, PCB))
 
1553
    {
 
1554
      mx = 0;
 
1555
      my = 0;
 
1556
    }
 
1557
  else
 
1558
    {
 
1559
      /* dither the grab point so that the mark, center, etc
 
1560
       * will end up on a grid coordinate
 
1561
       */
 
1562
      GetGridLockCoordinates (Crosshair.AttachedObject.Type,
 
1563
                              Crosshair.AttachedObject.Ptr1,
 
1564
                              Crosshair.AttachedObject.Ptr2,
 
1565
                              Crosshair.AttachedObject.Ptr3, &mx, &my);
 
1566
      mx = GRIDFIT_X (mx, PCB->Grid) - mx;
 
1567
      my = GRIDFIT_Y (my, PCB->Grid) - my;
 
1568
    }
 
1569
  Crosshair.AttachedObject.X = PlaceX - mx;
 
1570
  Crosshair.AttachedObject.Y = PlaceY - my;
 
1571
  if (!Marked.status || TEST_FLAG (LOCALREFFLAG, PCB))
 
1572
    SetLocalRef (PlaceX - mx, PlaceY - my, True);
 
1573
  Crosshair.AttachedObject.State = STATE_SECOND;
 
1574
 
 
1575
  /* get boundingbox of object and set cursor range */
 
1576
  box = GetObjectBoundingBox (Crosshair.AttachedObject.Type,
 
1577
                              Crosshair.AttachedObject.Ptr1,
 
1578
                              Crosshair.AttachedObject.Ptr2,
 
1579
                              Crosshair.AttachedObject.Ptr3);
 
1580
  SetCrosshairRange (Crosshair.AttachedObject.X - box->X1,
 
1581
                     Crosshair.AttachedObject.Y - box->Y1,
 
1582
                     PCB->MaxWidth - (box->X2 - Crosshair.AttachedObject.X),
 
1583
                     PCB->MaxHeight - (box->Y2 - Crosshair.AttachedObject.Y));
 
1584
 
 
1585
  /* get all attached objects if necessary */
 
1586
  if ((Settings.Mode != COPY_MODE) && TEST_FLAG (RUBBERBANDFLAG, PCB))
 
1587
    LookupRubberbandLines (Crosshair.AttachedObject.Type,
 
1588
                           Crosshair.AttachedObject.Ptr1,
 
1589
                           Crosshair.AttachedObject.Ptr2,
 
1590
                           Crosshair.AttachedObject.Ptr3);
 
1591
  if (Settings.Mode != COPY_MODE &&
 
1592
      (Crosshair.AttachedObject.Type == ELEMENT_TYPE ||
 
1593
       Crosshair.AttachedObject.Type == VIA_TYPE ||
 
1594
       Crosshair.AttachedObject.Type == LINE_TYPE ||
 
1595
       Crosshair.AttachedObject.Type == LINEPOINT_TYPE))
 
1596
    LookupRatLines (Crosshair.AttachedObject.Type,
 
1597
                    Crosshair.AttachedObject.Ptr1,
 
1598
                    Crosshair.AttachedObject.Ptr2,
 
1599
                    Crosshair.AttachedObject.Ptr3);
 
1600
}
 
1601
 
 
1602
/*
 
1603
 * Return nonzero if the given file exists and is readable.
 
1604
 */
 
1605
int
 
1606
FileExists (const char *name)
 
1607
{
 
1608
  FILE *f;
 
1609
  f = fopen (name, "r");
 
1610
  if (f)
 
1611
    {
 
1612
      fclose (f);
 
1613
      return 1;
 
1614
    }
 
1615
  return 0;
 
1616
}
 
1617
 
 
1618
char *
 
1619
Concat (const char *first, ...)
 
1620
{
 
1621
  char *rv;
 
1622
  int len;
 
1623
  va_list a;
 
1624
 
 
1625
  len = strlen (first);
 
1626
  rv = (char *) malloc (len + 1);
 
1627
  strcpy (rv, first);
 
1628
 
 
1629
  va_start (a, first);
 
1630
  while (1)
 
1631
    {
 
1632
      const char *s = va_arg (a, const char *);
 
1633
      if (!s)
 
1634
        break;
 
1635
      len += strlen (s);
 
1636
      rv = (char *) realloc (rv, len + 1);
 
1637
      strcat (rv, s);
 
1638
    }
 
1639
  va_end (a);
 
1640
  return rv;
 
1641
}