1 /* $XConsortium: DrArrow.c /main/6 1995/10/25 19:59:56 cde-sun $ */
2 /*
3  * Motif
4  *
5  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6  *
7  * These libraries and programs are free software; you can
8  * redistribute them and/or modify them under the terms of the GNU
9  * Lesser General Public License as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * These libraries and programs are distributed in the hope that
14  * they will be useful, but WITHOUT ANY WARRANTY; without even the
15  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16  * PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with these librararies and programs; if not, write
21  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22  * Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 /*
26  * HISTORY
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 
34 #include "XmI.h"
35 #include <Xm/DrawP.h>
36 
37 
38 /****************************XmeDrawArrow**********************************/
XmeDrawArrow(Display * display,Drawable d,GC top_gc,GC bot_gc,GC cent_gc,int x,int y,int width,int height,int shadow_thick,unsigned int direction)39 void XmeDrawArrow(Display *display, Drawable d,
40                   GC top_gc, GC bot_gc, GC cent_gc,
41 #if NeedWidePrototypes
42                   int x, int y,
43                   int width, int height, int shadow_thick,
44                   unsigned int direction)
45 #else
46                   Position x, Position y,
47                   Dimension width, Dimension height, Dimension shadow_thick,
48                   unsigned char direction)
49 #endif /* NeedWidePrototypes */
50 {
51    /* cent_gc might be NULL, which means don't draw anything on the center,
52       but if shadow_thick is 1, then center is not NULL, see in ArrowB */
53    /* in the current implementation, on shadow_thick = 2, 1 or 0 supported */
54 
55    static unsigned int allocated = 0;
56    static XRectangle * top  = NULL;
57    static XRectangle * cent = NULL;
58    static XRectangle * bot  = NULL;
59    XRectangle * rect_tmp;
60    int size, xOffset = 0, yOffset = 0, wwidth, start;
61    register int temp, yy, i, h, w;
62    short t = 0 , b = 0 , c = 0 ;
63    XtAppContext app;
64 
65    if (!d) return ;
66 
67    app = XtDisplayToApplicationContext(display);
68    _XmAppLock(app);
69 
70    /*  Get the size and the position and allocate the rectangle lists  */
71 
72    if (width > height) {
73       size = height - 2;
74       xOffset = (width - height) / 2;
75    } else {
76       size = width - 2 ;
77       yOffset = (height - width) / 2;
78    }
79    if (size < 1) { _XmAppUnlock(app); return; }
80    if (allocated < size) {
81       _XmProcessLock();
82       top  = (XRectangle *) XtRealloc ((char*)top,
83                                        sizeof (XRectangle) * (size/2+6));
84       cent = (XRectangle *) XtRealloc ((char*)cent,
85                                        sizeof (XRectangle) * (size/2+6));
86       bot  = (XRectangle *) XtRealloc ((char*)bot,
87                                        sizeof (XRectangle) * (size/2+6));
88       allocated = size;
89       _XmProcessUnlock();
90    }
91 
92 #define SWAP(x,y) temp = x ; x = y; y = temp
93 
94    if (direction == XmARROW_RIGHT || direction == XmARROW_LEFT) {
95       SWAP(xOffset,yOffset) ;
96    }
97 
98    /*  Set up a loop to generate the segments.  */
99 
100    wwidth = size;
101    yy = size - 1 + yOffset;
102    start = 1 + xOffset;
103 
104    _XmProcessLock();
105    while (wwidth > 0) {
106        if (wwidth == 1) {
107            top[t].x = start; top[t].y = yy + 1;
108            top[t].width = 1; top[t].height = 1;
109            t++;
110        }
111        else if (wwidth == 2) {
112            if (size == 2 || (direction == XmARROW_UP ||
113                              direction == XmARROW_LEFT)) {
114                top[t].x = start; top[t].y = yy;
115                top[t].width = 2; top[t].height = 1;
116                t++;
117                top[t].x = start; top[t].y = yy + 1;
118                top[t].width = 1; top[t].height = 1;
119                t++;
120                bot[b].x = start + 1; bot[b].y = yy + 1;
121                bot[b].width = 1; bot[b].height = 1;
122                b++;
123            }
124        }
125        else {
126            if (start == 1 + xOffset)
127                {
128                    if (direction == XmARROW_UP || direction == XmARROW_LEFT) {
129                        top[t].x = start; top[t].y = yy;
130                        top[t].width = 2; top[t].height = 1;
131                        t++;
132                        top[t].x = start; top[t].y = yy + 1;
133                        top[t].width = 1; top[t].height = 1;
134                        t++;
135                        bot[b].x = start + 1; bot[b].y = yy + 1;
136                        bot[b].width = 1; bot[b].height = 1;
137                        b++;
138                        bot[b].x = start + 2; bot[b].y = yy;
139                        bot[b].width = wwidth - 2; bot[b].height = 2;
140                        b++;
141                    }
142                    else {
143                        top[t].x = start; top[t].y = yy;
144                        top[t].width = 2; top[t].height = 1;
145                        t++;
146                        bot[b].x = start; bot[b].y = yy + 1;
147                        bot[b].width = 2; bot[b].height = 1;
148                        b++;
149                        bot[b].x = start + 2; bot[b].y = yy;
150                        bot[b].width = wwidth - 2; bot[b].height = 2;
151                        b++;
152                    }
153                }
154            else {
155                top[t].x = start; top[t].y = yy;
156                top[t].width = 2; top[t].height = 2;
157                t++;
158                bot[b].x = start + wwidth - 2; bot[b].y = yy;
159                bot[b].width = 2; bot[b].height = 2;
160                if (wwidth == 3) {
161                    bot[b].width = 1;
162                    bot[b].x += 1;
163                }
164                b++;
165                if (wwidth > 4) {
166                    cent[c].x = start + 2; cent[c].y = yy;
167                    cent[c].width = wwidth - 4; cent[c].height = 2;
168                    c++;
169                }
170            }
171        }
172        start++;
173        wwidth -= 2;
174        yy -= 2;
175    }
176 
177    if (direction == XmARROW_DOWN || direction == XmARROW_RIGHT) {
178        rect_tmp = top; top = bot; bot = rect_tmp;
179        SWAP(t, b);
180    }
181 
182 
183    /*  Transform the "up" pointing arrow to the correct direction  */
184 
185    switch (direction) {
186    case XmARROW_LEFT:
187        i = -1;
188        do {
189            i++;
190            if (i < t) {
191                SWAP(top[i].y, top[i].x);
192                SWAP(top[i].width, top[i].height);
193            }
194            if (i < b) {
195                SWAP(bot[i].y, bot[i].x);
196                SWAP(bot[i].width, bot[i].height);
197            }
198            if (i < c) {
199                SWAP(cent[i].y, cent[i].x);
200                SWAP(cent[i].width, cent[i].height);
201            }
202        } while (i < t || i < b || i < c);
203        break;
204 
205    case XmARROW_RIGHT:
206        h = height - 2;
207        w = width - 2;
208        i = -1;
209        do {
210            i++;
211            if (i < t) {
212                SWAP(top[i].y, top[i].x);
213                SWAP(top[i].width, top[i].height);
214                top[i].x = w - top[i].x - top[i].width + 2;
215                top[i].y = h - top[i].y - top[i].height + 2;
216            }
217            if (i < b) {
218                SWAP(bot[i].y, bot[i].x);
219                SWAP(bot[i].width, bot[i].height);
220                bot[i].x = w - bot[i].x - bot[i].width + 2;
221                bot[i].y = h - bot[i].y - bot[i].height + 2;
222            }
223            if (i < c) {
224                SWAP(cent[i].y, cent[i].x);
225                SWAP(cent[i].width, cent[i].height);
226                cent[i].x = w - cent[i].x - cent[i].width + 2;
227                cent[i].y = h - cent[i].y - cent[i].height + 2;
228            }
229        } while (i < t || i < b || i < c);
230        break;
231 
232    case XmARROW_DOWN:
233        w = width - 2;
234        h = height - 2;
235        i = -1;
236        do {
237            i++;
238            if (i < t) {
239                top[i].x = w - top[i].x - top[i].width + 2;
240                top[i].y = h - top[i].y - top[i].height + 2;
241            }
242            if (i < b) {
243                bot[i].x = w - bot[i].x - bot[i].width + 2;
244                bot[i].y = h - bot[i].y - bot[i].height + 2;
245            }
246            if (i < c) {
247                cent[i].x = w - cent[i].x - cent[i].width + 2;
248                cent[i].y = h - cent[i].y - cent[i].height + 2;
249            }
250        } while (i < t || i < b || i < c);
251        break;
252    }
253 
254    if (x != 0 || y != 0) {
255        for (i = 0; i < t; i++) {
256            top[i].x += x;
257            top[i].y += y;
258        }
259        for (i = 0; i < c; i++) {
260            cent[i].x += x;
261            cent[i].y += y;
262        }
263        for (i = 0; i < b; i++) {
264            bot[i].x += x;
265            bot[i].y += y;
266        }
267    }
268 
269    if (shadow_thick) {  /* 1 or 2 shadow thickness: always draw
270 			   2 thickness at that point, we'll correct it
271 			   later */
272        XFillRectangles (display, d, top_gc, top, t);
273        XFillRectangles (display, d, bot_gc, bot, b);
274    } else {
275        /* handle the case where arrow shadow_thickness = 0, which give
276           a flat arrow: draw the shadow area with the center color */
277        if (cent_gc) {
278            XFillRectangles (display, d, cent_gc, top, t);
279            XFillRectangles (display, d, cent_gc, bot, b);
280        }
281    }
282 
283    if (shadow_thick == 1) {
284        /* we already drawn the shadow of 2, now let's draw a
285 	  bigger center area: ask for a smaller arrow with
286 	  flat look */
287        XmeDrawArrow(display, d, top_gc, bot_gc, cent_gc,
288 		    x+1, y+1, width-2, height-2, 0, direction) ;
289    } else
290    if (cent_gc) XFillRectangles (display, d, cent_gc, cent, c);
291    _XmProcessUnlock();
292    _XmAppUnlock(app);
293 }
294 
295