// -*- C++ -*- // $RCSfile: scrollcanvas.C,v $ // $Revision: 1.5 $ // $Author: langer $ // $Date: 2001/02/16 14:53:54 $ /* This software was produced by NIST, an agency of the U.S. government, * and by statute is not subject to copyright in the United States. * Recipients of this software assume all responsibilities associated * with its operation, modification and maintenance. However, to * facilitate maintenance we ask that before distributing modifed * versions of this software, you first contact the authors at * oof_manager@ctcms.nist.gov. */ #include "colorutils.h" #include "forms.h" #include "menucolor.h" #include "meshcoord.h" #include "mouseclick.h" #include "readbinary.h" #include "scrollcanvas.h" #include "shape.h" #include "mvvd.h" #include "vec.h" #include #include const int ScrollCanvas::scrollbarwidth(20); // thickness of scrollbars int ScrollCanvas::Ncanvases(0); //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // The following is a modfied version of the fdesign code in scrcanvas.c void create_form_scrollcanvas(ScrollCanvas *fdui, int x, int y, int w, int h) { FL_OBJECT *obj; fdui->backdrop = obj = fl_add_box(FL_FLAT_BOX, x+ScrollCanvas::scrollbarwidth, y+ScrollCanvas::scrollbarwidth, w-ScrollCanvas::scrollbarwidth, h-ScrollCanvas::scrollbarwidth,""); fl_set_object_color(obj,FL_WHITE,FL_COL1); fl_set_object_gravity(obj, FL_NorthWest, FL_SouthEast); fdui->horscrollbar = obj = fl_add_slider(FL_HOR_SLIDER, x+ScrollCanvas::scrollbarwidth, y, w-ScrollCanvas::scrollbarwidth, ScrollCanvas::scrollbarwidth,""); fl_set_object_gravity(obj, FL_NorthWest, FL_NorthEast); fl_set_object_resize(obj, FL_RESIZE_X); fl_set_object_callback(obj,ScrollCanvas::horscrollcallback,(long) fdui); fl_set_slider_return(obj, FL_RETURN_CHANGED); fdui->verscrollbar = obj = fl_add_slider(FL_VERT_SLIDER, x, y+ScrollCanvas::scrollbarwidth, ScrollCanvas::scrollbarwidth, h-ScrollCanvas::scrollbarwidth,""); fl_set_object_gravity(obj, FL_NorthWest, FL_SouthWest); fl_set_object_resize(obj, FL_RESIZE_Y); fl_set_object_callback(obj,ScrollCanvas::verscrollcallback,(long) fdui); fl_set_slider_return(obj, FL_RETURN_CHANGED); fdui->zoombutton = obj = fl_add_button(FL_NORMAL_BUTTON, x, y, ScrollCanvas::scrollbarwidth, ScrollCanvas::scrollbarwidth,"z"); fl_set_object_lstyle(obj,FL_BOLD_STYLE); fl_set_object_gravity(obj, FL_NorthWest, FL_NorthWest); fl_set_object_callback(obj,ScrollCanvas::zoomcallback,(long) fdui); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// ScrollCanvas::ScrollCanvas(FL_FORM *form, int x, int y, int w, int h, void (*scb)(const MeshCoord&, const MeshCoord&, void *), void *scbptr) : backdropvisible(1), xscroll(0), yscroll(0), xscrollmin(0), xscrollmax(w-scrollbarwidth), yscrollmin(0), yscrollmax(h-scrollbarwidth), pmap(w-scrollbarwidth, h-scrollbarwidth), xmin(0), xmax(1), ymin(0), ymax(1), zoomfactor(1.5), usestipple(0), index(Ncanvases), holding(0), scrollcallback(scb), scrollcallbackptr(scbptr), xscrollcallback(0), yscrollcallback(0), xyscrollcallbackptr(0), zoombutton_callback(0), zoombutton_callbackptr(0), resize_callback(0), resize_callbackptr(0) { index++; fl_addto_form(form); create_form_scrollcanvas(this, x, y, w, h); canvas = fl_add_canvas(FL_NORMAL_CANVAS, backdrop->x, backdrop->y, backdrop->w, backdrop->h, ""); fl_set_object_gravity(canvas, FL_NorthWest, FL_SouthEast); fl_set_canvas_decoration(canvas, FL_NO_FRAME); fl_add_canvas_handler(canvas, Expose, exposecallback, this); fl_add_canvas_handler(canvas, ButtonPress, mousedncallback, this); fl_add_canvas_handler(canvas, ButtonRelease, mouseupcallback, this); fl_add_canvas_handler(canvas, MotionNotify, mousemvcallback, this); fl_end_form(); fl_set_canvas_visual(canvas, gfxinfo.visual()); fl_set_canvas_depth(canvas, gfxinfo.depth()); fillgc = XCreateGC(gfxinfo.display(), gfxinfo.window(), 0, 0); XSetForeground(gfxinfo.display(), fillgc, BlackPixel(gfxinfo.display(), gfxinfo.screen())); canvasw = canvas->w; canvash = canvas->h; setscrollbars(); } ScrollCanvas::~ScrollCanvas() { fl_hide_object(canvas); fl_hide_object(horscrollbar); fl_hide_object(verscrollbar); fl_hide_object(zoombutton); fl_hide_object(backdrop); fl_delete_object(canvas); fl_delete_object(horscrollbar); fl_delete_object(verscrollbar); fl_delete_object(zoombutton); fl_delete_object(backdrop); fl_free_object(canvas); fl_free_object(horscrollbar); fl_free_object(verscrollbar); fl_free_object(zoombutton); fl_free_object(backdrop); } void ScrollCanvas::set_colormap(Colormap cmap) { colormap = cmap; fl_share_canvas_colormap(canvas, cmap); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// void ScrollCanvas::show() { fl_show_object(horscrollbar); fl_show_object(verscrollbar); fl_show_object(zoombutton); if(backdropvisible) fl_show_object(backdrop); else fl_show_object(canvas); } void ScrollCanvas::hide() { fl_hide_object(horscrollbar); fl_hide_object(verscrollbar); fl_hide_object(zoombutton); if(backdropvisible) fl_hide_object(backdrop); else fl_hide_object(canvas); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // copy pixmap to screen static void copylimits(int scroll, int psize, int csize, int &source, int &dest, int ©) { source = scroll; if(source >= 0) { // left edge of pixmap is beyond left edge of canvas dest = 0; copy = psize - source; if(copy > csize) // right edge of pixmap is beyond right edge of canvas copy = csize; } else { // left edge of pixmap is within canvas dest = -source; source = 0; copy = csize - dest; if(copy > psize) // right edge of pixmap is within canvas copy = psize; } } void ScrollCanvas::refresh() { backdropvisible = 0; copyimage(fl_get_canvas_id(canvas)); } void ScrollCanvas::copyimage(Drawable destination) const { int xsource, xdest, xcopy; int ysource, ydest, ycopy; // Find how much of the pixmap is visible. copylimits(xscroll, pmap.width(), canvas->w, xsource, xdest, xcopy); copylimits(yscroll, pmap.height(), canvas->h, ysource, ydest, ycopy); // Copy visible region of pixmap to canvas. XCopyArea(gfxinfo.display(), pixmap(), destination, gc(), xsource, ysource, xcopy, ycopy, xdest, ydest); // If pixmap didn't fill canvas, fill in the rest. if(xdest > 0 || xdest + xcopy < canvas->w || ydest > 0 || ydest + ycopy < canvas->h) { if(usestipple) { // find origin for stipple pattern. It has to be coincident with // the origin of the pixmap, so that the pixmap background and // the canvas background merge. //int xorigin = xdest > 0 ? xdest : xscrollmin - xscroll; //int yorigin = ydest > 0 ? ydest : yscrollmin - yscroll; XSetTSOrigin(gfxinfo.display(), fillgc, -xscroll, -yscroll); } if(xdest > 0) XFillRectangle(gfxinfo.display(), destination, fillgc, 0, 0, xdest, canvas->h); if(ydest > 0) XFillRectangle(gfxinfo.display(), destination, fillgc, 0, 0, canvas->w, ydest); if(xdest + xcopy < canvas->w) XFillRectangle(gfxinfo.display(), destination, fillgc, xdest+xcopy, 0, canvas->w-xdest-xcopy, canvas->h); if(ydest + ycopy < canvas->h) XFillRectangle(gfxinfo.display(), destination, fillgc, 0, ydest+ycopy, canvas->w, canvas->h-ydest-ycopy); } } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // Scrolling static void setscrolllimits(int scroll, int pw, int cw, int &scrollmin, int &scrollmax) { if(scroll < 0) scrollmin = scroll; else scrollmin = 0; if(scroll + cw > pw) scrollmax = scroll + cw; else scrollmax = pw; } void ScrollCanvas::setscrollbars() { fl_set_slider_bounds(horscrollbar, xscrollmin, xscrollmax-canvas->w); fl_set_slider_size(horscrollbar, canvas->w/(double) (xscrollmax - xscrollmin)); fl_set_slider_value(horscrollbar, xscroll); fl_set_slider_bounds(verscrollbar, yscrollmin, yscrollmax-canvas->h); fl_set_slider_size(verscrollbar, canvas->h/(double) (yscrollmax - yscrollmin)); fl_set_slider_value(verscrollbar, yscroll); } void ScrollCanvas::save_scroll(ostream &os) const { os << xscrollmin << " " << xscroll << " " << xscrollmax << " " << yscrollmin << " " << yscroll << " " << yscrollmax << " " << pmap.width() << " " << pmap.height() << endl; // cerr << "ScrollCanvas::save_scroll w=" << pmap.width() // << " h=" << pmap.height() << endl // << xscrollmin << " " << xscroll << " " << xscrollmax << " " // << yscrollmin << " " << yscroll << " " << yscrollmax << endl; } void ScrollCanvas::read_scroll(istream &is) { int w, h; is >> xscrollmin >> xscroll >> xscrollmax >> yscrollmin >> yscroll >> yscrollmax >> w >> h; // cerr << "ScrollCanvas::read_scroll w=" << pmap.width() // << " h=" << pmap.height() << endl // << xscrollmin << " " << xscroll << " " << xscrollmax << " " // << yscrollmin << " " << yscroll << " " << yscrollmax << endl; pmap.resize(w, h); setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); do_scrollcallback(); // if(xscrollcallback) // (*xscrollcallback)(xscroll - oldscroll, xyscrollcallbackptr); // if(yscrollcallback) // (*yscrollcallback)(yscroll - oldscroll, xyscrollcallbackptr); refresh(); } void ScrollCanvas::horscrollcallback(FL_OBJECT*, long arg) { ScrollCanvas *sc = (ScrollCanvas*) arg; sc->horscrollhandler(); } void ScrollCanvas::horscrollhandler() { int oldscroll = xscroll; xscroll = int(fl_get_slider_value(horscrollbar)); // adjust size & position of scroll bars here in case the image had // been slid off the screen (with scroll(int, int)). In that case, // the scroll bars make the unphysical region accessible. Adjusting // the bars here makes unphysical regions that are scrolled off // screen inaccessible. setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrollbars(); do_scrollcallback(); if(xscrollcallback) (*xscrollcallback)(xscroll - oldscroll, xyscrollcallbackptr); refresh(); } void ScrollCanvas::verscrollcallback(FL_OBJECT*, long arg) { ScrollCanvas *sc = (ScrollCanvas*) arg; sc->verscrollhandler(); } void ScrollCanvas::verscrollhandler() { int oldscroll = yscroll; yscroll = int(fl_get_slider_value(verscrollbar)); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); do_scrollcallback(); if(yscrollcallback) (*yscrollcallback)(yscroll - oldscroll, xyscrollcallbackptr); refresh(); } void ScrollCanvas::scroll(int x, int y) { xscroll += x; yscroll += y; setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); refresh(); do_scrollcallback(); } void ScrollCanvas::scroll(double x, double y) { XPoint xp(xpoint(x, y)); xscroll += xp.x; yscroll += xp.y; setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); refresh(); do_scrollcallback(); } XPoint ScrollCanvas::get_scroll_pixels() const { XPoint sc; sc.x = xscroll; sc.y = yscroll; return sc; } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// void ScrollCanvas::set_xyscrollcallbacks(void (*fx)(int, void*), void (*fy)(int, void*), void *ptr) { xscrollcallback = fx; yscrollcallback = fy; xyscrollcallbackptr = ptr; } void ScrollCanvas::set_zoombutton_callback(void (*f)(int, void*), void *ptr) { zoombutton_callback = f; zoombutton_callbackptr = ptr; } void ScrollCanvas::set_resize_callback(void (*f)(int, int, void*), void *ptr) { resize_callback = f; resize_callbackptr = ptr; } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // Zooming void ScrollCanvas::zoomcallback(FL_OBJECT*, long arg) { ((ScrollCanvas*) arg)->buttonzoom(); } void ScrollCanvas::buttonzoom() { int buttonnumber = fl_get_button_numb(zoombutton); zoom_button(buttonnumber); if(zoombutton_callback) (*zoombutton_callback)(buttonnumber, zoombutton_callbackptr); } void ScrollCanvas::zoom_button(int buttonnumber) { if(buttonnumber == 1) zoom(1./zoomfactor); else if(buttonnumber == 2) fullzoom(); else if(buttonnumber == 3) zoom(zoomfactor); } void ScrollCanvas::zoom(double factor) { if(holding) return; XPoint center; center.x = int(xscroll + 0.5*canvas->w); center.y = int(yscroll + 0.5*canvas->h); zoom(factor, center); } void ScrollCanvas::zoom(double factor, const XPoint &fixedpoint) { // fixedpoint is given in pixmap coordinates if(holding) return; int w = int(pmap.width()*factor); int h = int(pmap.height()*factor); if(h == 0 || w == 0) { cerr << "Can't zoom down that far!" << endl; return; } pmap.resize(w, h); xscroll += int(fixedpoint.x*(factor - 1.0)); yscroll += int(fixedpoint.y*(factor - 1.0)); setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); redraw(); refresh(); do_scrollcallback(); } void ScrollCanvas::fullzoom() { if(holding) return; int pwch = pmap.width()*canvas->h; int phcw = pmap.height()*canvas->w; int neww = canvas->w; int newh = canvas->h; if(pwch != phcw) { if(pwch > phcw) // h/w for canvas is greater than for pixmap newh = int(neww*pmap.height()/(double) pmap.width()); else // h/w for pixmap is greater than for canvas neww = int(newh*pmap.width()/(double) pmap.height()); } pmap.resize(neww, newh); xscroll = 0; yscroll = 0; xscrollmin = 0; yscrollmin = 0; xscrollmax = canvas->w; yscrollmax = canvas->h; setscrollbars(); redraw(); refresh(); do_scrollcallback(); } void ScrollCanvas::do_scrollcallback() const { if(scrollcallback) { MeshCoord ul, lr; // upper left and lower right corners of canvas physicalcoords(xscroll, yscroll, ul.x, ul.y); physicalcoords(xscroll+canvasw, yscroll+canvash, lr.x, lr.y); (*scrollcallback)(ul, lr, scrollcallbackptr); } } Rectangle ScrollCanvas::visible_region() const { MeshCoord ul, lr; physicalcoords(xscroll, yscroll, ul.x, ul.y); physicalcoords(xscroll+canvasw, yscroll+canvash, lr.x, lr.y); return Rectangle(ul, lr); } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// void ScrollCanvas::hold() { holding = 1; fl_deactivate_object(zoombutton); fl_deactivate_object(verscrollbar); fl_deactivate_object(horscrollbar); fl_set_object_lcol(zoombutton, FL_INACTIVE_COL); fl_set_object_color(horscrollbar, COL_BACKGROUND, COL_BACKGROUND); fl_set_object_color(verscrollbar, COL_BACKGROUND, COL_BACKGROUND); } void ScrollCanvas::release_hold() { holding = 0; fl_activate_object(zoombutton); fl_activate_object(verscrollbar); fl_activate_object(horscrollbar); fl_set_object_lcol(zoombutton, FL_BLACK); fl_set_object_color(horscrollbar, FL_COL1, FL_COL1); fl_set_object_color(verscrollbar, FL_COL1, FL_COL1); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// void ScrollCanvas::resizepixmap(int w, int h) { int oldw = pmap.width(); int oldh = pmap.height(); pmap.resize(w, h); xscroll = int(xscroll*w/(double) oldw); yscroll = int(yscroll*h/(double) oldh); setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); do_scrollcallback(); } void ScrollCanvas::setcoords_resize(double x0, double x1, double y0, double y1) { // set the physical coordinates and resize the pixmap so that the // range of physical coordinates visible in the canvas doesn't // change. Write down the equations for the physical coords of the // canvas limits and solve them for xscroll, yscroll, pixmap-width, // and pixmap-height. double oldw = xmax - xmin; double oldh = ymax - ymin; double xfactor = (x1 - x0)/oldw; double yfactor = (y1 - y0)/oldh; xscroll += int(pmap.width()*(xmin - x0)/oldw); yscroll += int(pmap.height()*(yfactor-1-(ymin-y0)/oldh)); setcoords(x0, x1, y0, y1); pmap.resize(pmap.width()*xfactor, pmap.height()*yfactor); setscrolllimits(xscroll, pmap.width(), canvas->w, xscrollmin, xscrollmax); setscrolllimits(yscroll, pmap.height(), canvas->h, yscrollmin, yscrollmax); setscrollbars(); do_scrollcallback(); redraw(); refresh(); } void ScrollCanvas::setcoords_reset(double x0, double x1, double y0, double y1) { // set the physical coordinates and resize the pixmap so that it // fits the canvas. pmap.resize(canvasw, canvash); setcoords(x0, x1, y0, y1); fullzoom(); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // convert to pixmap coordinates XPoint ScrollCanvas::xpoint(double x, double y) const { XPoint p; // order of multiplication and division is important to avoid round off error p.x = short((x - xmin)*pmap.width()/(xmax - xmin)); p.y = short(pmap.height() - ((y - ymin)*pmap.height()/(ymax - ymin))); return p; } XPoint ScrollCanvas::xpoint(const MV_Vector_double &xy) const { return xpoint(xy[0], xy[1]); } void ScrollCanvas::physicalcoords(int ix, int iy, double &x, double &y) const { x = xmin + (xmax - xmin)*ix/pmap.width(); y = ymin + (ymax - ymin)*(1.0 - iy/(double) pmap.height()); } void ScrollCanvas::setcoords(double x0, double x1, double y0, double y1) { xmin = x0; xmax = x1; ymin = y0; ymax = y1; } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// int ScrollCanvas::exposecallback(FL_OBJECT*, Window win, int w, int h, XEvent*, void *arg) { ((ScrollCanvas*) arg)->exposehandler(win, w, h); return 0; } void ScrollCanvas::exposehandler(Window, int w, int h) { if(w != canvasw || h != canvash) { // size has changed canvasw = w; canvash = h; if(canvasw + xscroll > pmap.width()) xscrollmax = canvasw + xscroll; else xscrollmax = pmap.width(); if(canvash + yscroll > pmap.height()) yscrollmax = canvash + yscroll; else yscrollmax = pmap.height(); setscrollbars(); if(resize_callback) (*resize_callback)(w, h, resize_callbackptr); do_scrollcallback(); } refresh(); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// void ScrollCanvas::clearcanvas() { if(!backdropvisible) { XSetTSOrigin(gfxinfo.display(), fillgc, -xscroll, -yscroll); XFillRectangle(gfxinfo.display(), fl_get_canvas_id(canvas), fillgc, 0, 0, canvas->w, canvas->h); } } void ScrollCanvas::clear() { if(usestipple) XSetTSOrigin(gfxinfo.display(), fillgc, 0, 0); pmap.clear(fillgc); refresh(); } void ScrollCanvas::clearpixmap() { if(usestipple) XSetTSOrigin(gfxinfo.display(), fillgc, 0, 0); pmap.clear(fillgc); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // Filling in the undrawn regions void ScrollCanvas::setfillcolor(unsigned long fillcolor) { usestipple = 0; XSetFillStyle(gfxinfo.display(), fillgc, FillSolid); XSetForeground(gfxinfo.display(), fillgc, fillcolor); } void ScrollCanvas::setstipple(int w, int h, char *bits, unsigned long fg, unsigned long bg) { usestipple = 1; stipple_w = w; stipple_h = h; stipple = XCreateBitmapFromData(gfxinfo.display(), gfxinfo.window(), bits, w, h); XSetForeground(gfxinfo.display(), fillgc, fg); XSetBackground(gfxinfo.display(), fillgc, bg); XSetFillStyle(gfxinfo.display(), fillgc, FillOpaqueStippled); XSetStipple(gfxinfo.display(), fillgc, stipple); } //=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=// // Mouse MouseClick ScrollCanvas::lastclick; // remember last mouse down int ScrollCanvas::checkclick(int x, int y) const { // make sure click is on the image. Return 1 if it's NOT. return (x < 0 || y < 0 || x >= pmap.width() || y >= pmap.height()); } int ScrollCanvas::mousedncallback(FL_OBJECT*, Window, int, int, XEvent *xev, void *arg) { ((ScrollCanvas*) arg)->mousedncb(xev); return 0; } void ScrollCanvas::mousedncb(XEvent *xev) { double x, y; int ix = xev->xbutton.x + xscroll; int iy = xev->xbutton.y + yscroll; //if(checkclick(ix, iy)) return; physicalcoords(ix, iy, x, y); lastclick = MouseClick(x, y, ix, iy, index, xev); mouse(lastclick); // virtual function } const MouseClick &ScrollCanvas::downclick() const { return lastclick; } // ---------------------------------- int ScrollCanvas::mouseupcallback(FL_OBJECT*, Window, int, int, XEvent *xev, void *arg) { ((ScrollCanvas*) arg)->mouseupcb(xev); return 0; } void ScrollCanvas::mouseupcb(XEvent *xev) { double x, y; if(!lastclick) return; if(lastclick.window == index) { // same window as last mouse down? int ix = xev->xbutton.x + xscroll; int iy = xev->xbutton.y + yscroll; //if(checkclick(ix, iy)) return; physicalcoords(ix, iy, x, y); mouse(MouseClick(x, y, ix, iy, index, xev)); // virtual function } lastclick.event = MOUSE_TRAP; // last click no longer meaningful } // ----------------------------------- int ScrollCanvas::mousemvcallback(FL_OBJECT*, Window, int, int, XEvent *xev, void *arg) { ((ScrollCanvas*) arg)->mousemvcb(xev); return 0; } void ScrollCanvas::mousemvcb(XEvent *xev) { double x, y; if(!lastclick || lastclick.window != index) return; // wrong window! int ix = xev->xbutton.x + xscroll; int iy = xev->xbutton.y + yscroll; //if(checkclick(ix, iy)) return; physicalcoords(ix, iy, x, y); mouse(MouseClick(x, y, ix, iy, index, xev)); // virtual function } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// // simulate a mouse click void ScrollCanvas::robomouse(const MouseClick &click) { if(click.event == MOUSE_DN) lastclick = click; mouse(click); if(click.event == MOUSE_UP) lastclick.event = MOUSE_TRAP; } //-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-//-\\-// static inline void writebyte(FILE* file, unsigned char c) { writebinary(file, c, 1); } class ColorList { private: Display *display; Colormap colormap; Vec list; public: ColorList(Display *d, Colormap cmap) : display(d), colormap(cmap), list(0, BlockSize(100)) {} const XColor &operator[](unsigned long); }; const XColor &ColorList::operator[](unsigned long pixel) { // look for color in list for(int i=0; iw, canvas->h); copyimage(temp.pixmap()); unsigned long plane_mask = ~(unsigned long) 0; // all planes XImage *image = XGetImage(gfxinfo.display(), temp.pixmap(), 0, 0, canvas->w, canvas->h, plane_mask, ZPixmap); // header for PPM file fputs("P6\n", file); /* P3 for ascii version */ fputs("# CREATOR: oof\n", file); fprintf(file, "%d %d\n", canvas->w, canvas->h); fprintf(file, "255\n"); /* 65535 for ascii version? */ ColorList colorlist(gfxinfo.display(), colormap); for(int i=0; iheight; i++) { for(int j=0; jwidth; j++) { XColor color = colorlist[XGetPixel(image, j, i)]; // look up rgb writebyte(file, color.red>>8); writebyte(file, color.green>>8); writebyte(file, color.blue>>8); } } XDestroyImage(image); }