source: trunk/athena/lib/Xj/Arrow.c @ 12350

Revision 12350, 10.6 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: Arrow.c,v 1.2 1999-01-22 23:16:47 ghudson Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char rcsid[] =
13"$Id: Arrow.c,v 1.2 1999-01-22 23:16:47 ghudson Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include "Jets.h"
19#include "Arrow.h"
20
21extern int DEBUG;
22
23#define offset(field) XjOffset(ArrowJet,field)
24
25static XjResource resources[] = {
26  { XjNx, XjCX, XjRInt, sizeof(int),
27      offset(core.x), XjRString, XjInheritValue },
28  { XjNy, XjCY, XjRInt, sizeof(int),
29      offset(core.y), XjRString, XjInheritValue },
30  { XjNwidth, XjCWidth, XjRInt, sizeof(int),
31      offset(core.width), XjRString, "15" },
32  { XjNheight, XjCHeight, XjRInt, sizeof(int),
33      offset(core.height), XjRString, "15" },
34  { XjNforeground, XjCForeground, XjRColor, sizeof(int),
35      offset(arrow.foreground), XjRString, XjDefaultForeground },
36  { XjNbackground, XjCBackground, XjRColor, sizeof(int),
37      offset(arrow.background), XjRString, XjDefaultBackground },
38  { XjNfillColor, XjCForeground, XjRColor, sizeof(int),
39      offset(arrow.fillColor), XjRString, XjDefaultForeground },
40  { XjNreverseVideo, XjCReverseVideo, XjRBoolean, sizeof(Boolean),
41      offset(arrow.reverseVideo), XjRBoolean, (caddr_t) False },
42  { XjNpadding, XjCPadding, XjRInt, sizeof(int),
43      offset(arrow.padding), XjRString, "2" },
44  { XjNdirection, XjCDirection, XjRDirection, sizeof(int),
45      offset(arrow.direction), XjRString, XjNorth },
46  { XjNhighlightProc, XjCHighlightProc, XjRCallback, sizeof(XjCallback *),
47      offset(arrow.highlightProc), XjRString, "fillArrow(1)" },
48  { XjNunHighlightProc, XjCHighlightProc, XjRCallback, sizeof(XjCallback *),
49      offset(arrow.unHighlightProc), XjRString, "fillArrow(0)" },
50};
51
52#undef offset
53
54static void classInitialize(), expose(), realize(),
55  querySize(), move(), destroy(), resize(), computePoints();
56
57int fillArrow();
58
59ArrowClassRec arrowClassRec = {
60  {
61    /* class name */            "Arrow",
62    /* jet size   */            sizeof(ArrowRec),
63    /* classInitialize */       classInitialize,
64    /* classInitialized? */     0,
65    /* initialize */            NULL,
66    /* prerealize */            NULL,
67    /* realize */               realize,
68    /* event */                 NULL,
69    /* expose */                expose,
70    /* querySize */             querySize,
71    /* move */                  move,
72    /* resize */                resize,
73    /* destroy */               destroy,
74    /* resources */             resources,
75    /* number of 'em */         XjNumber(resources)
76  }
77};
78
79JetClass arrowJetClass = (JetClass)&arrowClassRec;
80
81
82static void classInitialize(me)
83     ArrowJet me;
84{
85  XjRegisterCallback(fillArrow, "fillArrow");
86}
87
88
89/*
90 * Things are currently broken screenwise.
91 * It will be fun to fix later. :)
92 */
93static void realize(me)
94     ArrowJet me;
95{
96  unsigned long valuemask;
97  XGCValues values;
98
99  if (me->arrow.reverseVideo)
100    {
101      int temp;
102
103      temp = me->arrow.foreground;
104      me->arrow.foreground = me->arrow.background;
105      me->arrow.background = temp;
106      if (me->arrow.fillColor == me->arrow.background)
107        me->arrow.fillColor = me->arrow.foreground;
108    }
109
110  values.foreground = me->arrow.foreground;
111  values.background = me->arrow.background;
112  values.function = GXcopy;
113  values.graphics_exposures = False;
114  valuemask = ( GCForeground | GCBackground |
115               GCFunction | GCGraphicsExposures );
116
117  me->arrow.gc_reverse = XjCreateGC(me->core.display,
118                                    me->core.window,
119                                    valuemask,
120                                    &values);
121
122  values.foreground = me->arrow.background;
123  values.background = me->arrow.foreground;
124  valuemask = ( GCForeground | GCBackground |
125               GCFunction | GCGraphicsExposures );
126
127  me->arrow.gc = XjCreateGC(me->core.display,
128                            me->core.window,
129                            valuemask,
130                            &values);
131
132  values.foreground = me->arrow.fillColor;
133  valuemask = ( GCForeground | GCBackground |
134               GCFunction | GCGraphicsExposures );
135
136  me->arrow.gc_fill = XjCreateGC(me->core.display,
137                                 me->core.window,
138                                 valuemask,
139                                 &values);
140}
141
142static void destroy(me)
143     ArrowJet me;
144{
145  XjFreeGC(me->core.display, me->arrow.gc);
146  XjFreeGC(me->core.display, me->arrow.gc_reverse);
147  XjFreeGC(me->core.display, me->arrow.gc_fill);
148}
149
150static void querySize(me, size)
151     ArrowJet me;
152     XjSize *size;
153{
154  if (DEBUG)
155    printf ("QS(arrow) '%s' w=%d,h=%d\n", me->core.name, me->core.width,
156            me->core.height);
157
158  size->width = me->core.width;
159  size->height = me->core.height;
160}
161
162static void move(me, x, y)
163     ArrowJet me;
164     int x, y;
165{
166  if (DEBUG)
167    printf ("MV(arrow) '%s' x=%d,y=%d\n", me->core.name, x, y);
168
169  me->core.x = x;
170  me->core.y = y;
171  computePoints(me);
172}
173
174static void resize(me, size)
175     Jet me;
176     XjSize *size;
177{
178  if (DEBUG)
179    printf ("RS(arrow) '%s' w=%d,d=%d\n",
180            me->core.name, size->width, size->height);
181
182  if (me->core.width != size->width
183      || me->core.height != size->height)
184    {
185      XClearArea(me->core.display, me->core.window,
186                 me->core.x, me->core.y,
187                 me->core.width, me->core.height,
188                 None);
189
190      me->core.width = size->width;
191      me->core.height = size->height;
192
193      computePoints(me);
194    }
195}
196
197
198static void expose(me, event)
199     Jet me;
200     XEvent *event;             /* ARGSUSED */
201{
202  ArrowJet aj = (ArrowJet) me;
203
204  XFillPolygon(me->core.display, me->core.window,
205               aj->arrow.gc,
206               aj->arrow.pt, aj->arrow.num_pts,
207               Nonconvex, CoordModeOrigin);
208  XDrawLines(me->core.display, me->core.window,
209             aj->arrow.gc_reverse,
210             aj->arrow.pt, aj->arrow.num_pts, CoordModeOrigin);
211}
212
213
214int fillArrow(me, fill, data)
215     Jet me;
216     int fill;
217     caddr_t data;              /* ARGSUSED */
218{
219  ArrowJet aj = (ArrowJet) me;
220
221  if (fill)
222    XFillPolygon(me->core.display, me->core.window,
223                 aj->arrow.gc_fill,
224                 aj->arrow.pt, aj->arrow.num_pts,
225                 Nonconvex, CoordModeOrigin);
226  else
227    XFillPolygon(me->core.display, me->core.window,
228                 aj->arrow.gc,
229                 aj->arrow.pt, aj->arrow.num_pts,
230                 Nonconvex, CoordModeOrigin);
231  XDrawLines(me->core.display, me->core.window,
232             aj->arrow.gc_reverse,
233             aj->arrow.pt, aj->arrow.num_pts, CoordModeOrigin);
234  return 0;
235}
236
237
238void setDirection(me, dir)
239     ArrowJet me;
240     int dir;
241{
242  XClearArea(me->core.display, me->core.window,
243             me->core.x, me->core.y,
244             me->core.width, me->core.height,
245             None);
246  me->arrow.direction = dir;
247
248  computePoints((Jet) me);
249  expose((Jet) me, NULL);
250}
251
252
253
254static void computePoints(me)
255     Jet me;
256{
257  ArrowJet aj = (ArrowJet) me;
258  int length = MIN(me->core.width, me->core.height);
259  int length2 = length - (2 * aj->arrow.padding);
260
261  aj->arrow.x = me->core.x + (me->core.width - length)/2;
262  aj->arrow.y = me->core.y + (me->core.height - length)/2;
263
264  if (aj->arrow.direction % 2)  /* the diagonals are all "odd" */
265    {
266/*
267 *  For an arrow pointing northeast, the points go something like this:
268 *
269 *  07-----6    Point 0 and 7 are identical, to close the figure.
270 *   \     |
271 *    1    |    For the other diagonals, you get the idea...
272 *   /     |
273 *  2   4  |
274 *   \ / \ |
275 *    3   \5
276 */
277      int i;
278      double len25 = length2 * .25;
279      double len35 = length2 * .35;
280      double len40 = length2 * .40;
281
282#define PT aj->arrow.pt
283#define PAD aj->arrow.padding
284#define len15  (len40-len25)
285#define len75  (len35+len40)
286#define len100 (len25+len75)
287#define LEN  (PAD + length2 - 1)
288
289      aj->arrow.num_pts = 8;
290
291      /*
292       * Assign the "X" coordinates first...
293       */
294      switch (aj->arrow.direction)
295        {
296        case 1:         /* northeast */
297        case 3:         /* southeast */
298          PT[0].x = PT[7].x = PAD + len15;
299          PT[1].x = PAD + len40;
300          PT[2].x = PAD;
301          PT[3].x = PAD + len35;
302          PT[4].x = PAD + len75;
303          PT[5].x = PT[6].x = PAD + length2;
304          break;
305
306        case 5:         /* southwest */
307          break;
308
309        case 7:         /* northwest */
310          break;
311        }
312
313      /*
314       * Now assign the "Y" coordinates...
315       */
316      switch (aj->arrow.direction)
317        {
318        case 1:         /* northeast */
319          PT[0].y = PT[6].y = PT[7].y = LEN - len100;
320          PT[1].y = LEN - len75;
321          PT[2].y = LEN - len35;
322          PT[3].y = LEN;
323          PT[4].y = LEN - len40;
324          PT[5].y = LEN - len15 /*len40 + len25*/;
325          break;
326
327        case 3:         /* southeast */
328          PT[0].y = PT[6].y = PT[7].y = PAD + len100;
329          PT[1].y = PAD + len75;
330          PT[2].y = PAD + len35;
331          PT[3].y = PAD;
332          PT[4].y = PAD + len40;
333          PT[5].y = PAD + len15;
334          break;
335
336        case 2:         /* east */
337        case 6:         /* west */
338          break;
339        }
340
341      for (i=0; i < aj->arrow.num_pts; i++)
342        {
343          PT[i].x += aj->arrow.x;
344          PT[i].y += aj->arrow.y;
345        }
346    }
347  else                          /* N, E, S, W are all "even" */
348    {
349/*
350 *  For an arrow pointing north, the points go something like this:
351 *      0--9       
352 *     /    \      Points 0 and 9 are distinct points, because of
353 *    /      \     the fact that we divide the width by 2 in order
354 *   /        \    to get the midpoint, and so for an even-width
355 *  1          8   arrow, the "tip" of the arrow will be off-center
356 *  2--3    6--7   by one pixel.
357 *     |    |
358 *     4----5      Similar ordering for the other major directions.
359 */
360      int l[8], x[8], y[8], i;
361      int length3 = (length + 1)/2 - 1;
362      int length4 = length2 * 2/7;
363
364      aj->arrow.num_pts = 10;
365
366      l[0] = aj->arrow.padding;
367      l[1] = length3;
368      l[2] = length/2;
369      l[3] = aj->arrow.padding + length2 - 1;
370      l[4] = aj->arrow.padding + length4;
371      l[5] = l[3] - length4;
372      l[6] = length3 + 1;
373      l[7] = l[2] - 1;
374
375      for (i=0; i<8; i++)
376        {
377          x[i] = l[i] + aj->arrow.x;
378          y[i] = l[i] + aj->arrow.y;
379        }
380
381      /*
382       * Assign the "X" coordinates first...
383       */
384      switch (aj->arrow.direction)
385        {
386        case 0:         /* north */
387        case 4:         /* south */
388          PT[0].x = x[1];
389          PT[1].x = PT[2].x = x[0];
390          PT[3].x = PT[4].x = x[4];
391          PT[5].x = PT[6].x = x[5];
392          PT[7].x = PT[8].x = x[3];
393          PT[9].x = x[2];
394          break;
395
396        case 2:         /* east */
397          PT[0].x = PT[9].x = x[3];
398          PT[1].x = PT[8].x = x[2];
399          PT[2].x = PT[3].x = PT[6].x = PT[7].x = x[7];
400          PT[4].x = PT[5].x = x[0];
401          break;
402
403        case 6:         /* west */
404          PT[0].x = PT[9].x = x[0];
405          PT[1].x = PT[8].x = x[1];
406          PT[2].x = PT[3].x = PT[6].x = PT[7].x = x[6];
407          PT[4].x = PT[5].x = x[3];
408          break;
409        }
410
411      /*
412       * Now assign the "Y" coordinates...
413       */
414      switch (aj->arrow.direction)
415        {
416        case 0:         /* north */
417          PT[0].y = PT[9].y = y[0];
418          PT[1].y = PT[8].y = y[1];
419          PT[2].y = PT[3].y = PT[6].y = PT[7].y = y[6];
420          PT[4].y = PT[5].y = y[3];
421          break;
422
423        case 4:         /* south */
424          PT[0].y = PT[9].y = y[3];
425          PT[1].y = PT[8].y = y[2];
426          PT[2].y = PT[3].y = PT[6].y = PT[7].y = y[7];
427          PT[4].y = PT[5].y = y[0];
428          break;
429
430        case 2:         /* east */
431        case 6:         /* west */
432          PT[0].y = y[1];
433          PT[1].y = PT[2].y = y[0];
434          PT[3].y = PT[4].y = y[4];
435          PT[5].y = PT[6].y = y[5];
436          PT[7].y = PT[8].y = y[3];
437          PT[9].y = y[2];
438          break;
439#undef PT
440        }
441    }
442}
Note: See TracBrowser for help on using the repository browser.