291 lines
9.0 KiB
C
291 lines
9.0 KiB
C
/* File graphevents.c */
|
|
/* This module contains a function to process the events from the graph window */
|
|
|
|
/****************************************************************
|
|
Topograph - A function browser
|
|
Copyright (C) 1996 Marc Culler
|
|
|
|
culler@math.uic.edu
|
|
|
|
Department of Mathematics (M/C 249)
|
|
University of Illinois at Chicago
|
|
851 S. Morgan St.
|
|
Chicago, IL 60607-7045
|
|
|
|
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.
|
|
******************************************************************/
|
|
|
|
#include "Topograph.h"
|
|
#include "graph.h"
|
|
|
|
/* Defined in this module */
|
|
void processGraphIDCMP(void);
|
|
BOOL printxyz(int mouseX, int mouseY);
|
|
void drawBox(int X, int Y, int halfW, int halfH);
|
|
|
|
/* Defined in UI.c */
|
|
extern struct Screen *graphScreen;
|
|
extern struct Window *graphWindow;
|
|
extern struct Window *CPWindow;
|
|
extern struct Window *xyzWindow;
|
|
extern struct Gadget *CPGadgets[];
|
|
extern int graphHeight;
|
|
extern int graphWidth;
|
|
extern void noPointer(void);
|
|
|
|
/* Defined in graph.c */
|
|
extern void printX(struct graph *G, char *string, int xIndex);
|
|
extern void printY(struct graph *G, char *string, int yIndex);
|
|
extern void printZ(struct graph *G, char *string, int xIndex, int yIndex);
|
|
|
|
/* Defined in CP.c */
|
|
extern struct CPMessage CPmsg;
|
|
extern void CP_displayExtrema(struct graph *);
|
|
extern void CP_displayDomain(void);
|
|
extern void CP_computeAspect(void);
|
|
extern void CP_adjustY(void);
|
|
|
|
/* Defined in graphtask.c */
|
|
extern struct graph *theGraph;
|
|
extern void graphMessage(int command);
|
|
extern double readX(struct graph *G, int xIndex);
|
|
extern double readY(struct graph *G, int yIndex);
|
|
|
|
|
|
|
|
static BOOL mouseDragging = FALSE;
|
|
static int clickX;
|
|
static int clickY;
|
|
static int zoomHW;
|
|
static int zoomHH;
|
|
static int maxHW;
|
|
static int maxHH;
|
|
static double xMinSave, xMaxSave, yMinSave, yMaxSave, aspectSave;
|
|
|
|
#define MINHH 2
|
|
#define MINHW 4
|
|
|
|
void processGraphIDCMP(void){
|
|
struct IntuiMessage *m;
|
|
struct IntuiMessage message;
|
|
BOOL mouseMoved = FALSE;
|
|
int mouseX, mouseY;
|
|
static int clickX, clickY;
|
|
double boxAspect = (double)graphHeight/graphWidth;
|
|
|
|
while(m = (struct IntuiMessage *)GetMsg(graphWindow->UserPort)){
|
|
message = *m;
|
|
ReplyMsg((struct Message *)m);
|
|
|
|
switch(message.Class){
|
|
|
|
case MOUSEMOVE:
|
|
mouseX = message.MouseX;
|
|
mouseY = message.MouseY;
|
|
mouseMoved = TRUE;
|
|
break;
|
|
|
|
case MOUSEBUTTONS:
|
|
/*
|
|
Start zooming in.
|
|
*/
|
|
if (message.Code == SELECTDOWN){
|
|
clickX = graphWindow->MouseX;
|
|
clickY = graphWindow->MouseY;
|
|
if (printxyz(clickX,clickY)){
|
|
mouseDragging = TRUE;
|
|
noPointer();
|
|
maxHW = 2*clickX<graphWidth?clickX:(graphWidth - clickX - 1);
|
|
maxHH = 2*clickY<graphHeight?clickY:(graphHeight - clickY - 1);
|
|
zoomHW = 0;
|
|
zoomHH = 0;
|
|
xMinSave = CPmsg.xMin;
|
|
xMaxSave = CPmsg.xMax;
|
|
yMinSave = CPmsg.yMin;
|
|
yMaxSave = CPmsg.yMax;
|
|
aspectSave = CPmsg.aspect;
|
|
}
|
|
}
|
|
/*
|
|
Done zooming. Redraw the graph.
|
|
*/
|
|
else if (message.Code == SELECTUP){
|
|
mouseDragging = FALSE;
|
|
drawBox(clickX,clickY,zoomHW, zoomHH);
|
|
ClearPointer(graphWindow);
|
|
/*
|
|
If the box is too small we assume that User changed her mind.
|
|
*/
|
|
if (zoomHW > MINHW && zoomHH > MINHH){
|
|
CPmsg.computeNewValues = YES;
|
|
graphMessage(DRAW_CMD);
|
|
}
|
|
else{
|
|
CPmsg.xMin = xMinSave;
|
|
CPmsg.xMax = xMaxSave;
|
|
CPmsg.yMin = yMinSave;
|
|
CPmsg.yMax = yMaxSave;
|
|
CPmsg.aspect = aspectSave;
|
|
CP_displayDomain();
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case IDCMP_RAWKEY:
|
|
switch (message.Code){
|
|
case UPARROW:
|
|
graphMessage(UP_CMD);
|
|
break;
|
|
|
|
case DOWNARROW:
|
|
graphMessage(DOWN_CMD);
|
|
break;
|
|
|
|
case LEFTARROW:
|
|
graphMessage(LEFT_CMD);
|
|
break;
|
|
|
|
case RIGHTARROW:
|
|
graphMessage(RIGHT_CMD);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
CP_displayDomain();
|
|
CP_displayExtrema(theGraph);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (mouseMoved) {
|
|
|
|
if (mouseDragging){
|
|
/*
|
|
Erase the old box. Note that drawBox does nothing if the box is too
|
|
small.
|
|
*/
|
|
drawBox(clickX,clickY,zoomHW, zoomHH);
|
|
|
|
/*
|
|
Compute the size of the new box.
|
|
*/
|
|
zoomHW = mouseX - clickX;
|
|
if (zoomHW < 0) zoomHW = -zoomHW;
|
|
if (zoomHW > maxHW) zoomHW = maxHW;
|
|
if (CPmsg.aspectIsFixed == TRUE){
|
|
if (zoomHW*boxAspect <= maxHH) zoomHH = zoomHW*boxAspect;
|
|
else {
|
|
zoomHH = maxHH;
|
|
zoomHW = zoomHH/boxAspect;
|
|
}
|
|
}
|
|
else {
|
|
zoomHH = mouseY - clickY;
|
|
if (zoomHH < 0) zoomHH = -zoomHH;
|
|
if (zoomHH > maxHH) zoomHH = maxHH;
|
|
}
|
|
|
|
/*
|
|
Draw a new box.
|
|
*/
|
|
drawBox(clickX,clickY,zoomHW,zoomHH);
|
|
/*
|
|
Save and display the domain;
|
|
*/
|
|
CPmsg.xMin=readX(theGraph,clickX - zoomHW);
|
|
CPmsg.xMax=readX(theGraph,clickX + zoomHW);
|
|
CPmsg.yMin=readY(theGraph,clickY + zoomHH);
|
|
CPmsg.yMax=readY(theGraph,clickY - zoomHH);
|
|
if (CPmsg.aspectIsFixed == TRUE) CP_adjustY();
|
|
else CP_computeAspect();
|
|
CP_displayDomain();
|
|
}
|
|
|
|
/*
|
|
If User isn't dragging the mouse, we print x,y and z values.
|
|
During a drag, we leave the coordinates of the center point
|
|
in the xyzWindow. Maybe we should print out Xmin, ... Ymax, though.
|
|
This is a good time to check if the pointer is in the CPWindow,
|
|
and if so to activate it.
|
|
*/
|
|
else {
|
|
printxyz(mouseX,mouseY);
|
|
if (mouseY < 0) ActivateWindow(CPWindow);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void drawBox(int X, int Y, int halfW, int halfH){
|
|
struct RastPort *rp = &(graphScreen->RastPort);
|
|
|
|
if (halfW <= MINHW || halfH <= MINHH) return;
|
|
|
|
/* SetWrMsk(rp, 0x10);*/ /*We draw boxes on plane 4 only.*/
|
|
SetWrMsk(rp, 0x21);
|
|
Move(rp,(long)(X-halfW),(long)(Y-halfH));
|
|
Draw(rp,(long)(X+halfW),(long)(Y-halfH));
|
|
Draw(rp,(long)(X+halfW),(long)(Y+halfH));
|
|
Draw(rp,(long)(X-halfW),(long)(Y+halfH));
|
|
Draw(rp,(long)(X-halfW),(long)(Y-halfH+1));
|
|
SetWrMsk(rp, 0xff);
|
|
|
|
}
|
|
|
|
|
|
/* If the pointer is not on the graph, clear the xyz gadgets and return FALSE.
|
|
Otherwise print the coordinates and return TRUE. */
|
|
|
|
BOOL printxyz(int mouseX, int mouseY){
|
|
/* These have to be long because printf does weird things with nans. */
|
|
char xString[64];
|
|
char yString[64];
|
|
char zString[64];
|
|
BOOL value;
|
|
|
|
|
|
if (mouseX < 0 | mouseX >= graphWidth | mouseY >= graphHeight | mouseY < 0){
|
|
xString[0] = '\0';
|
|
yString[0] = '\0';
|
|
zString[0] = '\0';
|
|
value = FALSE;
|
|
}
|
|
|
|
else {
|
|
printX(theGraph, xString, mouseX);
|
|
printY(theGraph, yString, mouseY);
|
|
printZ(theGraph, zString, mouseX, mouseY);
|
|
value = TRUE;
|
|
}
|
|
|
|
GT_SetGadgetAttrs(CPGadgets[XDISPLAY], xyzWindow,NULL,
|
|
GTTX_Text, xString,
|
|
TAG_END);
|
|
|
|
GT_SetGadgetAttrs(CPGadgets[YDISPLAY], xyzWindow,NULL,
|
|
GTTX_Text, yString,
|
|
TAG_END);
|
|
|
|
GT_SetGadgetAttrs(CPGadgets[ZDISPLAY], xyzWindow,NULL,
|
|
GTTX_Text, zString,
|
|
TAG_END);
|
|
|
|
return(value);
|
|
}
|