file: glyphtool.c
/* util.c - routines for glyph brush tool for XmdvTool */
/* Copyright 1994, Matthew O. Ward
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without fee
* is granted provided that the above copyright notice appears in all copies.
* It is provided "as is" without express or implied warranty.
*/
#include <X11/Xatom.h>
#include "XmdvTool.h"
#include "glyph.h"
#include "glyphtool.h"
#include "brush.h"
extern Widget appShell;
extern int dims;
extern char names[MAXDIM][MAXLABEL];
extern double *br_pos, *br_size;
extern double dim_min[MAXDIM], dim_max[MAXDIM];
extern unsigned long color_cells[NUM_COLOR_CELLS];
extern XColor outline_col;
extern GC gc;
/* is this a color display? */
extern int COLOR;
extern int X_SIZE, Y_SIZE;
Arg wargs[10];
int n;
/* glyph brush tool brush variables */
int gbt_open = FALSE;
double gbt_br_pos[MAXDIM], gbt_br_size[MAXDIM];
Dimension gbt_x, gbt_y; /* Glyph Brush Tool X/Y dims */
/* button defines */
#define BUTTON_DOWN 1
#define BUTTON_DRAG 2
#define BUTTON_UP 3
#define BUTTON_CANCEL 4
void GlyphBToolRedrawCanvas(Widget w, caddr_t client_data,
XawDrawingAreaCallbackStruct *call_data)
{
GlyphBToolDoRedraw();
}
/*
* GlyphBToolDoRedraw() - Redraw the entire glyph brush tool
*/
void GlyphBToolDoRedraw(void)
{
Widget gbt_canvas_w; /* the glyph brush tool canvas */
int i;
int n;
Arg wargs[10]; /* widget args */
int center_x, center_y; /* canvas center */
int rad; /* axis radius */
int center_offset; /* radial offset from center */
double angle; /* radial axis angle */
int x,y,x2,y2;
XPoint xpts[MAXDIM*2+2]; /* polyline brush points */
XFontStruct *font; /* the font to draw text with */
unsigned long font_height; /* the height of the font */
int dummy; /* dummy var passed to XTextExtents() */
XCharStruct overall; /* for finding extents */
int label_len; /* the length of a label */
gbt_canvas_w = WcFullNameToWidget(appShell,"*glyph_btool_canvas");
if(!gbt_canvas_w)
{
fprintf(stderr, "Error finding *glyph_btool_canvas\n");
return;
}
/* if brush tool is not open, do nothing */
if(!gbt_open)
return;
/* get the new x/y dimensions of the brush tool */
n = 0;
XtSetArg(wargs[n],XtNwidth,&gbt_x); n++;
XtSetArg(wargs[n],XtNheight,&gbt_y); n++;
XtGetValues(gbt_canvas_w,wargs,n);
center_x = gbt_x/2;
center_y = gbt_y/2;
/* make radius the smallest half width and scale */
rad = MIN(center_x, center_y);
rad *= .65;
/* make the center offset 10% of the width */
center_offset = MIN(center_x, center_y);
center_offset *= .20;
/* clear the canvas */
XClearWindow(XtDisplay(gbt_canvas_w), XtWindow(gbt_canvas_w));
/* draw the brush */
/* add the outside edge points */
for(n=0, i=0, angle=0.; i<dims; i++, angle+=(2.*M_PI)/(double)dims)
{
xpts[n].x = center_x + center_offset * cos(angle);
xpts[n].x += rad * cos(angle) *
(gbt_br_pos[i]+gbt_br_size[i]/2.-dim_min[i])/(dim_max[i] - dim_min[i]);
xpts[n].y = center_y - center_offset * sin(angle);
xpts[n].y -= rad * sin(angle) *
(gbt_br_pos[i]+gbt_br_size[i]/2.-dim_min[i])/(dim_max[i] - dim_min[i]);
n++;
}
/* add the first point again */
xpts[n].x = xpts[0].x;
xpts[n].y = xpts[0].y;
n++;
/* add the inside edge points */
for(i=0, angle=0.; i<dims; i++, angle+=(2.*M_PI)/(double)dims)
{
xpts[n].x = center_x + center_offset * cos(angle);
xpts[n].x += rad * cos(angle) *
(gbt_br_pos[i]-gbt_br_size[i]/2.-dim_min[i])/(dim_max[i] - dim_min[i]);
xpts[n].y = center_y - center_offset * sin(angle);
xpts[n].y -= rad * sin(angle) *
(gbt_br_pos[i]-gbt_br_size[i]/2.-dim_min[i])/(dim_max[i] - dim_min[i]);
n++;
}
/* add the first inside point again */
xpts[n].x = xpts[dims+1].x;
xpts[n].y = xpts[dims+1].y;
n++;
/* set the brush color */
if(COLOR==1)
XSetForeground(XtDisplay(gbt_canvas_w), gc, outline_col.pixel);
/* draw the brush */
XFillPolygon(XtDisplay(gbt_canvas_w), XtWindow(gbt_canvas_w), gc,
xpts, n, Complex, CoordModeOrigin);
/* draw the axes */
/* set the foreground color for drawing axis */
XSetForeground(XtDisplay(gbt_canvas_w), gc, color_cells[CCELL_TEXT]);
/* draw the axes radially from the center */
for(i=0, angle=0.; i<dims; i++, angle+=(2.*M_PI)/(double)dims)
{
x = center_x + center_offset * cos(angle);
y = center_y - center_offset * sin(angle);
xpts[i].x = x;
xpts[i].y = y;
x2 = center_x + (rad + center_offset) * cos(angle);
y2 = center_y - (rad + center_offset) * sin(angle);
XDrawLine(XtDisplay(gbt_canvas_w), XtWindow(gbt_canvas_w),
gc, x, y, x2, y2);
}
/* connect the inner points of the axes */
xpts[i].x = xpts[0].x;
xpts[i].y = xpts[0].y;
i++;
XDrawLines(XtDisplay(gbt_canvas_w), XtWindow(gbt_canvas_w), gc,
xpts, i, CoordModeOrigin);
#define GBT_TEXT_SPACING 4 /* space between axis and text */
#define GBT_TEXT_MAX_LETTERS 3 /* maximum letters in label */
/* draw the labels */
XSetForeground(XtDisplay(gbt_canvas_w),gc, color_cells[CCELL_TEXT]);
/* get the font */
font = XQueryFont(XtDisplay(gbt_canvas_w), XGContextFromGC(gc));
for(i=0, angle=0.; i<dims; i++, angle+=(2.*M_PI)/(double)dims)
{
/* determine the string length */
label_len = MIN(GBT_TEXT_MAX_LETTERS, strlen(names[i]));
/* find the extents of the string */
XTextExtents(font, names[i], label_len, &dummy, &dummy, &dummy,
&overall);
font_height = overall.ascent + overall.descent;
x = center_x + (rad + center_offset) * cos(angle);
y = center_y - (rad + center_offset) * sin(angle);
/* tweak values to center string */
x += (font_height/3.) * sin(angle+M_PI/2.);
y += (font_height/2.) + (font_height/2.) * sin(angle+M_PI);
/* if on the left side, move the text over so it ends at the axis */
if(angle > M_PI/2. && angle < 3.*M_PI/2.)
x -= overall.width;
XDrawString(XtDisplay(gbt_canvas_w), XtWindow(gbt_canvas_w), gc,
x, y, names[i], label_len);
}
}
/* glyph brush tool button flags */
int gbt_button_one_down = FALSE;
int gbt_button_two_down = FALSE;
int gbt_button_three_down = FALSE;
void GlyphBToolMotionCanvas(Widget w, caddr_t client_data,
XawDrawingAreaCallbackStruct *call_data)
{
if(gbt_button_one_down)
{
GlyphBToolInteractiveResize(call_data->event->xmotion.x,
call_data->event->xmotion.y,
BUTTON_DRAG); //OVERLOAD CALL: BUTTON_DRAG: glyphtool.c(?), stacktool.c(?), util.c(?)
}
else if(gbt_button_two_down)
{
GlyphBToolInteractiveMove(call_data->event->xmotion.x,
call_data->event->xmotion.y,
BUTTON_DRAG); //OVERLOAD CALL: BUTTON_DRAG: glyphtool.c(?), stacktool.c(?), util.c(?)
}
else if(gbt_button_three_down)
{
}
}
void GlyphBToolInputCanvas(Widget w, caddr_t client_data,
XawDrawingAreaCallbackStruct *call_data)
{
int x, y;
switch (call_data->event->type)
{
/* Process mouse button events */
case ButtonPress:
x = call_data->event->xbutton.x;
y = call_data->event->xbutton.y;
switch (call_data->event->xbutton.button)
{
case 1: /* the resize button */
if(gbt_button_two_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
GlyphBToolInteractiveMove(x, y, BUTTON_CANCEL); //OVERLOAD CALL: BUTTON_CANCEL: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
}
else if(gbt_button_three_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
break;
}
gbt_button_one_down = TRUE;
GlyphBToolInteractiveResize(x, y, BUTTON_DOWN); //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
case 2: /* the move button */
if(gbt_button_one_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
GlyphBToolInteractiveResize(x, y, BUTTON_CANCEL); //OVERLOAD CALL: BUTTON_CANCEL: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
}
else if(gbt_button_three_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
break;
}
gbt_button_two_down = TRUE;
GlyphBToolInteractiveMove(x, y, BUTTON_DOWN); //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
case 3:
if(gbt_button_one_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
GlyphBToolInteractiveResize(x, y, BUTTON_CANCEL); //OVERLOAD CALL: BUTTON_CANCEL: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
}
else if(gbt_button_two_down)
{
XBell(XtDisplay(w), 0);
gbt_button_one_down = gbt_button_two_down = gbt_button_three_down = FALSE;
GlyphBToolInteractiveMove(x, y, BUTTON_CANCEL); //OVERLOAD CALL: BUTTON_CANCEL: glyphtool.c(?), stacktool.c(?), util.c(?)
break;
}
gbt_button_three_down = TRUE;
break;
}
break;
case ButtonRelease:
x = call_data->event->xbutton.x;
y = call_data->event->xbutton.y;
switch (call_data->event->xbutton.button)
{
case 1:
if(!gbt_button_one_down)
break;
GlyphBToolInteractiveResize(x, y, BUTTON_UP); //OVERLOAD CALL: BUTTON_UP: glyphtool.c(?), stacktool.c(?), util.c(?)
gbt_button_one_down = FALSE;
break;
case 2:
if(!gbt_button_two_down)
break;
GlyphBToolInteractiveMove(x, y, BUTTON_UP); //OVERLOAD CALL: BUTTON_UP: glyphtool.c(?), stacktool.c(?), util.c(?)
gbt_button_two_down = FALSE;
break;
case 3:
if(!gbt_button_three_down)
break;
gbt_button_three_down = FALSE;
break;
}
break;
}
}
void GlyphBToolApply(Widget w, caddr_t client_data, caddr_t call_data)
{
int i;
/* copy the glyph btool brush to the real brush */
for(i=0; i<dims; i++)
{
br_pos[i] = gbt_br_pos[i];
br_size[i] = gbt_br_size[i];
}
do_redraw();
}
void GlyphBToolInit(Widget w, caddr_t client_data, caddr_t call_data)
{
int i;
/* set the global tool open flag */
gbt_open = TRUE;
/* copy the real brush to the glyph btool brush */
for(i=0; i<dims; i++)
{
gbt_br_pos[i] = br_pos[i];
gbt_br_size[i] = br_size[i];
}
}
/*
* GlyphBToolPopDown() - Callback when brush tool is popped down.
*/
void GlyphBToolPopDown(Widget w, caddr_t client_data, caddr_t call_data)
{
/* reset global tool open flag */
gbt_open = FALSE;
}
/*
* GlyphBToolUpdate() - Update the glyph brush tool so that it matches
* the real brush.
*/
void GlyphBToolUpdate(void)
{
int i;
/* if brush tool is not open, do nothing */
if(!gbt_open)
return;
for(i = 0;i < dims;i++) {
gbt_br_pos[i] = br_pos[i];
gbt_br_size[i] = br_size[i];
}
/*
GlyphBToolInit(NULL, NULL, NULL);
*/
GlyphBToolDoRedraw();
}
void GlyphBToolInteractiveMove(int mouse_x, int mouse_y, int button)
{
Widget gbt_canvas_w; /* the glyph brush tool canvas widget */
static int axis; /* axis for resize */
int center_x, center_y, rad; /* brushtool center and axis radius */
int center_offset; /* radial offset from center */
double mouse_angle, angle; /* angle of button press */
double dist; /* distance from center */
double new_pos; /* new brush position */
gbt_canvas_w = WcFullNameToWidget(appShell,"*glyph_btool_canvas");
if(!gbt_canvas_w)
{
fprintf(stderr, "Error finding *glyph_btool_canvas\n");
return;
}
/* find the canvas center */
center_x = gbt_x/2;
center_y = gbt_y/2;
/* make radius the smallest half width and scale */
rad = MIN(center_x, center_y);
rad *= .65;
/* make the center offset 10% of the width */
center_offset = MIN(center_x, center_y);
center_offset *= .20;
/* check if user clicked in center (no man's land) */
if((mouse_x - center_x)*(mouse_x - center_x) +
(mouse_y - center_y)*(mouse_y - center_y) <
(center_offset*.8) * (center_offset*.8))
{
if(button == BUTTON_DOWN) //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
XBell(XtDisplay(gbt_canvas_w), 0);
return;
}
/* find the angle of the line from the center to the mouse */
/* position */
mouse_angle = atan2((double)(center_y-mouse_y), (double)(mouse_x - center_x));
/* if this is a button down, determine axis */
if(button == BUTTON_DOWN) //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
{
/* add a half wedge to the angle */
angle = mouse_angle + ((2.*M_PI)/(double)dims)/2.;
/* wrap angle around if it is negative */
if(angle < 0.)
angle += 2.*M_PI;
/* map angle to an axis */
axis = dims*(angle/(2.*M_PI));
/* sanity check */
if(axis < 0 || axis >= dims)
{
XBell(XtDisplay(gbt_canvas_w), 0);
return;
}
/* store old brush position for later retrieval on cancel */
}
else
{
/* sanity check */
if(axis < 0 || axis >= dims)
return;
}
/* map mouse location to data coordinates */
/* calculate distance from center */
dist = sqrt((double)((center_x-mouse_x)*(center_x-mouse_x) +
(center_y-mouse_y)*(center_y-mouse_y)));
/* normalize */
dist -= center_offset;
dist /= rad;
/* find angle of axis */
angle = axis * (2.*M_PI/(double)dims);
/* calculate new position and bound it */
dist *= cos(mouse_angle - angle);
new_pos = dim_min[axis]+dist*(dim_max[axis]-dim_min[axis]);
new_pos = MIN(new_pos, dim_max[axis]-gbt_br_size[axis]/2.);
new_pos = MAX(new_pos, dim_min[axis]+gbt_br_size[axis]/2.);
/* move brush to new location */
gbt_br_pos[axis] = new_pos;
/* redraw brush tool */
GlyphBToolDoRedraw();
/* if this is a cancel, retrieve the old brush */
}
/*
* GlyphBToolInteractiveResize() - Interactively resize the brush
* using the glyph brush tool
*/
void GlyphBToolInteractiveResize(int mouse_x, int mouse_y, int button)
{
Widget gbt_canvas_w; /* the glyph brush tool canvas widget */
static int axis; /* axis for resize */
int center_x, center_y, rad; /* brushtool center and axis radius */
int center_offset; /* radial offset from center */
double mouse_angle, angle; /* angle of button press */
double dist; /* distance from center */
double new_min, new_max; /* new brush min/max */
double mouse_data; /* mouse in data coords */
static int resize_min, /* resize min/max flags */
resize_max;
gbt_canvas_w = WcFullNameToWidget(appShell,"*glyph_btool_canvas");
if(!gbt_canvas_w)
{
fprintf(stderr, "Error finding *glyph_btool_canvas\n");
return;
}
/* find the canvas center */
center_x = gbt_x/2;
center_y = gbt_y/2;
/* make radius the smallest half width and scale */
rad = MIN(center_x, center_y);
rad *= .65;
/* make the center offset 10% of the width */
center_offset = MIN(center_x, center_y);
center_offset *= .20;
/* check if user clicked in center (no man's land) */
if((mouse_x - center_x)*(mouse_x - center_x) +
(mouse_y - center_y)*(mouse_y - center_y) <
(center_offset*.8) * (center_offset*.8))
{
if(button == BUTTON_DOWN) //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
XBell(XtDisplay(gbt_canvas_w), 0);
return;
}
/* find the angle of the line from the center to the mouse */
/* position */
mouse_angle = atan2((double)(center_y-mouse_y), (double)(mouse_x - center_x));
/* if this is a button down, determine axis */
if(button == BUTTON_DOWN) //OVERLOAD CALL: BUTTON_DOWN: glyphtool.c(?), stacktool.c(?), util.c(?)
{
/* add a half wedge to the angle */
angle = mouse_angle + ((2.*M_PI)/(double)dims)/2.;
/* wrap angle around if it is negative */
if(angle < 0.)
angle += 2.*M_PI;
/* map angle to an axis */
axis = dims*(angle/(2.*M_PI));
/* sanity check */
if(axis < 0 || axis >= dims)
{
XBell(XtDisplay(gbt_canvas_w), 0);
return;
}
/* map mouse location to data coordinates */
/* calculate distance from center */
dist = sqrt((double)((center_x-mouse_x)*(center_x-mouse_x) +
(center_y-mouse_y)*(center_y-mouse_y)));
/* normalize */
dist -= center_offset;
dist /= rad;
/* find angle of axis */
angle = axis * (2.*M_PI/(double)dims);
/* calculate mouse position in data coords and bound it */
dist *= cos(mouse_angle - angle);
mouse_data = dim_min[axis]+dist*(dim_max[axis]-dim_min[axis]);
mouse_data = MIN(mouse_data, dim_max[axis]);
mouse_data = MAX(mouse_data, dim_min[axis]);
/* now determine if min or max is being resized */
resize_min = resize_max = FALSE;
if(mouse_data < gbt_br_pos[axis])
resize_min = TRUE;
else
resize_max = TRUE;
}
else
{
/* sanity check */
if(axis < 0 || axis >= dims)
return;
/* map mouse location to data coordinates */
/* calculate distance from center */
dist = sqrt((double)((center_x-mouse_x)*(center_x-mouse_x) +
(center_y-mouse_y)*(center_y-mouse_y)));
/* normalize */
dist -= center_offset;
dist /= rad;
/* find angle of axis */
angle = axis * (2.*M_PI/(double)dims);
/* calculate mouse position in data coords and bound it */
dist *= cos(mouse_angle - angle);
mouse_data = dim_min[axis]+dist*(dim_max[axis]-dim_min[axis]);
mouse_data = MIN(mouse_data, dim_max[axis]);
mouse_data = MAX(mouse_data, dim_min[axis]);
}
/* resize min or max */
if(resize_min)
{
new_min = mouse_data;
new_max = gbt_br_pos[axis]+gbt_br_size[axis]/2.;
}
else
{
new_min = gbt_br_pos[axis]-gbt_br_size[axis]/2.;
new_max = mouse_data;
}
/* check if min>max */
if(resize_min && new_min > new_max)
new_max = new_min;
if(resize_max && new_min > new_max)
new_min = new_max;
/* assign the new brush */
gbt_br_pos[axis] = (new_min + new_max)/2.;
gbt_br_size[axis] = new_max - new_min;
/* redraw brush tool */
GlyphBToolDoRedraw();
}
C++ to HTML Conversion by ctoohtml