XForms: CanvasInteraction with Images on a Canvas

From: Ivan Powis (Ivan.Powis@nottingham.ac.uk)
Date: Fri May 11 2001 - 11:58:25 EDT

  • Next message: Joel: "XForms: strange form behaviour"

    # To subscribers of the xforms list from Ivan Powis <Ivan.Powis@nottingham.ac.uk> :

    I'm starting to write some support code for an enhanced version of an
    older xforms application where there is now an additional need to
    interact with a pseudo-colour image (rubber-band selection of regions)
    and then do subsequent processing. I've identified the use of xforms
    Canvas and Image support to do this within the broad existing
    application framework. I've always chosen xforms to avoid getting too
    close to raw X, but canvases seem to require a step in that direction,
    hence I'm not certain my approach is correct! I've noted several minor
    "problems" and am curious as to how to resolve them. I've attached a
    cut down version of my coding (eg it doesn't actually put an image
    onto the canvas) in case I've made some fundamental mistakes in the event
    handling...

    (1) Fdesign output by default puts a DOWN_BOX decoration on the
    canvas. Is this border drawn _within_ the declared canvas dimensions?
    If so where does the FL_IMAGE get pasted, because (0,0) on the canvas
    is presumably already obscured by the border decoration. So is the
    image offset by the border width or is it masked by the border? Other
    evidence suggests to me the border decoration may be drawn outside the
    canvas on the main form, but I'd appreciate clarification of this.

    (2) The cursor in the canvas/image is supposed to be a cross-hair
    changed by Enter/Leave events (see attached sample code). However, if
    the mouse pointer happens to already lie the area of the display
    screen where the canvas appears as the form first gets displayed no
    such events get notified - so the cursor remains as its default
    shape. Is there some better way to make sure the cursor will always
    change when it happens to fall in the canvas?

    (3) My routine for drawing a selection region on the canvas essentially
    works. After drawing the rubber-banded area the user is to be allowed to
    single click on the canvas to remove the visual selection, by XORing over it.
    Running under KDE 2.0 on Mandrake Linux 7.2 (XFree 4) this final
    step seems incredibly sluggish (ie nearly a second after the click)
    before the selection is cleared. Additionally I notice that the
    mouse pointer briefly flashes from the cross-hair back to the default
    shape before the selection area gets erased. This sluggishness and
    cursor flahing do not seem to happen with other Xservers, or
    under say Gnome on the same linux box. Is this a problem with my approach,
    xforms or KDE ?

    (4) I can register event handlers for the canvas once it is created,
    but before it is displayed (because no window id is required). But to
    modify those registered events (eg to apply PointerMotionHintMask)
    seems to need fl_remove_selected_xevent for which a valid window ID
    is required. Ie this can't be done until after the canvas is displayed.
    I find this a little inconsistent ... have I missed some other routines
    which would enable the event handling to be fully setup before
    the form was displayed?

    ------------------------------------------------------------------
    /******************************************************************
    // xf_image.c
    // Routines for using xforms images pasted on canvas
    // with interactive capability
    //
    // $Log$
    ******************************************************************/

    #include <forms.h>
    #include <stdlib.h>
    #include <math.h>

    /**** FD Structs ****/
    typedef struct {
            FL_FORM *trial;
            void *vdata;
            char *cdata;
            long ldata;
            FL_OBJECT *cnvs;
    } FD_trial;

    /*--- Data structures used by rubber banding ---*/
    typedef struct{
      FL_COORD ox, oy; /* starting x,y */
      FL_COORD dx, dy; /* last displacement */
      int drawn; /* flag set while box displayed */
      char * (*xy_lab) (int x, int y, unsigned int state, FL_OBJECT *cnvs);
    } XF_IM_DESC; /* SUPPORT FOR RUBBER BANDING */

    #define ERR_MSG(a) fprintf(stderr,a)
    #define DBG
    #define CLR FL_GREEN

    /* Prototypes */

    void init_cnvs(FL_OBJECT *ob);
    static int
    expose_hndl(FL_OBJECT *, Window , int, int, XEvent *, void *);
    static int
    cross_hndl(FL_OBJECT *, Window , int, int, XEvent *, void *);
    static int
    motion_hndl(FL_OBJECT *, Window, int, int, XEvent *, void *);

    /* Create Form with Canvas ... fdesigner stuff */

    FD_trial *create_form_trial(void)
    {
      FL_OBJECT *obj;
      FD_trial *fdui = (FD_trial *) fl_calloc(1, sizeof(*fdui));

      fdui->trial = fl_bgn_form(FL_NO_BOX, 730, 630);
      obj = fl_add_box(FL_UP_BOX,0,0,730,630,"");
      fdui->cnvs = obj = fl_add_canvas(FL_NORMAL_CANVAS,50,50,610,470,"");
      fl_end_form();

      fdui->trial->fdui = fdui;

      return fdui;
    }

    /* Return text for a one-liner cursor readout */

    char *label_it(int x, int y, unsigned int state, FL_OBJECT *cnvs)
    {
      static char txt[50];

      sprintf(txt,"X:%3d Y:%3d St:$%4x", x,y,state);
      return txt;
    }
    /***************************************************
    // MAIN
    ****************************************************/

    int main(int argc, char *argv[])
    {
       FD_trial *fd_trial;
       XF_IM_DESC desc;
       int stat,i,j;

       fl_initialize(&argc, argv, 0, 0, 0);
       fd_trial = create_form_trial();

       fl_show_form(fd_trial->trial,FL_PLACE_FREE,FL_FULLBORDER,"trial");

       /* Setup canvas handlers */
       init_cnvs(fd_trial->cnvs);
      /* Attach storage to canvas u_vdata */
        desc.drawn=0;
        desc.xy_lab = label_it;
        fd_trial->cnvs->u_vdata = (void *) &desc;

     /* Normally could display image to canvas here */

       while (fl_do_forms());
       return 0;
    }

    /*------------------------------------------------------------------*/
    /* Canvas specific stuff follows */
    /*------------------------------------------------------------------*/

    /* Setup canvas handlers */

    void init_cnvs(FL_OBJECT *canvas)
    {
      /* Add canvas handlers */
      fl_add_canvas_handler(canvas, Expose, expose_hndl,(void *) 0);

      fl_add_canvas_handler(canvas, EnterNotify, cross_hndl,(void *) 0);
      fl_add_canvas_handler(canvas, LeaveNotify, cross_hndl,(void *) 0);

      fl_add_canvas_handler(canvas, MotionNotify, motion_hndl,(void *) 0);

      fl_add_canvas_handler(canvas, ButtonPress, motion_hndl,(void *) 0);
      fl_add_canvas_handler(canvas, ButtonRelease, motion_hndl,(void *) 0);
     
      if( FL_ObjWin(canvas) == 0 ){
        ERR_MSG("Canvas Window Unkown As Yet\n");
      }else{
        /* So how do I modify these before canvas is created ? */
        fl_remove_selected_xevent(FL_ObjWin(canvas),
             PointerMotionHintMask);
        fl_remove_selected_xevent(FL_ObjWin(canvas),
             Button2MotionMask);
      }
      return;
    }

    static int
    expose_hndl(FL_OBJECT * ob, Window win, int w, int h, XEvent * xev, void *data)
    {
      int dmode;
      XF_IM_DESC *xfm = (XF_IM_DESC *) ob->u_vdata;

    /* Refresh image display here */

      if(xfm->drawn){ /* deal with existing rbanded region */
        dmode=fl_get_drawmode();
        fl_drawmode(GXxor); /* redraw box */
        fl_winset(win);
        fl_rectf(xfm->ox,xfm->oy,xfm->dx,xfm->dy,CLR);
        fl_drawmode(dmode);
      }
      return 0;
    }

    static int
    cross_hndl(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *data)
    {
      switch(xev->type ){
      case(EnterNotify):
        fl_set_cursor(win,XC_crosshair);
        break;
      case(LeaveNotify):
        fl_reset_cursor(win);
        fl_hide_oneliner();
        break;
      default:
        fl_print_xevent_name("Cross handler", xev);
      }
      return 0;
    }

    static int
    motion_hndl(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *data)
    {
      int dmode;
      char buf[50], *txt;
      XF_IM_DESC *xfm = (XF_IM_DESC *) ob->u_vdata;

      dmode=fl_get_drawmode();

      switch(xev->type ){

      case(MotionNotify):
        if( xfm != NULL && xfm->xy_lab != NULL){
          txt = xfm->xy_lab(xev->xmotion.x, xev->xmotion.y,
                            xev->xmotion.state, ob);
          fl_show_oneliner(txt, ob->x + ob->form->x, ob->y+ob->form->y-20);
        }else{
          sprintf(buf,"x: %.3d y:%.3d, msk=$%x",
                  xev->xmotion.x, xev->xmotion.y, xev->xmotion.state);
          fl_show_oneliner(buf,ob->x + ob->form->x, ob->y+ob->form->y-20);
        }

        if(xev->xmotion.state & (Button1Mask|Button3Mask)){ /*dragging*/
          fl_drawmode(GXxor);
          fl_winset(win);

          if(xfm->drawn){ /* deal with existing rbanded region */
            fl_rectf(xfm->ox,xfm->oy,xfm->dx,xfm->dy,CLR);
          }
          xfm->dx= xev->xmotion.x - xfm->ox;
          xfm->dy= xev->xmotion.y - xfm->oy;
          fl_rectf(xfm->ox,xfm->oy,xfm->dx,xfm->dy,CLR);
          xfm->drawn=1;
          fl_drawmode(dmode);
        }
        break;

      case(ButtonPress):
        switch (xev->xbutton.button) {
        case (Button1):
        case (Button3):
          if(xfm->drawn){ /* deal with existing rbanded region */
            fl_drawmode(GXxor); /* visually erase box */
            fl_winset(win);
            fl_rectf(xfm->ox,xfm->oy,xfm->dx,xfm->dy,CLR);
            fl_drawmode(dmode);
            xfm->drawn=0;
          }
          xfm->ox = xev->xbutton.x;
          xfm->oy = xev->xbutton.y;
          xfm->dx=xfm->dy=0;
          break;
        default:
    #ifdef DBG
          fprintf(stderr,"Unexpected Button Press $%x, State $%x\n",
                  xev->xbutton.button, xev->xbutton.state);
    #endif
          break;
        }
        break;
      case (ButtonRelease):
        switch (xev->xbutton.button) {
        case (Button1):
          break;
        case (Button3):
          break;
        default:
    #ifdef DBG
          fprintf(stderr,"Unexpected Button Release $%x, State $%x\n",
                  xev->xbutton.button, xev->xbutton.state);
    #endif
          break;
        }
        break;
      default:
        fl_print_xevent_name("Motion handler", xev);
      }

      return 0;
    }

    /*---------------------------------------*/

    --
    --------------------------------------------------------------------
        ___  ___/   _  __ /   Ivan Powis   [Ivan.Powis@Nottingham.ac.uk]
            /         /   /   School of Chemistry
           /         /  _/    University of Nottingham
          /         ___/      Nottingham NG7 2RD, UK
         /         /     TEL: +44-115-951-3467
        /         /      FAX: +44-115-951-3562
    _______/  ____/      http://www.chem.nott.ac.uk/IP.html
    --------------------------------------------------------------------
    

    _________________________________________________ To unsubscribe, send the message "unsubscribe" to xforms-request@bob.usuhs.mil or see http://bob.usuhs.mil/mailserv/xforms.html XForms Home Page: http://world.std.com/~xforms List Archive: http://bob.usuhs.mil/mailserv/list-archives/



    This archive was generated by hypermail 2b29 : Fri May 11 2001 - 12:05:23 EDT