Newer
Older
#ifdef WIN32
# include "winjunk.h"
#endif
#if unix
# include "FL/x.H"
#endif
#include "Plot.H"
#include "sfont.h"
#include "shmem.h"
int Plot_add_drawer( Fl_Plot *plot,
void (*func)( Fl_Plot *, void *obj, void *arg ),
void *obj, void *arg, char *name, int id ) {
return plot->add_drawer( func, obj, arg, name, id );
}
int Plot_inpick( Fl_Plot *plot ) { return plot->inpick(); }
void Plot_setpick( Fl_Plot *, void (*pickcb)(Fl_Plot *, int hits, int ents, GLuint *buf) );
Fl_Plot::Fl_Plot(int x, int y, int w, int h, const char *label)
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
: Fl_Gl_Window(x,y,w,h,label) {
init();
end();
}
int Fl_Plot::add_drawer( void (*func)( Fl_Plot *, void *obj, void *arg ),
void *obj, void *arg, const char *name, int id )
{
if(id < 0) id = next_id();
int dno = withid( id );
if(dno < 0) {
if(ndrawers_ >= maxdrawers_) {
maxdrawers_ = ndrawers_*2 + 15;
int room = maxdrawers_ * sizeof(struct drawer);
drawers_ = (struct drawer *)
(drawers_==NULL ? malloc(room) : realloc(drawers_, room));
}
dno = ndrawers_++;
}
struct drawer *dp = &drawers_[dno];
dp->func = func;
dp->obj = obj;
dp->arg = arg;
dp->name = shmstrdup(name);
dp->id = id;
notify();
redraw();
return id;
}
void Fl_Plot::notify() {
if(notify_ != NULL)
(*notify_)( this, notifyarg_ );
}
int Fl_Plot::withid( int id ) const { // Which drawer[] slot is id in?
for(int dno = 0; dno < ndrawers_; dno++)
if(drawers_[dno].id == id)
return dno;
return -1;
}
int Fl_Plot::next_id() const {
int id;
for(id = 1; withid(id) >= 0; id++)
;
return id;
}
void draw_axis( float v0, float v1, float ybase, float ytick, float htext, char *just, char *title ) {
char ljust[4], rjust[4];
sprintf(ljust, "%.2sw", just?just:"");
sprintf(rjust, "%.2se", just?just:"");
glColor3f( 1,1,1 );
glBegin( GL_LINES );
glVertex2f( 0,ybase );
glVertex2f( 1,ybase );
glVertex2f( 0,ybase );
glVertex2f( 0,ytick );
glVertex2f( 1,ybase );
glVertex2f( 1,ytick );
glEnd();
char lbl[16];
sprintf(lbl, "%.2g", v0);
Point at = { 0, ytick, 0 };
sfStrDrawTJ( lbl, htext*.8, &at, NULL, ljust );
sfStrDrawTJ( lbl, htext*.8, &at, NULL, rjust );
if(title) {
at.x[0] = .5;
at.x[1] = ytick + (ytick-ybase);
sfStrDrawTJ( title, htext, &at, NULL, "c" );
}
static float coordof( int pixel, int npix, float o0, float o1, float v0, float v1 ) {
float o = pixel * (o1-o0) / npix + o0;
return o * (v1-v0) + v0;
}
static float rounded( int prec, float v ) {
sprintf(str, "%.*g", prec, v);
return atof(str);
}
static float choosezoom( float zoom, int pixel,
int npix, float o0, float o1, float *v0p, float *v1p ) {
float range = (*v1p - *v0p);
if(range == 0) return 1; /* unchanged */
float newv0, newv1, error;
float center = coordof( pixel, npix, o0, o1, *v0p, *v1p );
for(int prec = 0; prec < 4; prec++) {
newv0 = rounded( prec, center - .5*range/zoom );
newv1 = rounded( prec, center + .5*range/zoom );
error = 1 - zoom*(newv1 - newv0)/range;
if(fabs(error) < .1) break;
}
if(newv1 == newv0) return 1; /* degenerate after 4 digits?! */
*v0p = newv0;
*v1p = newv1;
return range / (newv1 - newv0);
}
float Fl_Plot::zoomview( float zoomfactor, int xev, int yev ) {
if(zoomfactor == 0) {
xrange( initx0_, initx1_ );
yrange( inity0_, inity1_ );
redraw();
return 1.0;
}
choosezoom( zoomfactor, h()-yev, h(), orthoy0_, orthoy1_, &y0_, &y1_ );
float got = choosezoom( zoomfactor, xev, w(), orthox0_, orthox1_, &x0_, &x1_ );
#if unix
Window xwin = fl_xid(this);
if(xwin != None)
XWarpPointer(fl_display, xwin, xwin, 0, 0, 0, 0,
(int)(w()*(.5 - orthox0_)/(orthox1_ - orthox0_)),
(int)(h()*(orthoy1_ - .5)/(orthoy1_ - orthoy0_)));
#endif
redraw();
return got;
}
if(!valid() || damage() || inpick()) {
/* Assume reshaped */
valid(1);
glViewport( 0, 0, w(), h() );
}
glClearDepth( 1.0 );
glColorMask( 1, 1, 1, 1 );
glClearColor( bgcolor_.x[0], bgcolor_.x[1], bgcolor_.x[2], 0 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
glDisable( GL_TEXTURE_2D );
glDisable( GL_COLOR_MATERIAL );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if(inpick()) {
GLint vp[4] = {0, 0, w(), h()};
gluPickMatrix( pickx_, picky_, pickwidth_, pickheight_, vp );
}
glOrtho( orthox0_, orthox1_, orthoy0_, orthoy1_, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glScalef( x1_ == x0_ ? 1 : 1/(x1_-x0_),
y1_ == y0_ ? 1 : 1/(y1_-y0_), 1 );
glTranslatef( -x0_, -y0_, 0 );
for(int i = 0; i < ndrawers_; i++) {
struct drawer *dp = &drawers_[i];
if(dp->func != NULL) {
if(inpick_) {
glLoadName( dp->id );
glPushName( 0 );
}
if(children() > 0)
Fl_Gl_Window::draw();
}
int Fl_Plot::handle(int ev) {
if(eventhook) {
/* Allow clients to pre-screen our events without subclassing */
switch((*eventhook)(this, ev)) {
case 1: return 1; /* pre-screener handled it */
case -1: return 0; /* pre-screener commands us to ignore it too */
default: break; /* Else just process event normally below */
}
}
if(Fl_Gl_Window::handle(ev))
return 1;
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
switch(ev) {
case FL_FOCUS: hasfocus_ = 1; return 1; // Yes, we want FL_KEYBOARD events
case FL_UNFOCUS: hasfocus_ = 0; return 1;
case FL_PUSH:
{ // Besides navigating, grab keyboard focus if we're clicked-on
if(!hasfocus_) take_focus();
}
case FL_DRAG:
case FL_RELEASE:
if(pickcb_ != NULL) {
dpickx_ = Fl::event_x();
dpicky_ = h() - Fl::event_y();
if(ev == FL_PUSH) {
do_pick( dpickx_, dpicky_ );
pickneeded_ = 0;
} else {
if(!pickneeded_) {
pickneeded_ = 1;
Fl::add_idle( Fl_Plot::idlepick, (void *)this );
}
}
return 1;
}
/* Maybe do right-button pick? */
return 0;
case FL_ENTER:
take_focus();
return 1;
case FL_KEYBOARD:
if(Fl::event_text() == NULL || Fl::event_text()[0] == '\0')
return 0;
int c = Fl::event_text()[0];
switch(c) {
case 'p':
case 'P':
do_pick( Fl::event_x_root() - x_root(),
y_root() + h() - Fl::event_y_root() );
break;
case 'V': zoomview( 1.33, Fl::event_x(), Fl::event_y() ); break;
case 'v': zoomview( 1/1.33, Fl::event_x(), Fl::event_y() ); break;
case 'w': zoomview( 0 ); break;
if(Fl::event_key(FL_Home)) {
zoomview( 0 );
return 1;
}
return c==0 ? 0 : 1;
}
return 0;
}
void Fl_Plot::xrange( float x0, float x1 ) {
initx0_ = x0_ = x0;
initx1_ = x1_ = x1;
notify(); redraw();
}
void Fl_Plot::yrange( float y0, float y1 ) {
inity0_ = y0_ = y0;
inity1_ = y1_ = y1;
notify(); redraw();
}
void Fl_Plot::xtitle( const char *str ) {
if(xtitle_) Free(xtitle_);
xtitle_ = str ? shmstrdup(str) : NULL;
notify();
redraw();
}
void Fl_Plot::ytitle( const char *str ) {
if(ytitle_) Free(ytitle_);
ytitle_ = str ? shmstrdup(str) : NULL;
notify();
redraw();
}
void Fl_Plot::picksize( float width, float height )
{
pickwidth_ = width;
pickheight_ = height;
}
void Fl_Plot::pickbuffer( int words, GLuint *buf )
{
picknents_ = words;
pickbuf_ = buf;
}
void Fl_Plot::picker( void (*pickcb)(Fl_Gl_Window *, int, int, GLuint *, void *arg), void *arg )
{
pickcb_ = pickcb;
pickarg_ = arg;
}
int Fl_Plot::pickresults( int *nentp, GLuint **bufp )
{
if(nentp) *nentp = picknents_;
if(bufp) *bufp = pickbuf_;
return pickhits_;
}
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
int Fl_Plot::do_pick( float xpick, float ypick )
{
make_current();
glSelectBuffer( picknents_, pickbuf_ );
int ok = glRenderMode( GL_SELECT );
if(ok != 0) {
fprintf(stderr, "Trouble in do_pick: glRenderMode( GL_SELECT ) = %d\n", ok);
ok = glRenderMode( GL_SELECT );
fprintf(stderr, "Retry: %d\n", ok);
}
glPushName(0);
inpick_ = 1;
pickx_ = xpick;
picky_ = ypick;
draw();
inpick_ = 0;
glPopName();
pickhits_ = glRenderMode( GL_RENDER );
if(pickcb_)
(*pickcb_)( this, pickhits_, picknents_, pickbuf_, pickarg_ );
valid(0);
return pickhits_;
}
int Fl_Plot::snapshot( int x, int y, int w, int h, void *packedrgb )
{
make_current();
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadBuffer( GL_FRONT );
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, packedrgb);
return 1; // Might return whether this window was properly uncovered?
}
// Take snapshot into caller-supplied buffer, w*h*3 bytes long
void Fl_Plot::idlepick( void *vthis ) {
Fl_Plot *me = (Fl_Plot *)vthis;
if(me->pickneeded_) {
me->do_pick( me->dpickx_, me->dpicky_ );
me->pickneeded_ = 0;
Fl::remove_idle( Fl_Plot::idlepick, vthis );
}
}