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