/* $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 <config.h>
#endif
#include "XmI.h"
#include <Xm/DrawP.h>
/****************************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);
}