/*
* Grace - GRaphing, Advanced Computation and Exploration of data
*
* Home page: http://plasma-gate.weizmann.ac.il/Grace/
*
* Copyright (c) 1991-1995 Paul J Turner, Portland, OR
* Copyright (c) 1996-2000 Grace Development Team
*
* Maintained by Evgeny Stambulchik
*
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
*
* event handler
*
*/
#include <config.h>
#include <cmath.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "globals.h"
#include "events.h"
#include "utils.h"
#include "graphs.h"
#include "draw.h"
#include "graphutils.h"
#include "x11drv.h"
#include "plotone.h"
#include "protos.h"
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/keysym.h>
#include "motifinc.h"
extern Widget loclab;
extern Widget arealab;
extern Widget perimlab;
int cursortype = 0;
static VPoint anchor_vp = {0.0, 0.0};
static int x, y; /* pointer coordinates */
static int anchor_x = 0;
static int anchor_y = 0;
static view bb;
static int move_dir;
static int action_flag = 0;
extern int regiontype;
/*
* for region, area and perimeter computation
*/
#define MAX_POLY_POINTS 200
static int region_pts = 0;
static int iax[MAX_POLY_POINTS];
static int iay[MAX_POLY_POINTS];
static WPoint region_wps[MAX_POLY_POINTS];
void anchor_point(int curx, int cury, VPoint curvp)
{
anchor_vp = curvp;
anchor_x = curx;
anchor_y = cury;
}
void my_proc(Widget parent, XtPointer data, XEvent *event)
{
char keybuf;
KeySym keys;
XComposeStatus compose;
static Time lastc = 0; /* time of last mouse click */
Boolean dbl_click;
WPoint wp, wp_new;
VPoint vp;
VVector shift;
view v;
int cg, newg, loc;
int track_setno;
static int track_loc;
int add_at;
static int type, id; /* for objects */
int axisno;
Datapoint dpoint;
GLocator locator;
cg = get_cg();
get_tracking_props(&track_setno, &move_dir, &add_at);
switch (event->type) {
case MotionNotify:
x = event->xmotion.x;
y = event->xmotion.y;
if (cursortype != 0) {
crosshair_motion(x, y);
}
vp = xlibdev2VPoint(x, y);
getpoints(&vp);
if (focus_policy == FOCUS_FOLLOWS) {
if ((newg = next_graph_containing(-1, vp)) != cg) {
switch_current_graph(newg);
cg = newg;
}
}
switch (action_flag) {
case DO_NOTHING:
break;
case VIEW_2ND:
case ZOOM_2ND:
case ZOOMX_2ND:
case ZOOMY_2ND:
case MAKE_BOX_2ND:
case MAKE_ELLIP_2ND:
select_region(anchor_x, anchor_y, x, y, 1);
break;
case MOVE_OBJECT_2ND:
case COPY_OBJECT2ND:
case PLACE_LEGEND_2ND:
case PLACE_TIMESTAMP_2ND:
slide_region(bb, x - anchor_x, y - anchor_y, 1);
break;
case MAKE_LINE_2ND:
case DEF_REGION2ND:
select_line(anchor_x, anchor_y, x, y, 1);
break;
case DEF_REGION:
if (region_pts > 0) {
select_line(anchor_x, anchor_y, x, y, 1);
}
break;
case MOVE_POINT2ND:
switch (move_dir) {
case MOVE_POINT_XY:
select_line(anchor_x, anchor_y, x, y, 1);
break;
case MOVE_POINT_X:
select_line(x, anchor_y, anchor_x, anchor_y, 1);
break;
case MOVE_POINT_Y:
select_line(anchor_x, anchor_y, anchor_x, y, 1);
break;
}
break;
default:
return;
break;
}
break;
case ButtonPress:
x = event->xbutton.x;
y = event->xbutton.y;
vp = xlibdev2VPoint(x, y);
getpoints(&vp);
switch (event->xbutton.button) {
case Button1:
/* first, determine if it's double click */
if (((XButtonEvent *) event)->time - lastc < CLICKINT) {
dbl_click = True;
} else {
dbl_click = False;
}
lastc = ((XButtonEvent *) event)->time;
switch (action_flag) {
case 0:
if (dbl_click == True && allow_dc == TRUE) {
track_setno = -1;
if (focus_clicked(cg, vp, &anchor_vp) == TRUE) {
xlibVPoint2dev(anchor_vp, &anchor_x, &anchor_y);
set_action(VIEW_2ND);
select_region(anchor_x, anchor_y, x, y, 0);
} else if (find_point(cg, vp, &track_setno, &loc) == RETURN_SUCCESS) {
define_symbols_popup((void *) track_setno);
} else if (axis_clicked(cg, vp, &axisno) == TRUE) {
create_axes_dialog(axisno);
} else if (title_clicked(cg, vp) == TRUE) {
create_graphapp_frame(cg);
} else if (legend_clicked(cg, vp, &bb) == TRUE) {
create_graphapp_frame(cg);
} else if (find_item(cg, vp, &bb, &type, &id) == RETURN_SUCCESS) {
object_edit_popup(type, id);
} else if (timestamp_clicked(vp, &bb) == TRUE) {
create_plot_frame();
} else if (graph_clicked(cg, vp) == TRUE) {
define_symbols_popup((void *) -1);
}
} else {
if (focus_policy == FOCUS_CLICK) {
if ((newg = next_graph_containing(cg, vp)) != cg) {
switch_current_graph(newg);
}
}
}
break;
case VIEW_2ND:
set_action(DO_NOTHING);
v.xv1 = MIN2(vp.x, anchor_vp.x);
v.yv1 = MIN2(vp.y, anchor_vp.y);
v.xv2 = MAX2(vp.x, anchor_vp.x);
v.yv2 = MAX2(vp.y, anchor_vp.y);
set_graph_viewport(cg, v);
update_view(cg);
xdrawgraph();
break;
case ZOOM_1ST:
anchor_point(x, y, vp);
set_action(ZOOM_2ND);
select_region(anchor_x, anchor_y, x, y, 0);
break;
case ZOOMX_1ST:
anchor_point(x, y, vp);
set_action(ZOOMX_2ND);
select_region(anchor_x, anchor_y, x, y, 0);
break;
case ZOOMY_1ST:
anchor_point(x, y, vp);
set_action(ZOOMY_2ND);
select_region(anchor_x, anchor_y, x, y, 0);
break;
case VIEW_1ST:
anchor_point(x, y, vp);
set_action(VIEW_2ND);
select_region(anchor_x, anchor_y, x, y, 0);
break;
case ZOOM_2ND:
set_action(DO_NOTHING);
newworld(cg, ALL_AXES, anchor_vp, vp);
break;
case ZOOMX_2ND:
set_action(DO_NOTHING);
newworld(cg, ALL_X_AXES, anchor_vp, vp);
break;
case ZOOMY_2ND:
set_action(DO_NOTHING);
newworld(cg, ALL_Y_AXES, anchor_vp, vp);
break;
case EDIT_OBJECT:
if (find_item(cg, vp, &bb, &type, &id) == RETURN_SUCCESS) {
object_edit_popup(type, id);
}
break;
case DEL_OBJECT:
if (find_item(cg, vp, &bb, &type, &id) == RETURN_SUCCESS) {
if (yesno("Kill the object?", NULL, NULL, NULL) == TRUE) {
kill_object(type, id);
xdrawgraph();
}
}
break;
case MOVE_OBJECT_1ST:
if (find_item(cg, vp, &bb, &type, &id) == RETURN_SUCCESS) {
anchor_point(x, y, vp);
slide_region(bb, x - anchor_x, y - anchor_y, 0);
set_action(MOVE_OBJECT_2ND);
}
break;
case MOVE_OBJECT_2ND:
shift.x = vp.x - anchor_vp.x;
shift.y = vp.y - anchor_vp.y;
move_object(type, id, shift);
xdrawgraph();
set_action(MOVE_OBJECT_1ST);
break;
case COPY_OBJECT1ST:
if (find_item(cg, vp, &bb, &type, &id) == RETURN_SUCCESS) {
anchor_point(x, y, vp);
slide_region(bb, x - anchor_x, y - anchor_y, 0);
set_action(COPY_OBJECT2ND);
}
break;
case COPY_OBJECT2ND:
shift.x = vp.x - anchor_vp.x;
shift.y = vp.y - anchor_vp.y;
id = duplicate_object(type, id);
move_object(type, id, shift);
xdrawgraph();
set_action(COPY_OBJECT1ST);
break;
case STR_LOC:
id = next_string();
init_string(id, vp);
object_edit_popup(OBJECT_STRING, id);
break;
case MAKE_LINE_1ST:
anchor_point(x, y, vp);
select_line(anchor_x, anchor_y, x, y, 0);
set_action(MAKE_LINE_2ND);
break;
case MAKE_LINE_2ND:
select_line(anchor_x, anchor_y, x, y, 0);
id = next_line();
init_line(id, anchor_vp, vp);
xdrawgraph();
set_action(MAKE_LINE_1ST);
break;
case MAKE_BOX_1ST:
anchor_point(x, y, vp);
select_region(anchor_x, anchor_y, x, y, 0);
set_action(MAKE_BOX_2ND);
break;
case MAKE_BOX_2ND:
select_region(anchor_x, anchor_y, x, y, 0);
id = next_box();
init_box(id, anchor_vp, vp);
xdrawgraph();
set_action(MAKE_BOX_1ST);
break;
case MAKE_ELLIP_1ST:
anchor_point(x, y, vp);
select_region(anchor_x, anchor_y, x, y, 0);
set_action(MAKE_ELLIP_2ND);
break;
case MAKE_ELLIP_2ND:
select_region(anchor_x, anchor_y, x, y, 0);
id = next_ellipse();
init_ellipse(id, anchor_vp, vp);
xdrawgraph();
set_action(MAKE_ELLIP_1ST);
break;
case AUTO_NEAREST:
if (find_point(cg, vp, &track_setno, &loc) == RETURN_SUCCESS) {
autoscale_byset(cg, track_setno, AUTOSCALE_XY);
update_ticks(cg);
xdrawgraph();
set_action(DO_NOTHING);
}
break;
case TRACKER:
track_point(cg, track_setno, &track_loc, -1);
break;
case DEL_POINT:
if (find_point(cg, vp, &track_setno, &loc) == RETURN_SUCCESS) {
del_point(cg, track_setno, loc);
update_set_lists(cg);
xdrawgraph();
}
break;
case MOVE_POINT1ST:
if (find_point(cg, vp, &track_setno, &track_loc) == RETURN_SUCCESS) {
anchor_point(x, y, vp);
get_point(cg, track_setno, track_loc, &wp);
select_line(anchor_x, anchor_y, x, y, 0);
set_action(MOVE_POINT2ND);
}
break;
case MOVE_POINT2ND:
if (is_valid_setno(cg, track_setno)) {
get_point(cg, track_setno, track_loc, &wp);
view2world(vp.x, vp.y, &wp_new.x, &wp_new.y);
switch (move_dir) {
case 0:
wp = wp_new;
break;
case 1:
wp.x = wp_new.x;
break;
case 2:
wp.y = wp_new.y;
break;
}
set_point(cg, track_setno, track_loc, wp);
update_point_locator(cg, track_setno, track_loc);
xdrawgraph();
set_action(MOVE_POINT1ST);
}
break;
case ADD_POINT:
view2world(vp.x, vp.y, &wp.x, &wp.y);
zero_datapoint(&dpoint);
dpoint.ex[0] = wp.x;
dpoint.ex[1] = wp.y;
switch (add_at) {
case ADD_POINT_BEGINNING: /* at the beginning */
loc = 0;
break;
case ADD_POINT_END: /* at the end */
loc = getsetlength(cg, track_setno);
break;
default: /* between nearest points */
loc = find_insert_location(cg, track_setno, vp);
break;
}
if (add_point_at(cg, track_setno, loc, &dpoint)
== RETURN_SUCCESS) {
update_set_lists(cg);
xdrawgraph();
}
break;
case PLACE_LEGEND_1ST:
if (legend_clicked(cg, vp, &bb) == TRUE) {
anchor_point(x, y, vp);
slide_region(bb, x - anchor_x, y - anchor_y, 0);
set_action(PLACE_LEGEND_2ND);
}
break;
case PLACE_LEGEND_2ND:
shift.x = vp.x - anchor_vp.x;
shift.y = vp.y - anchor_vp.y;
move_legend(cg, shift);
updatelegends(cg);
xdrawgraph();
set_action(PLACE_LEGEND_1ST);
break;
case PLACE_TIMESTAMP_1ST:
if (timestamp_clicked(vp, &bb) == TRUE) {
anchor_point(x, y, vp);
slide_region(bb, x - anchor_x, y - anchor_y, 0);
set_action(PLACE_TIMESTAMP_2ND);
}
break;
case PLACE_TIMESTAMP_2ND:
shift.x = vp.x - anchor_vp.x;
shift.y = vp.y - anchor_vp.y;
move_timestamp(shift);
xdrawgraph();
set_action(PLACE_TIMESTAMP_1ST);
break;
case SEL_POINT:
if (get_graph_locator(cg, &locator) == RETURN_SUCCESS) {
view2world(vp.x, vp.y, &locator.dsx, &locator.dsy);
locator.pointset = TRUE;
set_graph_locator(cg, &locator);
update_locator_items(cg);
xdrawgraph();
}
set_action(DO_NOTHING);
break;
case DEF_REGION1ST:
anchor_point(x, y, vp);
select_line(anchor_x, anchor_y, x, y, 0);
set_action(DEF_REGION2ND);
break;
case DEF_REGION2ND:
set_action(DO_NOTHING);
select_line(anchor_x, anchor_y, x, y, 0);
activate_region(nr, regiontype, cg);
view2world(anchor_vp.x, anchor_vp.y, &rg[nr].x1, &rg[nr].y1);
view2world(vp.x, vp.y, &rg[nr].x2, &rg[nr].y2);
xdrawgraph();
break;
case DEF_REGION:
anchor_point(x, y, vp);
iax[region_pts] = x;
iay[region_pts] = y;
view2world(vp.x, vp.y,
®ion_wps[region_pts].x, ®ion_wps[region_pts].y);
if (region_pts < MAX_POLY_POINTS) {
region_pts++;
} else {
errmsg("Too many points in polygon!");
}
select_line(anchor_x, anchor_y, x, y, 0);
break;
default:
break;
}
break;
case Button2:
switch (action_flag) {
case TRACKER:
track_setno = -1;
if (find_point(cg, vp, &track_setno, &track_loc) == RETURN_SUCCESS) {
track_point(cg, track_setno, &track_loc, 0);
} else {
update_point_locator(cg, track_setno, track_loc);
}
break;
default:
break;
}
break;
case Button3:
switch (action_flag) {
case DO_NOTHING:
/*
* find_item(cg, vp, &anchor_vp, &type, &id);
* sprintf(buf, "type = %d, id = %d", type, id);
* set_left_footer(buf);
*/
break;
case TRACKER:
track_point(cg, track_setno, &track_loc, +1);
break;
case DEF_REGION:
/* end region definition */
select_line(x, y, iax[0], iay[0], 0);
load_poly_region(nr, cg, region_pts, region_wps);
set_action(DO_NOTHING);
xdrawgraph();
break;
default:
set_action(DO_NOTHING);
break;
}
return;
default: /* TODO: wheel mice */
break;
}
break;
case KeyPress:
XLookupString((XKeyEvent *) event, &keybuf, 1, &keys, &compose);
if (keybuf == 27) { /* Esc */
set_action(DO_NOTHING);
return;
}
break;
default:
break;
}
}
/*
* action callback
*/
void set_actioncb(void *data)
{
int func = (int) data;
set_action(DO_NOTHING);
set_action(func);
}
/*
* set the action_flag to the desired action (actions are
* defined in defines.h), if 0 then cleanup the results
* from previous actions.
*/
void set_action(CanvasAction act)
{
int i;
/*
* indicate what's happening with a message in the left footer
*/
switch (act) {
case 0:
switch (action_flag) {
case ZOOM_2ND:
case ZOOMX_2ND:
case ZOOMY_2ND:
case VIEW_2ND:
select_region(anchor_x, anchor_y, x, y, 0);
break;
case MOVE_OBJECT_2ND:
case COPY_OBJECT2ND:
case PLACE_LEGEND_2ND:
case PLACE_TIMESTAMP_2ND:
slide_region(bb, x - anchor_x, y - anchor_y, 0);
break;
case MAKE_LINE_2ND:
case DEF_REGION2ND:
select_line(anchor_x, anchor_y, x, y, 0);
break;
case DEF_REGION:
select_line(anchor_x, anchor_y, x, y, 0);
for (i = 0; i < region_pts - 1; i++) {
select_line(iax[i], iay[i], iax[i + 1], iay[i + 1], 0);
}
break;
case MOVE_POINT2ND:
switch (move_dir) {
case 0:
select_line(anchor_x, anchor_y, x, y, 0);
break;
case 1:
select_line(anchor_x, anchor_y, x, anchor_y, 0);
break;
case 2:
select_line(anchor_x, anchor_y, anchor_x, y, 0);
break;
}
break;
default:
break;
}
set_cursor(-1);
set_left_footer(NULL);
break;
case ZOOM_1ST:
set_cursor(0);
set_left_footer("Pick first corner for zoom");
break;
case ZOOM_2ND:
set_left_footer("Pick second corner for zoom");
break;
case ZOOMX_1ST:
set_cursor(0);
set_left_footer("Pick first point for zoom along X-axis");
break;
case ZOOMX_2ND:
set_left_footer("Pick second point for zoom along X-axis");
break;
case ZOOMY_1ST:
set_cursor(0);
set_left_footer("Pick first point for zoom along Y-axis");
break;
case ZOOMY_2ND:
set_left_footer("Pick second point for zoom along Y-axis");
break;
case VIEW_1ST:
set_cursor(0);
set_left_footer("Pick first corner of viewport");
break;
case VIEW_2ND:
set_left_footer("Pick second corner of viewport");
break;
case EDIT_OBJECT:
set_cursor(1);
set_left_footer("Pick object to edit");
break;
case DEL_OBJECT:
set_cursor(3);
set_left_footer("Delete object");
break;
case MOVE_OBJECT_1ST:
set_cursor(1);
set_left_footer("Pick object to move");
break;
case COPY_OBJECT1ST:
set_cursor(1);
set_left_footer("Pick object to copy");
break;
case MOVE_OBJECT_2ND:
case COPY_OBJECT2ND:
set_cursor(4);
set_left_footer("Place object");
break;
case STR_LOC:
set_cursor(2);
set_left_footer("Pick beginning of text");
break;
case MAKE_LINE_1ST:
set_cursor(0);
set_left_footer("Pick beginning of line");
break;
case MAKE_LINE_2ND:
set_left_footer("Pick end of line");
break;
case MAKE_BOX_1ST:
set_cursor(0);
set_left_footer("First corner of box");
break;
case MAKE_BOX_2ND:
set_left_footer("Second corner of box");
break;
case MAKE_ELLIP_1ST:
set_cursor(0);
set_left_footer("Pick beginning of bounding box for ellipse");
break;
case MAKE_ELLIP_2ND:
set_left_footer("Pick opposite corner");
break;
case AUTO_NEAREST:
set_cursor(0);
set_left_footer("Autoscale on nearest set - click near a point of the set to autoscale");
break;
case TRACKER:
set_cursor(1);
set_left_footer("Tracker");
break;
case DEL_POINT:
set_cursor(3);
set_left_footer("Delete point");
break;
case MOVE_POINT1ST:
set_cursor(4);
set_left_footer("Pick point to move");
break;
case MOVE_POINT2ND:
set_left_footer("Pick final location");
break;
case ADD_POINT:
set_cursor(0);
set_left_footer("Add point");
break;
case PLACE_LEGEND_1ST:
set_cursor(1);
set_left_footer("Pick legend");
break;
case PLACE_LEGEND_2ND:
set_cursor(4);
set_left_footer("Move legend");
break;
case PLACE_TIMESTAMP_1ST:
set_cursor(1);
set_left_footer("Pick timestamp");
break;
case PLACE_TIMESTAMP_2ND:
set_cursor(4);
set_left_footer("Place timestamp");
break;
case SEL_POINT:
set_cursor(0);
set_left_footer("Pick reference point");
break;
case DEF_REGION1ST:
set_cursor(0);
set_left_footer("Pick first point for region");
break;
case DEF_REGION2ND:
set_left_footer("Pick second point for region");
break;
case DEF_REGION:
set_cursor(0);
set_left_footer("Define region");
break;
case COMP_AREA:
set_cursor(0);
set_left_footer("Compute area");
break;
case COMP_PERIMETER:
set_cursor(0);
set_left_footer("Compute perimeter");
break;
case DISLINE1ST:
set_cursor(0);
set_left_footer("Pick start of line for distance computation");
break;
case DISLINE2ND:
set_cursor(0);
set_left_footer("Pick ending point");
break;
}
action_flag = act;
}
void track_point(int gno, int setno, int *loc, int shift)
{
int len;
double *xtmp, *ytmp;
WPoint wp;
VPoint vp;
world w;
if ((len = getsetlength(gno, setno)) > 0) {
*loc += shift;
if (*loc < 0) {
*loc += len;
} else {
*loc = *loc % len;
}
xtmp = getx(gno, setno);
ytmp = gety(gno, setno);
wp.x = xtmp[*loc];
wp.y = ytmp[*loc];
get_graph_world(gno, &w);
wp.x = MAX2(wp.x, w.xg1);
wp.x = MIN2(wp.x, w.xg2);
wp.y = MAX2(wp.y, w.yg1);
wp.y = MIN2(wp.y, w.yg2);
vp = Wpoint2Vpoint(wp);
setpointer(vp);
update_point_locator(gno, setno, *loc);
}
}
/*
* set format string for locator
*/
static char *typestr[6] = {"X, Y",
"DX, DY",
"DIST",
"Phi, Rho",
"VX, VY",
"SX, SY"};
/*
* locator on main_panel
*/
void getpoints(VPoint *vpp)
{
static VPoint vp = {0.0, 0.0};
int cg = get_cg();
double wx, wy, xtmp, ytmp;
int x, y;
double dsx = 0.0, dsy = 0.0;
char buf[256], bufx[64], bufy[64], *s;
GLocator locator;
if (vpp != NULL) {
vp = *vpp;
}
view2world(vp.x, vp.y, &wx, &wy);
if (get_graph_locator(cg, &locator) != RETURN_SUCCESS) {
SetLabel(loclab, "[No graphs]");
return;
}
if (locator.pointset) {
dsx = locator.dsx;
dsy = locator.dsy;
}
switch (locator.pt_type) {
case 0:
if (get_graph_type(cg) == GRAPH_POLAR) {
polar2xy(wx, wy, &xtmp, &ytmp);
} else {
xtmp = wx;
ytmp = wy;
}
break;
case 1:
xtmp = wx - dsx;
ytmp = wy - dsy;
break;
case 2:
if (get_graph_type(cg) == GRAPH_POLAR) {
polar2xy(wx, wy, &xtmp, &ytmp);
} else {
xtmp = wx;
ytmp = wy;
}
xtmp = hypot(dsx - xtmp, dsy - ytmp);
ytmp = 0.0;
break;
case 3:
if (dsx - wx != 0.0 || dsy - wy != 0.0) {
xy2polar(wx - dsx, wy - dsy, &xtmp, &ytmp);
} else {
xtmp = 0.0;
ytmp = 0.0;
}
break;
case 4:
xtmp = vp.x;
ytmp = vp.y;
break;
case 5:
xlibVPoint2dev(vp, &x, &y);
xtmp = x;
ytmp = y;
break;
default:
return;
}
s = create_fstring(locator.fx, locator.px, xtmp, LFORMAT_TYPE_PLAIN);
strcpy(bufx, s);
s = create_fstring(locator.fy, locator.py, ytmp, LFORMAT_TYPE_PLAIN);
strcpy(bufy, s);
sprintf(buf, "G%1d: %s = [%s, %s]", cg, typestr[locator.pt_type], bufx, bufy);
SetLabel(loclab, buf);
}
/*
* switch on the area calculator
*/
void do_select_area(void)
{
set_action(DO_NOTHING);
set_action(COMP_AREA);
}
/*
* switch on the perimeter calculator
*/
void do_select_peri(void)
{
set_action(DO_NOTHING);
set_action(COMP_PERIMETER);
}
void do_dist_proc(void)
{
set_action(DO_NOTHING);
set_action(DISLINE1ST);
}
/*
* define a (polygon) region
*/
void do_select_region(void)
{
region_pts = 0;
set_action(DO_NOTHING);
set_action(DEF_REGION);
}
/*
* Given the graph gno, find the graph that contains
* (wx, wy). Used for setting the graph focus.
*/
int next_graph_containing(int cg, VPoint vp)
{
int i, j, ng, gno = -1;
view v;
ng = number_of_graphs();
if (is_valid_gno(cg) == FALSE) {
cg = -1;
}
for (i = 0; i < ng ; i++) {
j = (i + cg + 1) % ng;
if (is_graph_hidden(j) == FALSE &&
get_graph_viewport(j, &v) == RETURN_SUCCESS &&
is_vpoint_inside(v, vp, MAXPICKDIST) == TRUE) {
gno = j;
break;
}
}
return gno;
}
int legend_clicked(int gno, VPoint vp, view *bb)
{
legend l;
if (is_graph_hidden(gno) == FALSE) {
get_graph_legend(gno, &l);
if (l.active && is_vpoint_inside(l.bb, vp, MAXPICKDIST)) {
*bb = l.bb;
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
int graph_clicked(int gno, VPoint vp)
{
view v;
if (is_graph_hidden(gno) == FALSE) {
get_graph_viewport(gno, &v);
if (is_vpoint_inside(v, vp, MAXPICKDIST)) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
int timestamp_clicked(VPoint vp, view *bb)
{
if (timestamp.active && is_vpoint_inside(timestamp.bb, vp, MAXPICKDIST)) {
*bb = timestamp.bb;
return TRUE;
} else {
return FALSE;
}
}
int focus_clicked(int cg, VPoint vp, VPoint *avp)
{
view v;
if (is_graph_hidden(cg) == TRUE) {
return FALSE;
}
if (get_graph_viewport(cg, &v) != RETURN_SUCCESS) {
return FALSE;
}
if (fabs(vp.x - v.xv1) < MAXPICKDIST && fabs(vp.y - v.yv1) < MAXPICKDIST) {
avp->x = v.xv2;
avp->y = v.yv2;
return TRUE;
} else if (fabs(vp.x - v.xv1) < MAXPICKDIST && fabs(vp.y - v.yv2) < MAXPICKDIST) {
avp->x = v.xv2;
avp->y = v.yv1;
return TRUE;
} else if (fabs(vp.x - v.xv2) < MAXPICKDIST && fabs(vp.y - v.yv1) < MAXPICKDIST) {
avp->x = v.xv1;
avp->y = v.yv2;
return TRUE;
} else if (fabs(vp.x - v.xv2) < MAXPICKDIST && fabs(vp.y - v.yv2) < MAXPICKDIST) {
avp->x = v.xv1;
avp->y = v.yv1;
return TRUE;
} else {
return FALSE;
}
}
int axis_clicked(int gno, VPoint vp, int *axisno)
{
view v;
/* TODO: check for offsets, zero axes, polar graphs */
if (is_graph_hidden(gno) == TRUE) {
return FALSE;
} else {
get_graph_viewport(gno, &v);
if (vp.x >= v.xv1 && vp.x <= v.xv2 &&
(fabs(vp.y - v.yv1) < MAXPICKDIST ||
fabs(vp.y - v.yv2) < MAXPICKDIST)) {
*axisno = X_AXIS;
return TRUE;
} else if (vp.y >= v.yv1 && vp.y <= v.yv2 &&
(fabs(vp.x - v.xv1) < MAXPICKDIST ||
fabs(vp.x - v.xv2) < MAXPICKDIST)) {
*axisno = Y_AXIS;
return TRUE;
} else {
return FALSE;
}
}
}
int title_clicked(int gno, VPoint vp)
{
view v;
/* a rude check; TODO: use right offsets */
if (is_graph_hidden(gno) == TRUE) {
return FALSE;
} else {
get_graph_viewport(gno, &v);
if (vp.x >= v.xv1 && vp.x <= v.xv2 &&
vp.y > v.yv2 && vp.y < v.yv2 + 0.1) {
return TRUE;
} else {
return FALSE;
}
}
}
/*
* locate a point and the set the point is in
*/
int find_point(int gno, VPoint vp, int *setno, int *loc)
{
int i, start, stop, j, found;
double *xtmp, *ytmp;
WPoint wptmp;
VPoint vptmp;
double dist, mindist = MAXPICKDIST;
if (is_valid_gno(gno) != TRUE) {
return RETURN_FAILURE;
}
if (is_valid_setno(gno, *setno)) {
start = *setno;
stop = *setno;
} else {
start = 0;
stop = number_of_sets(gno) - 1;
}
found = FALSE;
for (i = start; i <= stop; i++) {
if (is_set_hidden(gno, i) == FALSE) {
xtmp = getx(gno, i);
ytmp = gety(gno, i);
for (j = 0; j < getsetlength(gno, i); j++) {
wptmp.x = xtmp[j];
wptmp.y = ytmp[j];
vptmp = Wpoint2Vpoint(wptmp);
dist = MAX2(fabs(vp.x - vptmp.x), fabs(vp.y - vptmp.y));
if (dist < mindist) {
found = TRUE;
*setno = i;
*loc = j;
mindist = dist;
}
}
}
}
if (found == FALSE) {
return RETURN_FAILURE;
} else {
update_point_locator(gno, *setno, *loc);
return RETURN_SUCCESS;
}
}
int find_insert_location(int gno, int setno, VPoint vp)
{
int j, loc = -1;
double *xtmp, *ytmp;
WPoint wptmp;
VPoint vp1, vp2;
double dist, mindist = 1.0;
if (is_valid_setno(gno, setno) == TRUE) {
if (is_set_hidden(gno, setno) == FALSE) {
xtmp = getx(gno, setno);
ytmp = gety(gno, setno);
for (j = 0; j < getsetlength(gno, setno) - 1; j++) {
wptmp.x = xtmp[j];
wptmp.y = ytmp[j];
vp1 = Wpoint2Vpoint(wptmp);
wptmp.x = xtmp[j + 1];
wptmp.y = ytmp[j + 1];
vp2 = Wpoint2Vpoint(wptmp);
dist = hypot(vp.x - vp1.x, vp.y - vp1.y) +
hypot(vp.x - vp2.x, vp.y - vp2.y);
if (dist < mindist) {
loc = j + 1;
mindist = dist;
}
}
}
}
return loc;
}
/*
* find object containing vp inside its bb
*/
int find_item(int gno, VPoint vp, view *bb, int *type, int *id)
{
int i;
*type = OBJECT_NONE;
for (i = 0; i < number_of_boxes(); i++) {
if (isactive_box(i)) {
get_object_bb(OBJECT_BOX, i, bb);
if (is_vpoint_inside(*bb, vp, MAXPICKDIST)) {
*type = OBJECT_BOX;
*id = i;
}
}
}
for (i = 0; i < number_of_ellipses(); i++) {
if (isactive_ellipse(i)) {
get_object_bb(OBJECT_ELLIPSE, i, bb);
if (is_vpoint_inside(*bb, vp, MAXPICKDIST)) {
*type = OBJECT_ELLIPSE;
*id = i;
}
}
}
for (i = 0; i < number_of_lines(); i++) {
if (isactive_line(i)) {
get_object_bb(OBJECT_LINE, i, bb);
if (is_vpoint_inside(*bb, vp, MAXPICKDIST)) {
*type = OBJECT_LINE;
*id = i;
}
}
}
for (i = 0; i < number_of_strings(); i++) {
if (isactive_string(i)) {
get_object_bb(OBJECT_STRING, i, bb);
if (is_vpoint_inside(*bb, vp, MAXPICKDIST)) {
*type = OBJECT_STRING;
*id = i;
}
}
}
if (*type == OBJECT_NONE) {
return RETURN_FAILURE;
} else {
get_object_bb(*type, *id, bb);
return RETURN_SUCCESS;
}
}
/*
* for zooms
*
*/
void newworld(int gno, int axes, VPoint vp1, VPoint vp2)
{
world w, wtmp;
if (vp1.x == vp2.x && (axes == ALL_AXES || axes == ALL_X_AXES)) {
errmsg("Zoomed rectangle is zero along X, zoom cancelled");
return;
}
if (vp1.y == vp2.y && (axes == ALL_AXES || axes == ALL_Y_AXES)) {
errmsg("Zoomed rectangle is zero along Y, zoom cancelled");
return;
}
view2world(vp1.x, vp1.y, &w.xg1, &w.yg1);
view2world(vp2.x, vp2.y, &w.xg2, &w.yg2);
if (w.xg1 > w.xg2) {
fswap(&w.xg1, &w.xg2);
}
if (w.yg1 > w.yg2) {
fswap(&w.yg1, &w.yg2);
}
if (is_graph_active(gno)) {
get_graph_world(gno, &wtmp);
switch (axes) {
case ALL_AXES:
wtmp.xg1 = w.xg1;
wtmp.xg2 = w.xg2;
wtmp.yg1 = w.yg1;
wtmp.yg2 = w.yg2;
break;
case ALL_X_AXES:
wtmp.xg1 = w.xg1;
wtmp.xg2 = w.xg2;
break;
case ALL_Y_AXES:
wtmp.yg1 = w.yg1;
wtmp.yg2 = w.yg2;
break;
default:
return;
break;
}
set_graph_world(gno, wtmp);
autotick_axis(gno, axes);
xdrawgraph();
}
}
void switch_current_graph(int gno)
{
int saveg = get_cg();
if (is_graph_hidden(gno) == FALSE) {
select_graph(gno);
draw_focus(saveg);
draw_focus(gno);
update_all();
set_graph_selectors(gno);
getpoints(NULL);
}
}
/* -------------------------------------------------------------- */
/* canvas_actions */
void autoscale_action(Widget w, XKeyEvent *e, String *p, Cardinal *c)
{
int cg = get_cg();
autoscale_graph(cg, AUTOSCALE_XY);
update_ticks(cg);
xdrawgraph();
}
void autoscale_on_near_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(AUTO_NEAREST);
}
void draw_line_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(MAKE_LINE_1ST);
}
void draw_box_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(MAKE_BOX_1ST);
}
void draw_ellipse_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(MAKE_ELLIP_1ST);
}
void write_string_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(STR_LOC);
}
void delete_object_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(DEL_OBJECT);
}
void place_legend_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(PLACE_LEGEND_1ST);
}
void place_timestamp_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(PLACE_TIMESTAMP_1ST);
}
void move_object_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(MOVE_OBJECT_1ST);
}
void refresh_hotlink_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
do_hotupdate_proc(NULL);
}
void set_viewport_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(VIEW_1ST);
}
void enable_zoom_action( Widget w, XKeyEvent *e, String *p, Cardinal *c )
{
set_action(DO_NOTHING);
set_action(ZOOM_1ST);
}
/*
* world stack operations
*/
void push_and_zoom(void)
{
push_world();
set_action(DO_NOTHING);
set_action(ZOOM_1ST);
}
syntax highlighted by Code2HTML, v. 0.9.1