/* $XConsortium: DrArrow.c /main/6 1995/10/25 19:59:56 cde-sun $ */ /* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * HISTORY */ #ifdef HAVE_CONFIG_H #include #endif #include "XmI.h" #include /****************************XmeDrawArrow**********************************/ void XmeDrawArrow(Display *display, Drawable d, GC top_gc, GC bot_gc, GC cent_gc, #if NeedWidePrototypes int x, int y, int width, int height, int shadow_thick, unsigned int direction) #else Position x, Position y, Dimension width, Dimension height, Dimension shadow_thick, unsigned char direction) #endif /* NeedWidePrototypes */ { /* cent_gc might be NULL, which means don't draw anything on the center, but if shadow_thick is 1, then center is not NULL, see in ArrowB */ /* in the current implementation, on shadow_thick = 2, 1 or 0 supported */ static unsigned int allocated = 0; static XRectangle * top = NULL; static XRectangle * cent = NULL; static XRectangle * bot = NULL; XRectangle * rect_tmp; int size, xOffset = 0, yOffset = 0, wwidth, start; register int temp, yy, i, h, w; short t = 0 , b = 0 , c = 0 ; XtAppContext app; if (!d) return ; app = XtDisplayToApplicationContext(display); _XmAppLock(app); /* Get the size and the position and allocate the rectangle lists */ if (width > height) { size = height - 2; xOffset = (width - height) / 2; } else { size = width - 2 ; yOffset = (height - width) / 2; } if (size < 1) { _XmAppUnlock(app); return; } if (allocated < size) { _XmProcessLock(); top = (XRectangle *) XtRealloc ((char*)top, sizeof (XRectangle) * (size/2+6)); cent = (XRectangle *) XtRealloc ((char*)cent, sizeof (XRectangle) * (size/2+6)); bot = (XRectangle *) XtRealloc ((char*)bot, sizeof (XRectangle) * (size/2+6)); allocated = size; _XmProcessUnlock(); } #define SWAP(x,y) temp = x ; x = y; y = temp if (direction == XmARROW_RIGHT || direction == XmARROW_LEFT) { SWAP(xOffset,yOffset) ; } /* Set up a loop to generate the segments. */ wwidth = size; yy = size - 1 + yOffset; start = 1 + xOffset; _XmProcessLock(); while (wwidth > 0) { if (wwidth == 1) { top[t].x = start; top[t].y = yy + 1; top[t].width = 1; top[t].height = 1; t++; } else if (wwidth == 2) { if (size == 2 || (direction == XmARROW_UP || direction == XmARROW_LEFT)) { top[t].x = start; top[t].y = yy; top[t].width = 2; top[t].height = 1; t++; top[t].x = start; top[t].y = yy + 1; top[t].width = 1; top[t].height = 1; t++; bot[b].x = start + 1; bot[b].y = yy + 1; bot[b].width = 1; bot[b].height = 1; b++; } } else { if (start == 1 + xOffset) { if (direction == XmARROW_UP || direction == XmARROW_LEFT) { top[t].x = start; top[t].y = yy; top[t].width = 2; top[t].height = 1; t++; top[t].x = start; top[t].y = yy + 1; top[t].width = 1; top[t].height = 1; t++; bot[b].x = start + 1; bot[b].y = yy + 1; bot[b].width = 1; bot[b].height = 1; b++; bot[b].x = start + 2; bot[b].y = yy; bot[b].width = wwidth - 2; bot[b].height = 2; b++; } else { top[t].x = start; top[t].y = yy; top[t].width = 2; top[t].height = 1; t++; bot[b].x = start; bot[b].y = yy + 1; bot[b].width = 2; bot[b].height = 1; b++; bot[b].x = start + 2; bot[b].y = yy; bot[b].width = wwidth - 2; bot[b].height = 2; b++; } } else { top[t].x = start; top[t].y = yy; top[t].width = 2; top[t].height = 2; t++; bot[b].x = start + wwidth - 2; bot[b].y = yy; bot[b].width = 2; bot[b].height = 2; if (wwidth == 3) { bot[b].width = 1; bot[b].x += 1; } b++; if (wwidth > 4) { cent[c].x = start + 2; cent[c].y = yy; cent[c].width = wwidth - 4; cent[c].height = 2; c++; } } } start++; wwidth -= 2; yy -= 2; } if (direction == XmARROW_DOWN || direction == XmARROW_RIGHT) { rect_tmp = top; top = bot; bot = rect_tmp; SWAP(t, b); } /* Transform the "up" pointing arrow to the correct direction */ switch (direction) { case XmARROW_LEFT: i = -1; do { i++; if (i < t) { SWAP(top[i].y, top[i].x); SWAP(top[i].width, top[i].height); } if (i < b) { SWAP(bot[i].y, bot[i].x); SWAP(bot[i].width, bot[i].height); } if (i < c) { SWAP(cent[i].y, cent[i].x); SWAP(cent[i].width, cent[i].height); } } while (i < t || i < b || i < c); break; case XmARROW_RIGHT: h = height - 2; w = width - 2; i = -1; do { i++; if (i < t) { SWAP(top[i].y, top[i].x); SWAP(top[i].width, top[i].height); top[i].x = w - top[i].x - top[i].width + 2; top[i].y = h - top[i].y - top[i].height + 2; } if (i < b) { SWAP(bot[i].y, bot[i].x); SWAP(bot[i].width, bot[i].height); bot[i].x = w - bot[i].x - bot[i].width + 2; bot[i].y = h - bot[i].y - bot[i].height + 2; } if (i < c) { SWAP(cent[i].y, cent[i].x); SWAP(cent[i].width, cent[i].height); cent[i].x = w - cent[i].x - cent[i].width + 2; cent[i].y = h - cent[i].y - cent[i].height + 2; } } while (i < t || i < b || i < c); break; case XmARROW_DOWN: w = width - 2; h = height - 2; i = -1; do { i++; if (i < t) { top[i].x = w - top[i].x - top[i].width + 2; top[i].y = h - top[i].y - top[i].height + 2; } if (i < b) { bot[i].x = w - bot[i].x - bot[i].width + 2; bot[i].y = h - bot[i].y - bot[i].height + 2; } if (i < c) { cent[i].x = w - cent[i].x - cent[i].width + 2; cent[i].y = h - cent[i].y - cent[i].height + 2; } } while (i < t || i < b || i < c); break; } if (x != 0 || y != 0) { for (i = 0; i < t; i++) { top[i].x += x; top[i].y += y; } for (i = 0; i < c; i++) { cent[i].x += x; cent[i].y += y; } for (i = 0; i < b; i++) { bot[i].x += x; bot[i].y += y; } } if (shadow_thick) { /* 1 or 2 shadow thickness: always draw 2 thickness at that point, we'll correct it later */ XFillRectangles (display, d, top_gc, top, t); XFillRectangles (display, d, bot_gc, bot, b); } else { /* handle the case where arrow shadow_thickness = 0, which give a flat arrow: draw the shadow area with the center color */ if (cent_gc) { XFillRectangles (display, d, cent_gc, top, t); XFillRectangles (display, d, cent_gc, bot, b); } } if (shadow_thick == 1) { /* we already drawn the shadow of 2, now let's draw a bigger center area: ask for a smaller arrow with flat look */ XmeDrawArrow(display, d, top_gc, bot_gc, cent_gc, x+1, y+1, width-2, height-2, 0, direction) ; } else if (cent_gc) XFillRectangles (display, d, cent_gc, cent, c); _XmProcessUnlock(); _XmAppUnlock(app); }