38
46
#include <sys/stat.h>
39
47
#include <sys/types.h>
41
50
#include <unistd.h>
43
53
#include "global.h"
55
#include "crosshair.h"
45
56
#include "create.h"
46
#include "crosshair.h"
48
58
#include "dialog.h"
55
66
#include "output.h"
56
67
#include "remove.h"
57
69
#include "rotate.h"
58
70
#include "rubberband.h"
59
71
#include "search.h"
62
#include <X11/cursorfont.h>
63
#include <X11/Shell.h>
64
#include <X11/Xaw/Scrollbar.h>
65
#include <X11/Xaw/Simple.h>
75
#ifdef HAVE_LIBDMALLOC
79
RCSID ("$Id: misc.c,v 1.33 2005/01/03 12:56:59 danmc Exp $");
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 *,
94
* Used by SaveStackAndVisibility() and
95
* RestoreStackAndVisibility()
100
Boolean ElementOn, InvisibleObjectsOn, PinOn, ViaOn, RatOn;
101
int LayerStack[MAX_LAYER];
102
Boolean LayerOn[MAX_LAYER];
72
106
/* ---------------------------------------------------------------------------
73
107
* prints copyright information
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",
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",
96
132
/* ---------------------------------------------------------------------------
97
133
* prints usage message
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",
139
* since we're going to exit, we want to make sure this message goes
140
* to the original 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",
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
208
GetValue (String * Params, Boolean * absolute, Cardinal Num)
211
/* if the first character is a sign we have to add the
212
* value to the current one
217
value = atof (*Params + 1);
221
if (isdigit (**Params))
225
value = atof (*Params);
229
if (strncasecmp (*(Params + 1), "mm", 2) == 0)
231
else if (strncasecmp (*(Params + 1), "mil", 3) == 0)
237
/* ---------------------------------------------------------------------------
238
* sets the bounding box of a point (which is silly)
241
SetPointBoundingBox (PointTypePtr Pnt)
247
/* ---------------------------------------------------------------------------
248
* sets the bounding box of a pin or via
251
SetPinBoundingBox (PinTypePtr Pin)
255
/* the bounding box covers the extent of influence
256
* so it must include the clearance values too
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;
266
/* ---------------------------------------------------------------------------
267
* sets the bounding box of a pad
270
SetPadBoundingBox (PadTypePtr Pad)
274
/* the bounding box covers the extent of influence
275
* so it must include the clearance values too
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;
285
/* ---------------------------------------------------------------------------
286
* sets the bounding box of a line
289
SetLineBoundingBox (LineTypePtr Line)
293
width = (Line->Thickness + Line->Clearance + 1) / 2;
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);
154
303
/* ---------------------------------------------------------------------------
155
304
* sets the bounding box of a polygons
157
void SetPolygonBoundingBox(PolygonTypePtr Polygon)
307
SetPolygonBoundingBox (PolygonTypePtr Polygon)
162
minx = miny = MAX_COORD;
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);
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);
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);
176
321
/* ---------------------------------------------------------------------------
177
322
* sets the bounding box of an elements
179
void SetElementBoundingBox(ElementTypePtr Element, FontTypePtr Font)
325
SetElementBoundingBox (DataTypePtr Data, ElementTypePtr Element,
189
/* first update the text objects */
190
ELEMENTTEXT_LOOP(Element, SetTextBoundingBox(Font, text));
192
/* do not include the elementnames bounding box which
193
* is handles seperatly
195
minx = miny = MAX_COORD;
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);
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);
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);
224
/* arc->StartAngle is in [0,360], arc->Delta in [0,360] */
225
angle1 = arc->StartAngle;
226
angle2 = arc->StartAngle +arc->Delta;
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));
234
/* loop and check all angles n*180
235
* with angle1 <= a <= angle2
237
for (angle = (angle1 /180 +1)*180; angle < angle2; angle += 180)
239
fminx = MIN(-cos(M180 *(float) angle), fminx);
240
fmaxx = MAX(-cos(M180 *(float) angle), fmaxx);
243
/* loop and check all angles n*180+90
244
* with angle1 <= a <= angle2
246
for (angle = ((angle1+90)/180)*180+90; angle < angle2; angle += 180)
248
fminy = MIN(sin(M180 *(float) angle), fminy);
249
fmaxy = MAX(sin(M180 *(float) angle), fmaxy);
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);
257
Element->BoundingBox.X1 = minx;
258
Element->BoundingBox.Y1 = miny;
259
Element->BoundingBox.X2 = maxx;
260
Element->BoundingBox.Y2 = maxy;
328
BoxTypePtr box, vbox;
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);
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);
341
r_insert_entry (Data->name_tree[n], (BoxType *) text, 0);
345
/* do not include the elementnames bounding box which
346
* is handles seperatly
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);
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);
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);
377
if (Data && Data->pin_tree)
378
r_delete_entry (Data->pin_tree, (BoxType *) pin);
379
SetPinBoundingBox (pin);
383
Data->pin_tree = r_create_tree (NULL, 0, 0);
384
r_insert_entry (Data->pin_tree, (BoxType *) pin, 0);
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);
398
if (Data && Data->pad_tree)
399
r_delete_entry (Data->pad_tree, (BoxType *) pad);
400
SetPadBoundingBox (pad);
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);
411
MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2);
413
MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness / 2);
415
MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness / 2);
417
MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2);
421
/* now we set the EDGE2FLAG of the pad if Point2
422
* is closer to the outside edge than Point1
426
if (pad->Point1.Y == pad->Point2.Y)
429
if (box->X2 - pad->Point2.X < pad->Point1.X - box->X1)
430
SET_FLAG (EDGE2FLAG, pad);
432
CLEAR_FLAG (EDGE2FLAG, pad);
437
if (box->Y2 - pad->Point2.Y < pad->Point1.Y - box->Y1)
438
SET_FLAG (EDGE2FLAG, pad);
440
CLEAR_FLAG (EDGE2FLAG, pad);
445
/* mark pins with component orientation */
446
if ((box->X2 - box->X1) > (box->Y2 - box->Y1))
450
SET_FLAG (EDGE2FLAG, pin);
458
CLEAR_FLAG (EDGE2FLAG, pin);
462
if (Data && !Data->element_tree)
463
Data->element_tree = r_create_tree (NULL, 0, 0);
465
r_insert_entry (Data->element_tree, box, 0);
263
468
/* ---------------------------------------------------------------------------
264
469
* creates the bounding box of a text object
266
void SetTextBoundingBox(FontTypePtr FontPtr, TextTypePtr Text)
472
SetTextBoundingBox (FontTypePtr FontPtr, TextTypePtr Text)
268
SymbolTypePtr symbol = FontPtr->Symbol;
269
unsigned char *s = (unsigned char *) Text->TextString;
273
/* calculate size of the bounding box */
275
if (*s <= MAX_FONTPOSITION && symbol[*s].Valid)
277
width += symbol[*s].Width +symbol[*s].Delta;
278
height = MAX(height, (Position) symbol[*s].Height);
282
width += ((FontPtr->DefaultSymbol.X2 -FontPtr->DefaultSymbol.X1) *6/5);
283
height = (FontPtr->DefaultSymbol.Y2 -FontPtr->DefaultSymbol.Y1);
286
/* scale values and rotate them */
287
width = width *Text->Scale /100;
288
height = height *Text->Scale /100;
290
/* set upper-left and lower-right corner;
291
* swap coordinates if necessary (origin is already in 'swapped')
294
Text->BoundingBox.X1 = Text->X;
295
Text->BoundingBox.Y1 = Text->Y;
296
if (TEST_FLAG(ONSOLDERFLAG, Text))
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);
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);
474
SymbolTypePtr symbol = FontPtr->Symbol;
475
unsigned char *s = (unsigned char *) Text->TextString;
476
LocationType width = 0, height = 0;
477
BDimension maxThick = 0;
480
/* calculate size of the bounding box */
482
if (*s <= MAX_FONTPOSITION && symbol[*s].Valid)
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);
494
((FontPtr->DefaultSymbol.X2 - FontPtr->DefaultSymbol.X1) * 6 / 5);
495
height = (FontPtr->DefaultSymbol.Y2 - FontPtr->DefaultSymbol.Y1);
499
width *= Text->Scale / 100.;
500
height *= Text->Scale / 100.;
501
maxThick *= Text->Scale / 200.;
505
/* set upper-left and lower-right corner;
506
* swap coordinates if necessary (origin is already in 'swapped')
509
Text->BoundingBox.X1 = Text->X;
510
Text->BoundingBox.Y1 = Text->Y;
511
if (TEST_FLAG (ONSOLDERFLAG, Text))
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);
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);
312
533
/* ---------------------------------------------------------------------------
313
534
* returns True if data area is empty
315
Boolean IsDataEmpty(DataTypePtr Data)
317
Boolean hasNoObjects;
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);
537
IsDataEmpty (DataTypePtr Data)
539
Boolean hasNoObjects;
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);
553
FlagIsDataEmpty (int parm)
555
int i = IsDataEmpty (PCB->Data);
556
return parm ? !i : i;
559
/* FLAG(DataEmpty,FlagIsDataEmpty,0) */
560
/* FLAG(DataNonEmpty,FlagIsDataEmpty,1) */
331
562
/* ---------------------------------------------------------------------------
332
563
* gets minimum and maximum coordinates
333
564
* returns NULL if layout is empty
335
BoxTypePtr GetDataBoundingBox(DataTypePtr Data)
567
GetDataBoundingBox (DataTypePtr Data)
339
/* preset identifiers with highest and lowest possible values */
340
box.X1 = box.Y1 = MAX_COORD;
343
/* now scan for the lowest/highest X and Y coodinate */
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);
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);
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);
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);
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);
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);
390
return(IsDataEmpty(Data) ? NULL : &box);
571
/* preset identifiers with highest and lowest possible values */
572
box.X1 = box.Y1 = MAX_COORD;
573
box.X2 = box.Y2 = -MAX_COORD;
575
/* now scan for the lowest/highest X and Y coodinate */
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);
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);
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);
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);
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);
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);
627
ALLPOLYGON_LOOP (Data);
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);
635
return (IsDataEmpty (Data) ? NULL : &box);
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
398
void CenterDisplay(Position X, Position Y, Boolean Delta)
645
CenterDisplay (LocationType X, LocationType Y, Boolean Delta)
401
Message("CenterDisplay(%d, %d, %s)\n", X, Y, Delta ? "True" : "False" );
650
Message ("CenterDisplay(%d, %d, %s)\n", X, Y, Delta ? "True" : "False");
405
/* move origin half a screen width/height to get display centered */
410
Y -= Output.Height/2;
411
Pan(X, Y, True, True);
654
x = X - TO_PCB (Output.Width / 2);
656
y = PCB->MaxHeight - Y - TO_PCB (Output.Height / 2);
658
y = Y - TO_PCB (Output.Height / 2);
662
x = Xorig + TO_PCB (X);
663
y = Yorig + TO_PCB (Y);
665
Pan (x, y, True, True);
414
668
/* ---------------------------------------------------------------------------
416
670
* is at the zero position. The y coordinates are moved so that min(y) = 0
419
void SetFontInfo(FontTypePtr Ptr)
674
SetFontInfo (FontTypePtr Ptr)
422
SymbolTypePtr symbol;
424
Position totalminy = MAX_COORD;
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
430
Ptr->MaxWidth = DEFAULT_CELLSIZE;
431
Ptr->MaxHeight = DEFAULT_CELLSIZE;
432
for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
677
SymbolTypePtr symbol;
679
LocationType totalminy = MAX_COORD;
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
685
Ptr->MaxWidth = DEFAULT_CELLSIZE;
686
Ptr->MaxHeight = DEFAULT_CELLSIZE;
687
for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
689
LocationType minx, miny, maxx, maxy;
691
/* next one if the index isn't used or symbol is empty (SPACE) */
692
if (!symbol->Valid || !symbol->LineN)
695
minx = miny = MAX_COORD;
697
for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
437
/* next one if the index isn't used or symbol is empty (SPACE) */
438
if (!symbol->Valid || !symbol->LineN)
441
minx = miny = MAX_COORD;
443
for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
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);
455
/* move symbol to left edge */
456
for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
457
MOVE_LINE_LOWLEVEL(line, -minx, 0);
459
/* set symbol bounding box with a minimum cell size of (1,1) */
460
symbol->Width = maxx -minx +1;
461
symbol->Height = maxy +1;
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);
469
/* move coordinate system to the upper edge (lowest y on screen) */
470
for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
473
symbol->Height -= totalminy;
474
for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
475
MOVE_LINE_LOWLEVEL(line, 0, -totalminy);
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;
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);
713
/* set symbol bounding box with a minimum cell size of (1,1) */
714
symbol->Width = maxx - minx + 1;
715
symbol->Height = maxy + 1;
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);
723
/* move coordinate system to the upper edge (lowest y on screen) */
724
for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++)
727
symbol->Height -= totalminy;
728
for (line = symbol->Line, j = symbol->LineN; j; j--, line++)
729
MOVE_LINE_LOWLEVEL (line, 0, -totalminy);
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;
739
GetNum (char **s, BDimension * num)
742
while (isdigit (**s))
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:...
497
int ParseRouteString(char *s, RouteStyleTypePtr routeStyle)
753
ParseRouteString (char *s, RouteStyleTypePtr routeStyle, int scale)
502
memset(routeStyle, 0, NUM_STYLES * sizeof(RouteStyleType));
503
for (style = 0; style < NUM_STYLES; style++, routeStyle++)
505
while(*s && isspace(*s))
507
for (i = 0; *s && *s != ','; i++)
510
routeStyle->Name = MyStrdup(Name, "ParseRouteString()");
513
GetNum(&s, &routeStyle->Thick);
514
while(*s && isspace(*s))
518
while(*s && isspace(*s))
522
GetNum(&s, &routeStyle->Diameter);
523
while(*s && isspace(*s))
527
while(*s && isspace(*s))
531
GetNum(&s, &routeStyle->Hole);
532
if (style < NUM_STYLES - 1)
534
while(*s && isspace(*s))
758
memset (routeStyle, 0, NUM_STYLES * sizeof (RouteStyleType));
759
for (style = 0; style < NUM_STYLES; style++, routeStyle++)
761
while (*s && isspace (*s))
763
for (i = 0; *s && *s != ','; i++)
766
routeStyle->Name = MyStrdup (Name, "ParseRouteString()");
769
GetNum (&s, &routeStyle->Thick);
770
routeStyle->Thick *= scale;
771
while (*s && isspace (*s))
775
while (*s && isspace (*s))
779
GetNum (&s, &routeStyle->Diameter);
780
routeStyle->Diameter *= scale;
781
while (*s && isspace (*s))
785
while (*s && isspace (*s))
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. */
794
routeStyle->Keepaway = 1000;
798
while (*s && isspace (*s))
802
GetNum (&s, &routeStyle->Keepaway);
803
routeStyle->Keepaway *= scale;
804
while (*s && isspace (*s))
807
if (style < NUM_STYLES - 1)
809
while (*s && isspace (*s))
542
memset(routeStyle, 0, NUM_STYLES * sizeof(RouteStyleType));
817
memset (routeStyle, 0, NUM_STYLES * sizeof (RouteStyleType));
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)
550
int ParseGroupString(char *s, LayerGroupTypePtr LayerGroup)
826
ParseGroupString (char *s, LayerGroupTypePtr LayerGroup)
555
Boolean c_set = False, /* flags for the two special layers to */
556
s_set = False; /* provide a default setting for old formats */
559
memset(LayerGroup, 0, sizeof (LayerGroupType));
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 */
833
memset (LayerGroup, 0, sizeof (LayerGroupType));
835
/* loop over all groups */
836
for (group = 0; s && *s && group < MAX_LAYER; group++)
838
while (*s && isspace (*s))
841
/* loop over all group members */
842
for (member = 0; *s; s++)
564
while (*s && isspace(*s))
567
/* loop over all group members */
568
for (member = 0; *s; s++)
570
/* ignore white spaces and get layernumber */
571
while(*s && isspace(*s))
576
case 'C': layer = MAX_LAYER +COMPONENT_LAYER;
581
case 'S': layer = MAX_LAYER +SOLDER_LAYER;
585
default: if (!isdigit(*s))
590
if (layer > MAX_LAYER+ MAX(SOLDER_LAYER, COMPONENT_LAYER) ||
591
member >= MAX_LAYER+1)
593
LayerGroup->Entries[group][member++] = layer;
594
while (*++s && isdigit(*s));
596
/* ignore white spaces and check for seperator */
597
while (*s && isspace(*s))
599
if (!*s || *s == ':')
604
LayerGroup->Number[group] = member;
844
/* ignore white spaces and get layernumber */
845
while (*s && isspace (*s))
851
layer = MAX_LAYER + COMPONENT_LAYER;
857
layer = MAX_LAYER + SOLDER_LAYER;
864
layer = atoi (s) - 1;
867
if (layer > MAX_LAYER + MAX (SOLDER_LAYER, COMPONENT_LAYER) ||
868
member >= MAX_LAYER + 1)
870
LayerGroup->Entries[group][member++] = layer;
871
while (*++s && isdigit (*s));
873
/* ignore white spaces and check for seperator */
874
while (*s && isspace (*s))
876
if (!*s || *s == ':')
609
LayerGroup->Entries[SOLDER_LAYER][LayerGroup->Number[SOLDER_LAYER]++] =
610
MAX_LAYER +SOLDER_LAYER;
612
LayerGroup->Entries[COMPONENT_LAYER][LayerGroup->Number[COMPONENT_LAYER]++] =
613
MAX_LAYER +COMPONENT_LAYER;
881
LayerGroup->Number[group] = member;
886
LayerGroup->Entries[SOLDER_LAYER][LayerGroup->Number[SOLDER_LAYER]++] =
887
MAX_LAYER + SOLDER_LAYER;
890
Entries[COMPONENT_LAYER][LayerGroup->Number[COMPONENT_LAYER]++] =
891
MAX_LAYER + COMPONENT_LAYER;
616
/* reset structure on error */
618
memset(LayerGroup, 0, sizeof (LayerGroupType));
894
/* reset structure on error */
896
memset (LayerGroup, 0, sizeof (LayerGroupType));
622
900
/* ---------------------------------------------------------------------------
623
901
* quits application
625
void QuitApplication(void)
904
QuitApplication (void)
627
/* save data if necessary */
628
if (PCB->Changed && Settings.SaveInTMP)
906
/* save data if necessary */
907
if (PCB->Changed && Settings.SaveInTMP)
633
912
/* ---------------------------------------------------------------------------
635
914
* %f is replaced by the filename
636
915
* %p by the searchpath
638
char *EvaluateFilename(char *Template, char *Path, char *Filename,
918
EvaluateFilename (char *Template, char *Path, char *Filename, char *Parameter)
641
static DynamicStringType command;
920
static DynamicStringType command;
644
DSClearString(&command);
645
for (p = Template; *p; p++)
647
/* copy character or add string to command */
648
if (*p == '%' && (*(p+1) == 'f' || *(p+1) == 'p' || *(p+1) == 'a'))
651
case 'a': DSAddString(&command, Parameter); break;
652
case 'f': DSAddString(&command, Filename); break;
653
case 'p': DSAddString(&command, Path); break;
656
DSAddCharacter(&command, *p);
658
DSAddCharacter(&command, '\0');
659
return(MyStrdup(command.Data, "EvaluateFilename()"));
923
DSClearString (&command);
924
for (p = Template; *p; p++)
926
/* copy character or add string to command */
928
&& (*(p + 1) == 'f' || *(p + 1) == 'p' || *(p + 1) == 'a'))
932
DSAddString (&command, Parameter);
935
DSAddString (&command, Filename);
938
DSAddString (&command, Path);
942
DSAddCharacter (&command, *p);
944
DSAddCharacter (&command, '\0');
945
return (MyStrdup (command.Data, "EvaluateFilename()"));
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
666
char *ExpandFilename(char *Dirname, char *Filename)
668
static DynamicStringType answer;
673
/* allocate memory for commandline and build it */
674
DSClearString(&answer);
677
command = MyCalloc(strlen(Filename) +strlen(Dirname) +7,
678
sizeof(char), "ExpandFilename()");
679
sprintf(command, "echo %s/%s", Dirname, Filename);
683
command = MyCalloc(strlen(Filename) +6, sizeof(char), "Expand()");
684
sprintf(command, "echo %s", Filename);
687
/* execute it with shell */
688
if ((pipe = popen(command, "r")) != NULL)
690
/* discard all but the first returned line */
693
if ((c = fgetc(pipe)) == EOF || c == '\n' || c == '\r')
696
DSAddCharacter(&answer, c);
700
return (pclose(pipe) ? NULL : answer.Data);
703
/* couldn't be expanded by the shell */
704
PopenErrorMessage(command);
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
714
Boolean GetPosition(char *MessageText)
717
XAnyEvent *any = (XAnyEvent *) &event;
725
MessagePrompt(MessageText);
726
oldObjState = Crosshair.AttachedObject.State;
727
oldLineState = Crosshair.AttachedLine.State;
728
oldBoxState = Crosshair.AttachedBox.State;
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);
736
/* eat up all events that would cause actions to be performed */
739
XtAppNextEvent(Context, &event);
745
/* first check if we are inside the output window */
746
if (any->window != Output.OutputWindow)
749
/* evaluate cursor keys and modifier keys;
750
* dispatch the event if true
752
XLookupString((XKeyEvent *) &event, buffer, sizeof(buffer),
754
if (IsCursorKey(keysym) || IsModifierKey(keysym))
755
XtDispatchEvent(&event);
758
/* abort on any other key;
759
* restore cursor and clear message line
762
Crosshair.AttachedObject.State = oldObjState;
763
Crosshair.AttachedLine.State = oldLineState;
764
Crosshair.AttachedBox.State = oldBoxState;
765
RestoreCrosshair(True);
766
SetOutputXCursor(oldCursor);
768
return(any->type == ButtonPress);
773
XtDispatchEvent(&event);
953
ExpandFilename (char *Dirname, char *Filename)
955
static DynamicStringType answer;
960
/* allocate memory for commandline and build it */
961
DSClearString (&answer);
964
command = MyCalloc (strlen (Filename) + strlen (Dirname) + 7,
965
sizeof (char), "ExpandFilename()");
966
sprintf (command, "echo %s/%s", Dirname, Filename);
970
command = MyCalloc (strlen (Filename) + 6, sizeof (char), "Expand()");
971
sprintf (command, "echo %s", Filename);
974
/* execute it with shell */
975
if ((pipe = popen (command, "r")) != NULL)
977
/* discard all but the first returned line */
980
if ((c = fgetc (pipe)) == EOF || c == '\n' || c == '\r')
983
DSAddCharacter (&answer, c);
987
return (pclose (pipe) ? NULL : answer.Data);
990
/* couldn't be expanded by the shell */
991
PopenErrorMessage (command);
778
996
/* ----------------------------------------------------------------------
779
997
* releases pixmap used to draw output data
781
void ReleaseOffscreenPixmap(void)
784
if (VALID_PIXMAP(Offscreen))
785
XFreePixmap(Dpy, Offscreen);
787
/* mark pixmap unusable */
788
Offscreen = BadAlloc;
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
795
unsigned int SetOutputXCursor(unsigned int Shape)
797
unsigned int oldShape = Output.XCursorShape;
798
Cursor oldCursor = Output.XCursor;
800
/* check if window exists to prevent from fatal errors */
801
if (Output.OutputWindow)
803
Output.XCursorShape = Shape;
804
if (Shape == XC_Clockwise)
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,
821
Output.XCursor= XCreateFontCursor(Dpy, Shape);
822
XDefineCursor(Dpy, Output.OutputWindow, Output.XCursor);
825
/* release old cursor and return old shape */
827
XFreeCursor(Dpy, oldCursor);
830
return(DEFAULT_CURSORSHAPE);
1000
ReleaseOffscreenPixmap (void)
1003
if (VALID_PIXMAP (Offscreen))
1004
XFreePixmap (Dpy, Offscreen);
1006
/* mark pixmap unusable */
1007
Offscreen = BadAlloc;
833
1010
/* ---------------------------------------------------------------------------
834
1011
* returns the layer number for the passed pointer
836
int GetLayerNumber(DataTypePtr Data, LayerTypePtr Layer)
1014
GetLayerNumber (DataTypePtr Data, LayerTypePtr Layer)
840
for (i = 0; i < MAX_LAYER + 2; i++)
841
if (Layer == &Data->Layer[i])
1018
for (i = 0; i < MAX_LAYER + 2; i++)
1019
if (Layer == &Data->Layer[i])
846
1024
/* ---------------------------------------------------------------------------
847
1025
* returns the layergroup number for the passed pointer
849
int GetLayerGroupNumberByPointer(LayerTypePtr Layer)
1028
GetLayerGroupNumberByPointer (LayerTypePtr Layer)
851
return(GetLayerGroupNumberByNumber(GetLayerNumber(PCB->Data, Layer)));
1030
return (GetLayerGroupNumberByNumber (GetLayerNumber (PCB->Data, Layer)));
854
1033
/* ---------------------------------------------------------------------------
855
1034
* returns the layergroup number for the passed layernumber
857
int GetLayerGroupNumberByNumber(Cardinal Layer)
1037
GetLayerGroupNumberByNumber (Cardinal Layer)
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)
867
/* since every layer belongs to a group it is safe to return
868
* the value without boundary checking
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)
1046
/* since every layer belongs to a group it is safe to return
1047
* the value without boundary checking
873
1052
/* ---------------------------------------------------------------------------
874
1053
* returns a pointer to an objects bounding box;
875
1054
* data is valid until the routine is called again
877
BoxTypePtr GetObjectBoundingBox(int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1057
GetObjectBoundingBox (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
885
PinTypePtr via = (PinTypePtr) Ptr1;
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;
896
LineTypePtr line = (LineTypePtr) Ptr2;
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);
906
box = ((ArcTypePtr) Ptr2)->BoundingBox;
910
case ELEMENTNAME_TYPE:
911
box = ((TextTypePtr) Ptr2)->BoundingBox;
915
box = ((PolygonTypePtr) Ptr2)->BoundingBox;
919
box = ((ElementTypePtr) Ptr1)->BoundingBox;
924
PadTypePtr pad = (PadTypePtr) Ptr2;
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);
935
PinTypePtr pin = (PinTypePtr) Ptr2;
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;
946
PointTypePtr point = (PointTypePtr) Ptr3;
948
box.X1 = box.X2 = point->X;
949
box.Y1 = box.Y2 = point->Y;
953
case POLYGONPOINT_TYPE:
955
PointTypePtr point = (PointTypePtr) Ptr3;
957
box.X1 = box.X2 = point->X;
958
box.Y1 = box.Y2 = point->Y;
963
Message("Request for bounding box of unsupported typ %d\n",Type);
964
box.X1 = box.X2 = box.Y1 = box.Y2 = 0;
1065
PinTypePtr via = (PinTypePtr) Ptr1;
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;
1076
LineTypePtr line = (LineTypePtr) Ptr2;
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;
1090
box = ((ArcTypePtr) Ptr2)->BoundingBox;
1094
case ELEMENTNAME_TYPE:
1095
box = ((TextTypePtr) Ptr2)->BoundingBox;
1099
box = ((PolygonTypePtr) Ptr2)->BoundingBox;
1103
box = ((ElementTypePtr) Ptr1)->BoundingBox;
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;
1119
PadTypePtr pad = (PadTypePtr) Ptr2;
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;
1134
PinTypePtr pin = (PinTypePtr) Ptr2;
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;
1143
case LINEPOINT_TYPE:
1145
PointTypePtr point = (PointTypePtr) Ptr3;
1147
box.X1 = box.X2 = point->X;
1148
box.Y1 = box.Y2 = point->Y;
1152
case POLYGONPOINT_TYPE:
1154
PointTypePtr point = (PointTypePtr) Ptr3;
1156
box.X1 = box.X2 = point->X;
1157
box.Y1 = box.Y2 = point->Y;
1162
Message ("Request for bounding box of unsupported typ %d\n", Type);
1163
box.X1 = box.X2 = box.Y1 = box.Y2 = 0;
970
1169
/* ---------------------------------------------------------------------------
971
1170
* computes the bounding box of an arc
973
void SetArcBoundingBox(ArcTypePtr Arc)
1173
SetArcBoundingBox (ArcTypePtr Arc)
976
register Position temp, width;
978
box = GetArcEnds(Arc);
980
box->X1 = MIN(box->X1, box->X2);
981
box->X2 = MAX(box->X2, temp);
983
box->Y1 = MIN(box->Y1, box->Y2);
984
box->Y2 = MAX(box->Y2, temp);
985
width = Arc->Thickness/2;
990
Arc->BoundingBox = *box;
1175
register double ca1, ca2, sa1, sa2;
1176
register LocationType ang1, ang2;
1177
register LocationType width;
1179
/* first put angles into standard form */
1180
if (Arc->Delta > 360)
1182
ang1 = Arc->StartAngle;
1183
ang2 = Arc->StartAngle + Arc->Delta;
1196
/* calculate sines, cosines */
1216
ca1 = M180 * (double) ang1;
1239
ca2 = M180 * (double) ang2;
1244
Arc->BoundingBox.X2 = Arc->X - Arc->Width *
1245
((ang1 < 180 && ang2 > 180) ? -1 : MIN (ca1, ca2));
1247
Arc->BoundingBox.X1 = Arc->X - Arc->Width *
1248
((ang1 < 360 && ang2 > 360) ? 1 : MAX (ca1, ca2));
1250
Arc->BoundingBox.Y2 = Arc->Y + Arc->Height *
1251
((ang1 < 90 && ang2 > 90) ? 1 : MAX (sa1, sa2));
1253
Arc->BoundingBox.Y1 = Arc->Y + Arc->Height *
1254
((ang1 < 270 && ang2 > 270) ? -1 : MIN (sa1, sa2));
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;
993
1263
/* ---------------------------------------------------------------------------
994
1264
* resets the layerstack setting
996
void ResetStackAndVisibility(void)
1000
for (i = 0; i < MAX_LAYER + 2; i++)
1004
PCB->Data->Layer[i].On = True;
1006
PCB->ElementOn = True;
1007
PCB->InvisibleObjectsOn = True;
1267
ResetStackAndVisibility (void)
1271
for (i = 0; i < MAX_LAYER + 2; i++)
1275
PCB->Data->Layer[i].On = True;
1277
PCB->ElementOn = True;
1278
PCB->InvisibleObjectsOn = True;
1284
/* ---------------------------------------------------------------------------
1285
* saves the layerstack setting
1288
SaveStackAndVisibility (void)
1291
static Boolean run = False;
1299
if (SavedStack.cnt != 0)
1302
"SaveStackAndVisibility() layerstack was already saved and not"
1303
"yet restored. cnt = %d\n", SavedStack.cnt);
1306
for (i = 0; i < MAX_LAYER + 2; i++)
1309
SavedStack.LayerStack[i] = LayerStack[i];
1310
SavedStack.LayerOn[i] = PCB->Data->Layer[i].On;
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;
1320
/* ---------------------------------------------------------------------------
1321
* restores the layerstack setting
1324
RestoreStackAndVisibility (void)
1328
if (SavedStack.cnt == 0)
1330
fprintf (stderr, "RestoreStackAndVisibility() layerstack has not"
1331
" been saved. cnt = %d\n", SavedStack.cnt);
1334
else if (SavedStack.cnt != 1)
1336
fprintf (stderr, "RestoreStackAndVisibility() layerstack save count is"
1337
" wrong. cnt = %d\n", SavedStack.cnt);
1340
for (i = 0; i < MAX_LAYER + 2; i++)
1343
LayerStack[i] = SavedStack.LayerStack[i];
1344
PCB->Data->Layer[i].On = SavedStack.LayerOn[i];
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;
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'
1016
char *GetWorkingDirectory(void)
1361
GetWorkingDirectory (char *path)
1018
static char path[MAXPATHLEN+1];
1020
#if defined(SYSV) || defined(linux)
1021
return(getcwd(path, MAXPATHLEN));
1363
#if defined(SYSV) || defined(linux) || defined(__NetBSD__)
1364
return getcwd (path, MAXPATHLEN);
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);
1028
1372
/* ---------------------------------------------------------------------------
1029
1373
* writes a string to the passed file pointer
1030
1374
* some special characters are quoted
1032
void CreateQuotedString(DynamicStringTypePtr DS, char *S)
1377
CreateQuotedString (DynamicStringTypePtr DS, char *S)
1035
DSAddCharacter(DS, '"');
1038
if (*S == '"' || *S == '\\')
1039
DSAddCharacter(DS, '\\');
1040
DSAddCharacter(DS, *S++);
1042
DSAddCharacter(DS, '"');
1380
DSAddCharacter (DS, '"');
1383
if (*S == '"' || *S == '\\')
1384
DSAddCharacter (DS, '\\');
1385
DSAddCharacter (DS, *S++);
1387
DSAddCharacter (DS, '"');
1045
1390
/* ---------------------------------------------------------------------------
1046
1391
* returns the current possible grid factor or zero
1048
int GetGridFactor(void)
1394
GetGridFactor (void)
1050
static int factor[] = { 1, 2, 5, 10 };
1396
static int factor[] = { 1, 2, 5, 10 };
1054
/* check to see if we have to draw every point,
1055
* every 2nd, 5th or 10th
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
1402
for (i = 0; i < ENTRIES (factor); i++)
1404
delta = PCB->Grid * factor[i];
1405
if (TO_SCREEN (delta) >= MIN_GRID_DISTANCE)
1059
delta = PCB->Grid *factor[i];
1060
if (TO_SCREEN(delta) >= MIN_GRID_DISTANCE)
1062
if (Settings.GridFactor != factor[i])
1064
Settings.GridFactor = factor[i];
1407
if (Settings.GridFactor != factor[i])
1409
Settings.GridFactor = factor[i];
1070
Settings.GridFactor = 0;
1075
static void RightAngles(int Angle, float *cosa, float *sina)
1077
*cosa = (float) cos((double) Angle * M180);
1078
*sina = (float) sin((double) Angle * M180);
1081
BoxTypePtr GetArcEnds(ArcTypePtr Arc)
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;
1095
static char *BumpName(char *Name)
1099
static char temp[256];
1102
/* seek end of string */
1105
/* back up to potential number */
1106
for (Name--; isdigit(*Name); Name--);
1109
num = atoi(Name) + 1;
1114
sprintf(temp, "%s%d", start, num);
1115
/* if this is not our string, put back the blown character */
1415
Settings.GridFactor = 0;
1421
RightAngles (int Angle, float *cosa, float *sina)
1423
*cosa = (float) cos ((double) Angle * M180);
1424
*sina = (float) sin ((double) Angle * M180);
1428
GetArcEnds (ArcTypePtr Arc)
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;
1443
BumpName (char *Name)
1447
static char temp[256];
1450
/* seek end of string */
1453
/* back up to potential number */
1454
for (Name--; isdigit (*Name); Name--);
1457
num = atoi (Name) + 1;
1462
sprintf (temp, "%s%d", start, num);
1463
/* if this is not our string, put back the blown character */
1122
1470
* make a unique name for the name on board
1123
1471
* this can alter the contents of the input string
1125
char *UniqueElementName(DataTypePtr Data, char *Name)
1127
Boolean unique = True;
1128
/* null strings are ok */
1129
if (!Name || !*Name)
1135
if (NAMEONPCB_NAME(element) &&
1136
strcmp(NAMEONPCB_NAME(element), Name) == 0)
1138
Name = BumpName(Name);
1149
static void GetGridLockCoordinates(int type, void *ptr1,
1150
void *ptr2, void *ptr3, Position *x, Position *y)
1155
*x = ((PinTypePtr) ptr2)->X;
1156
*y = ((PinTypePtr) ptr2)->Y;
1159
*x = ((LineTypePtr) ptr2)->Point1.X;
1160
*y = ((LineTypePtr) ptr2)->Point1.Y;
1163
case ELEMENTNAME_TYPE:
1164
*x = ((TextTypePtr) ptr2)->X;
1165
*y = ((TextTypePtr) ptr2)->Y;
1168
*x = ((ElementTypePtr) ptr2)->MarkX;
1169
*y = ((ElementTypePtr) ptr2)->MarkY;
1172
*x = ((PolygonTypePtr) ptr2)->Points[0].X;
1173
*y = ((PolygonTypePtr) ptr2)->Points[0].Y;
1176
case LINEPOINT_TYPE:
1177
case POLYGONPOINT_TYPE:
1178
*x = ((PointTypePtr) ptr3)->X;
1179
*y = ((PointTypePtr) ptr3)->Y;
1185
box = GetArcEnds((ArcTypePtr) ptr2);
1193
void AttachForCopy(Position PlaceX, Position PlaceY)
1198
Crosshair.AttachedObject.RubberbandN = 0;
1199
/* dither the grab point so that the mark, center, etc
1200
* will end up on a grid coordinate
1202
GetGridLockCoordinates(Crosshair.AttachedObject.Type,
1203
Crosshair.AttachedObject.Ptr1,
1204
Crosshair.AttachedObject.Ptr2,
1205
Crosshair.AttachedObject.Ptr3,
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;
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));
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);
1244
Boolean ShiftPressed(void)
1248
XQueryKeymap(Dpy, keys);
1249
if (keys[ShiftKeyIndex] & ShiftKeyMask)
1474
UniqueElementName (DataTypePtr Data, char *Name)
1476
Boolean unique = True;
1477
/* null strings are ok */
1478
if (!Name || !*Name)
1483
ELEMENT_LOOP (Data);
1485
if (NAMEONPCB_NAME (element) &&
1486
NSTRCMP (NAMEONPCB_NAME (element), Name) == 0)
1488
Name = BumpName (Name);
1501
GetGridLockCoordinates (int type, void *ptr1,
1502
void *ptr2, void *ptr3, LocationType * x, LocationType * y)
1507
*x = ((PinTypePtr) ptr2)->X;
1508
*y = ((PinTypePtr) ptr2)->Y;
1511
*x = ((LineTypePtr) ptr2)->Point1.X;
1512
*y = ((LineTypePtr) ptr2)->Point1.Y;
1515
case ELEMENTNAME_TYPE:
1516
*x = ((TextTypePtr) ptr2)->X;
1517
*y = ((TextTypePtr) ptr2)->Y;
1520
*x = ((ElementTypePtr) ptr2)->MarkX;
1521
*y = ((ElementTypePtr) ptr2)->MarkY;
1524
*x = ((PolygonTypePtr) ptr2)->Points[0].X;
1525
*y = ((PolygonTypePtr) ptr2)->Points[0].Y;
1528
case LINEPOINT_TYPE:
1529
case POLYGONPOINT_TYPE:
1530
*x = ((PointTypePtr) ptr3)->X;
1531
*y = ((PointTypePtr) ptr3)->Y;
1537
box = GetArcEnds ((ArcTypePtr) ptr2);
1546
AttachForCopy (LocationType PlaceX, LocationType PlaceY)
1549
LocationType mx, my;
1551
Crosshair.AttachedObject.RubberbandN = 0;
1552
if (TEST_FLAG (SNAPPINFLAG, PCB))
1559
/* dither the grab point so that the mark, center, etc
1560
* will end up on a grid coordinate
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;
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;
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));
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);
1603
* Return nonzero if the given file exists and is readable.
1606
FileExists (const char *name)
1609
f = fopen (name, "r");
1619
Concat (const char *first, ...)
1625
len = strlen (first);
1626
rv = (char *) malloc (len + 1);
1629
va_start (a, first);
1632
const char *s = va_arg (a, const char *);
1636
rv = (char *) realloc (rv, len + 1);