EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: edm : TwoDProfileMonitorClass : cropping/resizing image
From: Kate Feng <[email protected]>
To: [email protected]
Date: Tue, 16 Mar 2010 10:25:11 -0400
First, thanks to Mark River and Xihui Chen.  I will add interfaces
to the plugins in the future, when I have more time.

Bruce Hill wrote :

We've had similar requests here at SLAC.   We use TwoDProfileMonitorClass
with EDM for our cameras, and are looking for an easier way to select
the region of interest.   We looked briefly into doing a Python/QT camera
viewer with this feature, but haven't had time to get serious about it.


If anyone has a solution for this, we'd be interested in hearing about it.

Attached is the implementation in the TwoDProfileMonitor.cc and video.edl. For now, it only shows the cursor and displays the X,Y locations of the cursors. By doing the one click action on the mouse(ie. oneClickAct PV), it will automatically define the upper left corner of the ROI. The width and height has to be defined in advance manually. For now, the implementation of the cursor location and one click act is enough for us.


Cheers, Kate


// g++ -shared -o TwoDProfileMonitor.so TwoDProfileMonitor.cc -g -O -Wall -ansi
// -pedantic -I/ade/epics/supTop/extensions/R3.14.4/src/edm/util
// -I/ade/epics/supTop/extensions/R3.14.4/src/edm/lib 
// -I/ade/epics/supTop/extensions/R3.14.4/src/edm/pvlib
// -I /ade/epics/supTop/base/R3.14.4/include -I/usr/X11R6/include
// -L/usr/X11R6/lib widget.cc -lXpm

// To Do: class initialization, serialization, configuration (all related)
// Any chance of allowing overlapped widgets to be on top?
// Originally obatined from Diamond Light Source
// Kate Feng:added the feature to show the cursor and its (X,Y) location, 2010

#define VIDEO_MAX_LOAD_FACTOR 4
#define VIDEO_MAJOR_VERSION 4
#define VIDEO_MINOR_VERSION 0
#define VIDEO_RELEASE 0

#include <time.h>
#include <stream.h>

#include <act_grf.h>
#include <act_win.h>
#include <app_pkg.h>
#include <entry_form.h>
#include <pv_factory.h>

#include "widget.h"
#include <Xm/XmStrDefs.h>

// Start of add by Kate Feng 
#define DATA_CONNECT_STATE             1
#define WIDTH_CONNECT_STATE            2
#define HEIGHT_CONNECT_STATE           4
#define CURSORX_CONNECT_STATE          8
#define CURSORY_CONNECT_STATE       0x10
#define ONECLICKACT_CONNECT_STATE   0x20

// End of add by Kate Feng 

// our widget class
class TwoDProfileMonitor : public activeGraphicClass
{

    // standard colours for various PV states
    pvColorClass pvColour; 

    // width of data (fixed or from PV)
    int dataWidth, dataHeight;
    int pvBasedDataSize;
    int setCursorX, setCursorY;  // Kate Feng : set the cursor location for ROI
    int oneClickAct; // Kate Feng : activate the ROI or XY lineout

    // globals for the edit popup
    int xBuf;
    int yBuf;
    int wBuf;
    int hBuf;
    char dataPvBuf[activeGraphicClass::MAX_PV_NAME+1];
    char widthPvBuf[activeGraphicClass::MAX_PV_NAME+1];
    char heightPvBuf[activeGraphicClass::MAX_PV_NAME+1];
    char setCursorXPvBuf[activeGraphicClass::MAX_PV_NAME+1];  // Kate Feng
    char setCursorYPvBuf[activeGraphicClass::MAX_PV_NAME+1];  // Kate Feng
    char oneClickActPvBuf[activeGraphicClass::MAX_PV_NAME+1];  // Kate Feng

    expStringClass dataPvStr, widthPvStr, heightPvStr;
    expStringClass setCursorXPvStr, setCursorYPvStr, oneClickActPvStr; // Kate Feng
    ProcessVariable *dataPv, *widthPv, *heightPv;
    ProcessVariable *setCursorXPv, *setCursorYPv, *oneClickActPv; // Kate Feng

    // text stuff (for edit mode drawing)
    char *textFontTag;
    int textAlignment;
    int textColour;

    int initialDataConnection, initialWidthConnection, initialHeightConnection;
    int initialCursorXConnection, initialCursorYConnection; // Kate Feng
    int initialOneClickActConnection;  // Kate Feng
    int needConnectInit, needInfoInit, needDraw, needRefresh;
    unsigned char pvNotConnectedMask;
    int dataPvExists, widthPvExists, heightPvExists;
    int setCursorXPvExists, setCursorYPvExists, oneClickActPvExists; // Kate Feng
    int init, active, activeMode;
    struct timeval lasttv;
    unsigned long average_time_usec;

    // widget-specific stuff
    widgetData wd;
    Widget twoDWidget;

    // constructor "helper" function
    void constructCommon (void);

public:

    // constructors/destructor
    TwoDProfileMonitor (void);
    TwoDProfileMonitor (const TwoDProfileMonitor &s);
    virtual ~TwoDProfileMonitor (void);

    // Called when the data process variable connects or disconnects
    static void monitorDataConnectState (ProcessVariable *pv,
                                         void *userarg );
    // Called when the width process variable connects or disconnects
    static void monitorWidthConnectState (ProcessVariable *pv,
                                          void *userarg );
    // Called when the height process variable connects or disconnects
    static void monitorHeightConnectState (ProcessVariable *pv,
                                          void *userarg );  
    // Beginning of add by Kate Feng
    // Called when the CursorX process variable connects or disconnects
    static void monitorCursorXConnectState (ProcessVariable *pv,
                                          void *userarg );
    // Called when the  CursorY process variable connects or disconnects
    static void monitorCursorYConnectState (ProcessVariable *pv,
                                          void *userarg );
    // Called when the  oneClickAct process variable connects or disconnects
    static void monitorOneClickActConnectState (ProcessVariable *pv,
                                          void *userarg );
    // end of add by Kate Feng
   
    // Called when the value of the data process variable changes
    static void dataUpdate (ProcessVariable *pv,
                            void *userarg );
    
    // Called when the value of the width or height process variable changes
    static void sizeUpdate (ProcessVariable *pv,
                            void *userarg );

    static void grabButtonEvent (Widget w, XtPointer closure, XEvent* event,
                                 Boolean* b)
    {
        TwoDProfileMonitor *me = (TwoDProfileMonitor *) closure;
        // normalize dimensions (button and motion events store x,y in the
        // same location)

#if 0
	// <skf> Relative location on the X window
       printf("(X,Y) = (%d, %d)\n", event->xbutton.x, event->xbutton.y);
#endif
       me->setCursorX = event->xbutton.x * me->dataWidth/me->getW();
       me->setCursorY = event->xbutton.y * me->dataHeight/me->getH();

       switch (event->xany.type) {
       case MotionNotify : 
         // printf("pointer motion\n");
         // Kate Feng : Update the cursor position PVs
         me->setCursorXPv->put((double) (me->setCursorX));
         me->setCursorYPv->put((double) (me->setCursorY));
	 break;
       case ButtonPress : 
	 //printf("Button Pressed\n");
         me->oneClickAct = 1;
         me->oneClickActPv->put((double) (1));
	 break;
       case ButtonRelease : 
	 //printf("Button Released\n");
         //me->oneClickAct = 0;
         //me->oneClickActPv->put((double) (0)); // Toggle off the action until next
         break;
       case ResizeRequest :
         printf("Resize request\n"); 
         break;
       case ConfigureRequest :
	 printf("ConfigureRequest\n");
         break;
       case EnterNotify : 
         /* printf("Enter\n"); */
         break;
       default:
         break;
       }
#if 0
       printf("pixel (X,Y) = (%d, %d)\n", me->setCursorX, me->setCursorY);
       sprintf(me->setCursorXPvBuf,"%d", me->setCursorX);
       sprintf(me->setCursorYPvBuf,"%d", me->setCursorY);
#endif

       event->xbutton.x += me->getX0 (); // <skf> Absolute location on the X window
       event->xbutton.y += me->getY0 ();
    
        // now send this event to EDM
        XtDispatchEventToWidget (me->actWin->executeWidget, event);
        
#if 0      
	printf("(W,H) = (%d, %d), (DW,DH) = (%d, %d)\n", me->getW(), me->getH(),me->dataWidth, me->dataHeight);
#endif
        *b = False; // terminate this "dispatch path"
    }
  

    virtual int draw ( void ); 
  
    // called in response to "cut" command
    virtual int erase ( void );  
  
    virtual int activate (int pass);
  
    // apply the results of either "Apply" or "OK" buttons
    void applyEditChanges (void);
  
    // user hit the "OK" button on the edit popup
    static void editOK (Widget w,
                        XtPointer client,
                        XtPointer call );
    // user hit the "Apply" button on the edit popup
    static void editApply (Widget w,
                           XtPointer client,
                           XtPointer call );
    // user hit the "Cancel" button on the edit popup
    static void editCancel (Widget w,
                            XtPointer client,
                            XtPointer call );
 
    // user hit the "Cancel" button on the edit popup during widget creation
    static void editCancelCreate (Widget w,
                                  XtPointer client,
                                  XtPointer call );
 
    // "helper" function for editing widget under a variety of circumstances
    void editCommon ( activeWindowClass *actWin, entryFormClass *ef,
                      int create = 0 ) ;

    // user created object from GUI (after drawing rectangle)
    virtual int createInteractive (activeWindowClass *actWin,
                                   int x,
                                   int y,
                                   int w,
                                   int h );

    // object created from saved description on disk
    virtual int createFromFile (FILE *fptr,
                                char *name,
                                activeWindowClass *actWin );

    // object created from ????
    virtual int importFromXchFile (FILE *fptr,
                                   char *name,
                                   activeWindowClass *actWin );

    // save to disk
    virtual int save ( FILE *fptr );

    virtual int edit ( void );
  
    // ========================================================
    // execute mode widget functions
  
    virtual int deactivate ( int pass );
  
    virtual int initDefExeNode ( void *ptr )
    { 
        aglPtr = ptr; /* why isn't this done for me? */
        return activeGraphicClass::initDefExeNode (ptr);
    }
  
    virtual int expand1st (int numMacros,
                           char *macros[],
                           char *expansions[] ) 
    {
        int stat; 
        stat = dataPvStr.expand1st (numMacros, macros, expansions);
        if (stat)
            stat = widthPvStr.expand1st (numMacros, macros, expansions);
        if (stat)
            stat = heightPvStr.expand1st (numMacros, macros, expansions);
        if (stat)
            stat = setCursorXPvStr.expand1st (numMacros, macros, expansions);
        if (stat)
            stat = setCursorYPvStr.expand1st (numMacros, macros, expansions);
        if (stat)
            stat = oneClickActPvStr.expand1st (numMacros, macros, expansions);
        return stat;
    
    }
  
    // currently only used by mux devices (which we are not) 
    virtual int expand2nd (int numMacros,
                           char *macros[],
                           char *expansions[] )
    {
        int stat; 
        stat = dataPvStr.expand2nd (numMacros, macros, expansions);
        if (stat)
            stat = widthPvStr.expand2nd (numMacros, macros, expansions);
        if (stat)
            stat = heightPvStr.expand2nd (numMacros, macros, expansions);
        if (stat)
            stat = setCursorXPvStr.expand2nd (numMacros, macros, expansions);
        if (stat)
            stat = setCursorYPvStr.expand2nd (numMacros, macros, expansions);
        if (stat)
            stat = oneClickActPvStr.expand2nd (numMacros, macros, expansions);

        return stat;
    
    }
  
    // currently only used by mux devices (which we are not) 
    virtual int containsMacros ( void )
    {
        return dataPvStr.containsPrimaryMacros () ? 1 : 0;
    }
 
    template<class T> double * to_double (unsigned size, const T * data)
    {
        double * temp = (double *) malloc (sizeof (double) * size);
        for (unsigned s = 0; s < size; ++s)
        {
            temp[s] = data[s];
        }
        return temp;
    }

    static double *int_to_double (size_t s, const int *i)
    {

        double *d = (double *) malloc (sizeof (double)*s);
        if (!d) return d;
        for (size_t index = 0; index < s; index++)
        {
            d[index] = i[index];
        }
        return d;
    } 
    // here is where we deal with updating the execute-mode widget (data and
    //  connect state)
    virtual void executeDeferred ( void )
    {
        int ni, nc, nr;
        struct timeval tv;

        if (actWin->isIconified) 
             return;
        // The widget may not be able to handle video data as fast as it is
        // produced (particularly if it is displaying a large image on a
        // remote X display).  If this happens, unprocessed channel access
        // data is queued for transmission in the IOC and eventually some 
        // has to be discarded.  What is lost is not necessarily video data, 
        // with the result that other edm widgets appear to stop working.
        // To avoid this happening, we must make sure we receive all screen
        // images that are produced and ignore any we haven't time to put out.
        // The following code does this.
        gettimeofday (&tv, 0);
        unsigned long elapsedusec = (tv.tv_sec - lasttv.tv_sec) * 1000000 + tv.tv_usec - lasttv.tv_usec;
#ifdef DEBUG
        printf ("TwoDProfMon::executeDeferred - elapsed time = %lu\n", elapsedusec);
#endif
        if (elapsedusec < average_time_usec * VIDEO_MAX_LOAD_FACTOR)
            return;
        lasttv.tv_sec = tv.tv_sec;
        lasttv.tv_usec = tv.tv_usec;

        actWin->appCtx->proc->lock ();
        nc = needConnectInit; needConnectInit = 0;
        ni = needInfoInit; needInfoInit = 0;
        nr = needRefresh; needRefresh = 0;
        actWin->remDefExeNode (aglPtr);
        actWin->appCtx->proc->unlock ();
        if (!activeMode)
            return;

        if (nc)
        {
            ni = 1;
        }
 
        if (ni)
        {
            active = 1;
            init = 1;
            if (initialDataConnection)
            {
                initialDataConnection = 0;
#ifdef DEBUG
                printf (
                    "TwoDProfMon::execDeferred - add data value callback\n");
#endif
                dataPv->add_value_callback ( dataUpdate, this );
            }
            if (initialWidthConnection)
            {
                initialWidthConnection = 0;
#ifdef DEBUG
                printf (
                    "TwoDProfMon::execDeferred - add width value callback\n");
#endif
                widthPv->add_value_callback ( sizeUpdate, this );
            }
            if (initialHeightConnection)
            {
                initialHeightConnection = 0;
#ifdef DEBUG
                printf (
                    "TwoDProfMon::execDeferred - add height value callback\n");
#endif
                heightPv->add_value_callback ( sizeUpdate, this );
            }
        }
        
        // need to check if we're being updated because of width change
        // printf ("executeDeferred (TwoDMon.cc) - pvBasedDataWidth = %d\n",
        //         pvBasedDataWidth);
        // printf ("executeDeferred (TwoDMon.cc) - widthPv = %x\n", widthPv);
        // printf ("executeDeferred (TwoDMon.cc) - is_valid = %d\n",
        //         widthPv->is_valid ());
        if (pvBasedDataSize && widthPv && widthPv->is_valid ())
        {
            // printf ("executeDeferred (TwoDMon.cc) - pv based width\n");
            switch (widthPv->get_type ().type)
            {
            case ProcessVariable::Type::real:
                dataWidth = (int) widthPv->get_double ();
                break;
            case ProcessVariable::Type::integer:
                dataWidth = (int) widthPv->get_int ();
                break;
            default:
                dataWidth = -1;
                break;
            }
#ifdef DEBUG
            printf ("executeDeferred (TwoDMon.cc) - width = %d\n", dataWidth);
#endif
            if (heightPv && heightPv->is_valid ())
            {
                switch (heightPv->get_type ().type)
                {
                case ProcessVariable::Type::real:
                    dataHeight = (int) heightPv->get_double ();
                    break;
                case ProcessVariable::Type::integer:
                    dataHeight = (int) heightPv->get_int ();
                    break;
                default:
                    dataHeight = -1;
                }
            }
            if (setCursorXPv && setCursorXPv->is_valid ())
            {
                switch (setCursorXPv->get_type ().type)
                {
                case ProcessVariable::Type::real:
		  //printf("CursoX real\n");  /* Called often */
		     setCursorX = atoi ( setCursorXPvBuf );
		     //setCursorX = (int) setCursorXPv->get_double ();
                    break;
                case ProcessVariable::Type::integer:
		  //printf("CursoX int\n");
                    setCursorX = (int) setCursorXPv->get_int ();
                    break;
                default:
		  //printf("CursoX default\n");
                    setCursorX = -1;
                    break;
                }
            }
            if (setCursorYPv && setCursorYPv->is_valid ())
            {
                switch (setCursorYPv->get_type ().type)
                {
                case ProcessVariable::Type::real:
                    setCursorY = (int) setCursorYPv->get_double ();
                    break;
                case ProcessVariable::Type::integer:
                    setCursorY = (int) setCursorYPv->get_int ();
                    break;
                default:
                    setCursorY = -1;
                }
            }
            if (oneClickActPv && oneClickActPv->is_valid ())
            {
                switch (oneClickActPv->get_type ().type)
                {
                case ProcessVariable::Type::real:
                    oneClickAct = (int) oneClickActPv->get_double ();
                    break;
                case ProcessVariable::Type::integer:
                    oneClickAct = (int) oneClickActPv->get_int ();
                    break;
                default:
                    oneClickAct = -1;
                }
            }

        }
    
        if (dataWidth <= 0 || dataHeight < 0)  return;
    
        actWin->appCtx->proc->lock ();
    
        if (dataPv && dataPv->is_valid ())
        {
      
            switch (dataPv->get_type ().type)
            {
        
            case ProcessVariable::Type::real:
                 printf ("real\n");
                widgetNewDisplayData (
                    wd, dataPv->get_time_t (), dataPv->get_nano (),
                    (unsigned long) w, (unsigned long) h, dataWidth,
                    (dataHeight > 0 ? dataHeight 
                                    : dataPv->get_dimension () / dataWidth),
                    (const double *) dataPv->get_double_array ());
                break;

            case ProcessVariable::Type::text:
                {
		    // int dim = dataPv->get_dimension ();
                    // char const * data = dataPv->get_char_array ();
                    // printf ("text (%d, %08x)\n", dim, (int)data);
                    double * temp = to_double<char>(
                                        dataPv->get_dimension (),
                                        dataPv->get_char_array ());
                    // struct timeval tv;
                    // gettimeofday (&tv, 0);
                    // printf ("2dProfMon: executeDeferred - time %ld %ld\n",
                    //          tv.tv_sec, tv.tv_usec);
                    widgetNewDisplayData (
                        wd, dataPv->get_time_t (), dataPv->get_nano (),
                        (unsigned long)w, (unsigned long) h, dataWidth,
                        (dataHeight > 0 ? dataHeight 
                                        : dataPv->get_dimension() / dataWidth),
                        temp);
                   free (temp);
                }
                break;

            case ProcessVariable::Type::integer:
                // printf ("int\n");
                {
                    double* temp = int_to_double (dataPv->get_dimension (),
                                                  dataPv->get_int_array ());
                    widgetNewDisplayData (
                        wd, dataPv->get_time_t (), dataPv->get_nano (),
                        (unsigned long) w, (unsigned long) h, dataWidth,
                        (dataHeight > 0 ? dataHeight 
                                        : dataPv->get_dimension() / dataWidth),
                        temp);
                    free (temp);
                }
                break;

            default:
                // nothing to do!
                break;
            }
            widgetNewDisplayInfo (wd, true, dataPv->get_status (),
                                  dataPv->get_severity ());
        }
        else
        {
            widgetNewDisplayInfo (wd, false, 0, 0);
        }
    
        // actWin->remDefExeNode (aglPtr);
    
        actWin->appCtx->proc->unlock ();
    
        // Get approx average elapsed time for call - no point in being precise
        gettimeofday (&tv, 0);
        elapsedusec = (tv.tv_sec - lasttv.tv_sec) * 1000000 + tv.tv_usec - lasttv.tv_usec;
        if (!average_time_usec)
            average_time_usec = elapsedusec;
        else
            average_time_usec = (average_time_usec * 9 + elapsedusec) / 10;
#ifdef DEBUG
        printf ("TwoDProfMon::executeDeferred - average elapsed time = %lu\n", average_time_usec);
#endif
    }
  
    // let the user select among a field of functional names for drag-n-drop
    virtual char *firstDragName ( void ){ return "data PV"; };
    virtual char *nextDragName ( void ){ return NULL; } ;
  

    virtual char *dragValue ( int i )
    { return i ? NULL : dataPvStr.getExpanded (); };
  
    // yes we use PVs, therefore we support drag-n-drop and info dialogs
    virtual int atLeastOneDragPv (int x,
                                  int y ){ return 1; };
 
    // this one is to support an info dialog about widget-related PVs
    virtual void getPvs (int max,
                         ProcessVariable *pvs[],
                         int *n ){ *n = 1; pvs[0] = dataPv;};
  
    // This is a funny interface. It seems that the idea is to have a generic
    // interface to all widgets with a "standard" set of parameters (e.g.
    // control PV).  However, there doesn't seem to be a clean way to associate
    // widget values with their generic equivalents. I.e. the generic "control
    // PV" name is maintained in actWin->allSelectedCtlPvName[0]. One *could*
    // use that data storage for the control PV for a widget, but it is not
    // obvious (to me) that that interface is encouraged (or is guaranteed to
    // be supported in the future).

    // what I will do here is what most of the widgets do, which is to pick
    // out of the user supplied values anything that I see an obvious equivalent
    // in my "private" parameters, and copy in that data. Note that my "private"
    // equivalent might change (via the "edit" popup, and that change will not
    // be reflected in this popup. I *could* "blank out" the fields I use after
    // copying out the data, but that is not the behavior implemented in other
    // widgets.

    // I think that the *good* thing about this interface is that it hints at
    // what parameters each widget should support

    virtual void changePvNames (int flag,
                                int numCtlPvs,
                                char *ctlPvs[],
                                int numReadbackPvs,
                                char *readbackPvs[],
                                int numNullPvs,
                                char *nullPvs[],
                                int numVisPvs,
                                char *visPvs[],
                                int numAlarmPvs,
                                char *alarmPvs[] )
    {

        if ((flag & ACTGRF_READBACKPVS_MASK) && numReadbackPvs)
            dataPvStr.setRaw (readbackPvs[0]);

    }

    // see previous comments
  
    virtual void changeDisplayParams (unsigned int flag,
                                      char *fontTag,
                                      int alignment,
                                      char *ctlFontTag,
                                      int ctlAlignment,
                                      char *btnFontTag,
                                      int btnAlignment,
                                      int textFgColour,
                                      int fg1Colour,
                                      int fg2Colour,
                                      int offsetColour,
                                      int bgColour,
                                      int topShadowColour,
                                      int botShadowColour )
    {

        if (flag & ACTGRF_FONTTAG_MASK) textFontTag = fontTag; // strcpy???
        if (flag & ACTGRF_ALIGNMENT_MASK) textAlignment = alignment; 
        if (flag & ACTGRF_TEXTFGCOLOR_MASK) textColour = textFgColour;
    }
  
private:
  
    TwoDProfileMonitor &operator=(const TwoDProfileMonitor &s);
  
};


// class for read/write tags
// I like to break this out because it forces me to
// enumerate all the data memebers that are saved
// It is more work, but less error-prone (IMHO)
class TwoDProfileMonitorTags : public tagClass 
{

public:
    TwoDProfileMonitorTags (void){ init (); }
    ~TwoDProfileMonitorTags (){}
  
    int read (TwoDProfileMonitor* mon,
              FILE *fptr,
              int *x, int *y, int *w, int *h,
              expStringClass *dataPvStr,
              expStringClass *widthPvStr,
              expStringClass *heightPvStr,
	      // Beginnig of add by Kate Feng
              expStringClass *setCursorXPvStr,
              expStringClass *setCursorYPvStr,
              expStringClass *oneClickActPvStr,
	      // End of add by Kate Feng
              int *dataWidth,
              int *pvBasedDataSize)
    {
        int major, minor, release;
        int stat;
        loadR ("beginObjectProperties" );
        loadR ( "major", &major );
        loadR ( "minor", &minor );
        loadR ( "release", &release );
        loadR ( "x", x );
        loadR ( "y", y );
        loadR ( "w", w );
        loadR ( "h", h );
        loadR ( "dataPvStr", dataPvStr, (char *) "" );
        loadR ( "widthPvStr", widthPvStr, (char *) "" );
        loadR ( "heightPvStr", heightPvStr, (char *) "" ); 
	// Beginnig of add by Kate Feng
        loadR ( "setCursorXPvStr", setCursorXPvStr, (char *) "" );
        loadR ( "setCursorYPvStr", setCursorYPvStr, (char *) "" ); 
        loadR ( "oneClickActPvStr", oneClickActPvStr, (char *) "" ); 
	// End of add by Kate Feng
        loadR ( "dataWidth", dataWidth);
        loadR ( "pvBasedDataSize", pvBasedDataSize);
        stat = readTags ( fptr, "endObjectProperties" );
        if (major > VIDEO_MAJOR_VERSION ||
            (major == VIDEO_MAJOR_VERSION && minor > VIDEO_MINOR_VERSION))
        {
             // edl file was produced by a more recent version of edm than 
             // this and we can't predict the future
             mon->postIncompatable ();
             return 0;
        }
        if (major < VIDEO_MAJOR_VERSION)
        {
             // Major version changes render old edl files incompatible
             mon->postIncompatable ();
             return 0;
        }
        return stat;
    }
    int write (FILE *fptr,
               int *x, int *y, int *w, int *h,
               expStringClass *dataPvStr,
               expStringClass *widthPvStr,
               expStringClass *heightPvStr,
	       // Beginnig of add by Kate Feng
               expStringClass *setCursorXPvStr,
               expStringClass *setCursorYPvStr,
               expStringClass *oneClickActPvStr,
	       // End of add by Kate Feng 
               int *dataWidth,
               int *pvBasedDataSize)
    {
        int major, minor, release;
        major = VIDEO_MAJOR_VERSION;
        minor = VIDEO_MINOR_VERSION;
        release = VIDEO_RELEASE;
        loadW ("beginObjectProperties" );
        loadW ( "major", &major );
        loadW ( "minor", &minor );
        loadW ( "release", &release );
        loadW ( "x", x );
        loadW ( "y", y );
        loadW ( "w", w );
        loadW ( "h", h );
        loadW ( "dataPvStr", dataPvStr, (char *) "" );
        loadW ( "widthPvStr", widthPvStr, (char *) "" );
        loadW ( "heightPvStr", heightPvStr, (char *) "" ); 
	// Beginnig of add by Kate Feng
        loadW ( "setCursorXPvStr", setCursorXPvStr, (char *) "" );
        loadW ( "setCursorYPvStr", setCursorYPvStr, (char *) "" ); 
        loadW ( "oneClickActPvStr", oneClickActPvStr, (char *) "" ); 
	// End of add by Kate Feng 
        loadW ( "dataWidth", dataWidth);
        loadW ( "pvBasedDataSize", pvBasedDataSize);
        loadW ( "endObjectProperties" );
        loadW ( "" );
  
        return writeTags ( fptr );
    }

private:
    TwoDProfileMonitorTags (const TwoDProfileMonitorTags &s);
    TwoDProfileMonitorTags &operator= (const TwoDProfileMonitorTags &s);

};


// stuff needed for EDM to load from DLL
extern "C" 
{

    void *create_TwoDProfileMonitorClassPtr ( void )
    {

        return (new TwoDProfileMonitor ());

    }

}

extern "C"
{

    void *clone_TwoDProfileMonitorClassPtr ( void *s )
    {

        return (new TwoDProfileMonitor (*(TwoDProfileMonitor *)s));

    }

}

// Support registration
#include "environment.str"

typedef struct libRecTag
{
    char *className;
    char *typeName;
    char *text;
} libRecType, *libRecPtr;

static int libRecIndex = 0;

static libRecType libRec[] = 
{
    { "TwoDProfileMonitor", global_str2, "New Monitor" }
};

extern "C" 
{

    int firstRegRecord (char **className,
                        char **typeName,
                        char **text )
    {
    
        libRecIndex = 0;
    
        *className = libRec[libRecIndex].className;
        *typeName = libRec[libRecIndex].typeName;
        *text = libRec[libRecIndex].text;
    
        return 0; // OK
    
    }
  
    int nextRegRecord (char **className,
                       char **typeName,
                       char **text )
    {
    
        if (libRecIndex >= sizeof (libRec)/sizeof (libRecType) - 1)
            return -1; // done
        ++libRecIndex;
    
        *className = libRec[libRecIndex].className;
        *typeName = libRec[libRecIndex].typeName;
        *text = libRec[libRecIndex].text;
    
        return 0; // OK
    
    }
  
}

void TwoDProfileMonitor::constructCommon (void)
{

    /* start off not knowing image data width */
    pvBasedDataSize = 0;
    dataWidth = -1;
    dataHeight = 0; // 0 if no PV supplied which is OK, -1 if invalid PV
    activeMode = 0;

    wd = widgetCreate ();
    twoDWidget = NULL;

    name = "TwoDProfileMonitorClass";
  
    dataPvStr.setRaw ("");
    widthPvStr.setRaw ("");
    heightPvStr.setRaw ("");
    // Beginning of add by Kate Feng 
    setCursorXPvStr.setRaw ("");
    setCursorYPvStr.setRaw ("");
    oneClickActPvStr.setRaw ("");
    // End of add by Kate Feng  
    dataPv = NULL;
    heightPv = NULL;

    strcpy (dataPvBuf, ""); // just to be safe
    strcpy (widthPvBuf, ""); // just to be safe
    strcpy (heightPvBuf, ""); // just to be safe
    // Beginning of add by Kate Feng 
    strcpy (setCursorXPvBuf, ""); // just to be safe
    strcpy (setCursorYPvBuf, ""); // just to be safe
    strcpy (oneClickActPvBuf, ""); // just to be safe
    // End of add by Kate Feng  

    twoDWidget = NULL;

    average_time_usec = 0;

#if (0)
    // text stuff (for edit mode drawing)
    char *textFontTag;
    int textAlignment;
    int textColour;
#endif

}

TwoDProfileMonitor::TwoDProfileMonitor (void) : activeGraphicClass () 
{ 
  
    constructCommon ();
}


TwoDProfileMonitor::TwoDProfileMonitor (const TwoDProfileMonitor &s)
{ 
  
    // clone base class data
    // why doesn't activeGraphicClass copy constructor do this?
    activeGraphicClass::clone ( &s );

    constructCommon ();

    // does the copy constructor work?
    // dataPvStr = s.dataPvStr;
    // widthPvStr = s.widthPvStr;
    dataPvStr.setRaw (s.dataPvStr.rawString);
    widthPvStr.setRaw (s.widthPvStr.rawString);
    heightPvStr.setRaw (s.heightPvStr.rawString);
    setCursorXPvStr.setRaw (s.setCursorXPvStr.rawString);
    setCursorYPvStr.setRaw (s.setCursorYPvStr.rawString);
    oneClickActPvStr.setRaw (s.oneClickActPvStr.rawString);

    pvBasedDataSize = s.pvBasedDataSize;
    dataWidth = s.dataWidth; 
}

TwoDProfileMonitor::~TwoDProfileMonitor (void) {widgetDestroy (wd);}

// called when widget is made active as edm changes to "execute" mode,
// pass values are 0-6
int TwoDProfileMonitor::activate ( int pass )
{
    Arg args[10];
    int n;

    switch (pass)
    {
    case 1:
        initialDataConnection = 1;
        initialWidthConnection = 0;
        initialHeightConnection = 0;
        needConnectInit = needInfoInit = needRefresh = 0;
        pvNotConnectedMask = active = init = 0;
        activeMode = 1;

        if (!dataPvStr.getExpanded () ||
            blankOrComment (dataPvStr.getExpanded ()))
        {
            dataPvExists = 0;
        }
        else
        {
            dataPvExists = 1;
            pvNotConnectedMask |= DATA_CONNECT_STATE;
        }

        if (!pvBasedDataSize)
        {
            widthPvExists = 0;
            heightPvExists = 0;
            setCursorXPvExists = 0;
            setCursorYPvExists = 0;
	    oneClickActPvExists = 0;
        }
        else
        {
            if (!widthPvStr.getExpanded () ||
                blankOrComment (widthPvStr.getExpanded ()))
            {
                widthPvExists = 0;
            }
            else
            {
                widthPvExists = 1;
                initialWidthConnection = 1;
                pvNotConnectedMask |= WIDTH_CONNECT_STATE;
            }
            if (!heightPvStr.getExpanded () ||
                blankOrComment (heightPvStr.getExpanded ()))
            {
                heightPvExists = 0;
            }
            else
            {
                heightPvExists = 1;
                initialHeightConnection = 1;
                pvNotConnectedMask |= HEIGHT_CONNECT_STATE;
            }
            if (!setCursorXPvStr.getExpanded () ||
                blankOrComment (setCursorXPvStr.getExpanded ()))
            {
                setCursorXPvExists = 0;
            }
            else
            {
                setCursorXPvExists = 1;
                initialCursorXConnection = 1;
                pvNotConnectedMask |= CURSORX_CONNECT_STATE;
            }
            if (!setCursorYPvStr.getExpanded () ||
                blankOrComment (setCursorYPvStr.getExpanded ()))
            {
                setCursorYPvExists = 0;
            }
            else
            {
                setCursorYPvExists = 1;
                initialCursorYConnection = 1;
                pvNotConnectedMask |= CURSORY_CONNECT_STATE;
            }
            if (!oneClickActPvStr.getExpanded () ||
                blankOrComment (oneClickActPvStr.getExpanded ()))
            {
                oneClickActPvExists = 0;
            }
            else
            {
                oneClickActPvExists = 1;
                initialOneClickActConnection = 1;
                pvNotConnectedMask |= ONECLICKACT_CONNECT_STATE;
            }
        }

#ifdef DEBUG
        printf (
            "TwoDProfileMonitor::activate pass 1 - pvNotConnectedMask = %d\n",
            pvNotConnectedMask);
#endif
        break;
    
        // connect PVs during pass 2
    case 2:
        {
            // assume the best!
            pvColour.setColorIndex ( actWin->defaultTextFgColor, actWin->ci );
      

            if (!dataPvExists) 
                break; // don't bother the factory

            dataPv = the_PV_Factory->create ( dataPvStr.getExpanded () );
            if ( dataPv )
            {
#ifdef DEBUG             
                printf (
                    "TwoDProfMon::activate pass 2 - add data connect cb\n"); 
#endif
                dataPv->add_conn_state_callback (monitorDataConnectState,
                                                 this);
                //dataPv->add_value_callback ( pvUpdate, this );
            }
     
            if (!widthPvExists)
                break; // no need to set up width PV
            // printf ("activate (TwoDMon.cc) - width PV = %s = %s\n", 
            //         widthPvStr.getRaw(),
            //         widthPvStr.getExpanded());
            widthPv = the_PV_Factory->create ( widthPvStr.getExpanded () );
            if ( widthPv )
            {
#ifdef DEBUG
                printf (
                    "TwoDProfMon::activate pass 2 - adding width connect cb\n");
#endif
                widthPv->add_conn_state_callback (monitorWidthConnectState,
                                                  this);
                //widthPv->add_value_callback ( pvUpdate, this );
            }
            if (!heightPvExists)
                break; // no need to set up height PV
            // printf ("activate (TwoDMon.cc) - height PV = %s = %s\n", 
            //         heightPvStr.getRaw(),
            //         heightPvStr.getExpanded());
            heightPv = the_PV_Factory->create ( heightPvStr.getExpanded () );
            if ( heightPv )
            {
#ifdef DEBUG
                printf (
                    "TwoDProfMon::activate pass 2 - adding height connect cb\n");
#endif
                heightPv->add_conn_state_callback (monitorHeightConnectState,
                                                  this);
                //heightPv->add_value_callback ( pvUpdate, this );
            }
            if (!setCursorXPvExists)
                break; // no need to set up setCursorX PV
            // printf ("activate (TwoDMon.cc) - setCursorX PV = %s = %s\n", 
            //         setCursorXPvStr.getRaw(),
            //         setCursorXPvStr.getExpanded());
            setCursorXPv = the_PV_Factory->create ( setCursorXPvStr.getExpanded () );
            if ( setCursorXPv )
            {
#ifdef DEBUG
                printf (
                    "TwoDProfMon::activate pass 2 - adding setCursorX connect cb\n");
#endif
                setCursorXPv->add_conn_state_callback (monitorCursorXConnectState,
                                                  this);
		// setCursorXPv->add_value_callback ( pvUpdate, this );
            }
            if (!setCursorYPvExists)
                break; // no need to set up setCursorY PV
            // printf ("activate (TwoDMon.cc) - setCursorY PV = %s = %s\n", 
            //         setCursorYPvStr.getRaw(),
            //         setCursorYPvStr.getExpanded());
            setCursorYPv = the_PV_Factory->create ( setCursorYPvStr.getExpanded () );
            if ( setCursorYPv )
            {
#ifdef DEBUG
                printf (
                    "TwoDProfMon::activate pass 2 - adding setCursorY connect cb\n");
#endif
                setCursorYPv->add_conn_state_callback (monitorCursorYConnectState,
                                                  this);
                // setCursorYPv->add_value_callback ( pvUpdate, this );
            }
            if (!oneClickActPvExists)
                break; // no need to set up oneClickAct PV
            // printf ("activate (TwoDMon.cc) - oneClickAct PV = %s = %s\n", 
            //         oneClickActPvStr.getRaw(),
            //         oneClickActPvStr.getExpanded());
            oneClickActPv = the_PV_Factory->create ( oneClickActPvStr.getExpanded () );
            if ( oneClickActPv )
            {
#ifdef DEBUG
                printf (
                    "TwoDProfMon::activate pass 2 - adding oneClickAct connect cb\n");
#endif
                oneClickActPv->add_conn_state_callback (monitorOneClickActConnectState,
                                                  this);
		// oneClickActPv->add_value_callback ( pvUpdate, this );
            }
#ifdef DEBUG
            printf ("activate (TwoDMon.cc) - dataPv->is_valid = %d\n",
                    dataPv->is_valid ());
            printf ("activate (TwoDMon.cc) - widthPv->is_valid = %d\n",
                    widthPv->is_valid ());
            printf ("activate (TwoDMon.cc) - heightPv->is_valid = %d\n",
                    heightPv->is_valid ());
#endif
        }
        break;

        // OK, now create the widget
    case 6:

        // create the execute-mode widget using XRT or other
        // standard Motif 2-D data widget
        twoDWidget = widgetCreateWidget (
                         wd, actWin->appCtx->appContext (), actWin->d,
                         actWin->ci->getColorMap (), actWin->executeWidget,
                         x, y, h, w);

        // capture events to pass on to EDM
        XtAddEventHandler (
            twoDWidget,
            LeaveWindowMask | EnterWindowMask | PointerMotionMask |
            ButtonPressMask |ButtonReleaseMask | ResizeRedirectMask | StructureNotifyMask,
            False, grabButtonEvent, (XtPointer) this);
   
        // hand over control 
        XtManageChild (twoDWidget);
 
    /* Beginning of add by Kate Feng : set cursor to be cross hair */
    actWin->cursor.setColor(actWin->ci->pix(actWin->fgColor),actWin->ci->pix(actWin->bgColor));

    actWin->cursor.set( XtWindow(twoDWidget), CURSOR_K_CROSSHAIR);
    n = 0;
    XtSetArg( args[n], XmNcursorPositionVisible, (XtArgVal) True ); n++;
    XtSetValues(twoDWidget, args, n );

#ifdef DEBUG
    printf("Add cursor\n"); 
#endif

    /* End of add by Kate Feng : set cursor to be cross hair */

        break;


    default:
        break;
    
    }
  
    return 1;
}
 
// user hit the "OK" button on the edit popup
void TwoDProfileMonitor::editOK (Widget w,
                                 XtPointer client,
                                 XtPointer call )
{
  
    TwoDProfileMonitor *me = (TwoDProfileMonitor *) client;

    // first apply any changes
    editApply (w, client, call); 

    me->ef.popdown ();
    me->operationComplete ();
  
}
  
// user hit the "Apply" button on the edit popup
void TwoDProfileMonitor::editApply (Widget w,
                                    XtPointer client,
                                    XtPointer call )
{
  
    TwoDProfileMonitor *me = (TwoDProfileMonitor *) client;

    me->eraseSelectBoxCorners ();
    me->erase ();

    me->x = me->xBuf;
    me->y = me->yBuf;
    me->w = me->wBuf;
    me->h = me->hBuf;
    me->sboxX = me->xBuf;
    me->sboxY = me->yBuf;
    me->sboxW = me->wBuf;
    me->sboxH = me->hBuf;

    // do the PV name(s)
    me->dataPvStr.setRaw ( me->dataPvBuf );

    // now the width: if fixed is indicated, interpret PV string as int
    me->widthPvStr.setRaw ( me->widthPvBuf );
    if (!me->pvBasedDataSize)
         me->dataWidth = atoi ( me->widthPvBuf );
    else
         me->dataWidth = -1; // just to be safe

    me->heightPvStr.setRaw ( me->heightPvBuf );
    me->dataHeight = 0;  // correct if PV null, will be overwritten otherwise
    // support auto-save
    me->actWin->setChanged ();

  // let EDM know that "Apply" was invoked
  me->refresh ();
  
}

// user hit the "Cancel" button on the edit popup
void TwoDProfileMonitor::editCancel (Widget w,
                                     XtPointer client,
                                     XtPointer call )
{
  
    TwoDProfileMonitor *me = (TwoDProfileMonitor *) client;
    
    me->ef.popdown ();

    // no need for EDM to do anything
    me->operationCancel ();
    
}

// user hit the "Cancel" button on the edit popup
void TwoDProfileMonitor::editCancelCreate (Widget w,
                                           XtPointer client,
                                           XtPointer call )
{
  
    TwoDProfileMonitor *me = (TwoDProfileMonitor *) client;
  
    me->ef.popdown ();
  
    // remove all traces of our existence!
    me->erase ();
    me->deleteRequest = 1;
  
    // no need for EDM to do anything
    me->operationCancel ();
  
}

void TwoDProfileMonitor::editCommon ( activeWindowClass *actWin,
                                      entryFormClass *_ef, int create )
{

    // create edit box
    ef.create ( actWin->top, actWin->appCtx->ci.getColorMap (),
                &actWin->appCtx->entryFormX,
                &actWin->appCtx->entryFormY, &actWin->appCtx->entryFormW,
                &actWin->appCtx->entryFormH, &actWin->appCtx->largestH,
                "2D Profile Monitor Properties", NULL, NULL, NULL );

    xBuf = x;
    yBuf = y;
    wBuf = w;
    hBuf = h;

    ef.addTextField ("X", 30, &xBuf);
    ef.addTextField ("Y", 30, &yBuf);
    ef.addTextField ("Widget Width", 30, &wBuf);
    ef.addTextField ("Widget Height", 30, &hBuf);
    // copy out, we'll copy in during "Apply"
    strncpy (dataPvBuf, dataPvStr.getRaw (), sizeof (dataPvBuf) - 1);
    ef.addTextField ("Data PV", 30, dataPvBuf, sizeof (dataPvBuf) - 1);

    // copy out, we'll copy in during "Apply"
    strncpy (widthPvBuf, widthPvStr.getRaw (), sizeof (widthPvBuf) - 1);
    ef.addTextField ("Data Width (Fixed/PV)", 30, widthPvBuf,
                     sizeof (widthPvBuf) - 1);
    strncpy (heightPvBuf,heightPvStr.getRaw (), sizeof (heightPvBuf) - 1);
    ef.addTextField ("Data Height PV (ignored for fixed size)",
                     30, heightPvBuf, sizeof (heightPvBuf) - 1);

    // copy out, we'll copy in during "Apply"
    strncpy (setCursorXPvBuf, setCursorXPvStr.getRaw (), sizeof (setCursorXPvBuf) - 1);
    ef.addTextField ("Data Width (Fixed/PV)", 30, setCursorXPvBuf,
                     sizeof (setCursorXPvBuf) - 1);
    strncpy (setCursorYPvBuf,setCursorYPvStr.getRaw (), sizeof (setCursorYPvBuf) - 1);
    ef.addTextField ("Data Height PV (ignored for fixed size)",
                     30, setCursorYPvBuf, sizeof (setCursorYPvBuf) - 1);
    strncpy (oneClickActPvBuf,oneClickActPvStr.getRaw (), sizeof (oneClickActPvBuf) - 1);
    ef.addTextField ("Data Height PV (ignored for fixed size)",
                     30, oneClickActPvBuf, sizeof (oneClickActPvBuf) - 1);

    ef.addOption ("Data Size Type", "Fixed|PV-based", &pvBasedDataSize);
    // ef.addToggle ("PV-based Width", &height);

    // Map dialog box form buttons to callbacks
    ef.finished ( editOK, editApply, create ? editCancelCreate : editCancel,
                  this );

    // Required by display engine
    actWin->currentEf = _ef;

    // popup the dialog box
    ef.popup ();

}

int TwoDProfileMonitor::edit ( void )
{

    editCommon ( actWin, &ef );

    return 1;
}

int TwoDProfileMonitor::createInteractive (activeWindowClass *actWin,
                                           int x,
                                           int y,
                                           int w,
                                           int h )
{
  
    this->actWin = actWin;
    this->x = x;
    this->y = y;
    this->w = w;
    this->h = h;

    draw ();
  
    editCommon ( actWin, NULL, ~0 );

    return 1;
}

int TwoDProfileMonitor::createFromFile (FILE *fptr,
                                        char *name,
                                        activeWindowClass *actWin )
{
  
    this->actWin = actWin;
  
    // use tag class and name to read from file
    TwoDProfileMonitorTags tag;
  
    if ( !(1 & tag.read ( this,
                          fptr, &x, &y, &w, &h, &dataPvStr,
                          &widthPvStr, &heightPvStr, &setCursorXPvStr, &setCursorYPvStr,
                          &oneClickActPvStr, &dataWidth, &pvBasedDataSize ) ) )
    {
        actWin->appCtx->postMessage ( tag.errMsg () );
    }
  
    updateDimensions ();
    initSelectBox ();
  
    return 1;
}

// What is an exchange file?
int TwoDProfileMonitor::importFromXchFile (FILE *fptr,
                                           char *name,
                                           activeWindowClass *actWin )
{

    cerr << "Import from eXchange file not supported" << endl;

    return 0;
}

int TwoDProfileMonitor::save ( FILE *fptr )
{
    // use tag class to serialize data
    TwoDProfileMonitorTags tag;
    return tag.write ( fptr, &x, &y, &w, &h, &dataPvStr,
                       &widthPvStr, &heightPvStr, &setCursorXPvStr, &setCursorYPvStr,
                       &oneClickActPvStr, &dataWidth, &pvBasedDataSize );
  
}

// called any time the widget needs to draw or re-draw itself
// in edit-mode 
int TwoDProfileMonitor::draw (void)
{ 

    // draw rectangle using X primitives
    XFillRectangle ( actWin->d, XtWindow (actWin->drawWidget),
                     actWin->drawGc.eraseGC (), x, y, w, h );
    XDrawRectangle ( actWin->d, XtWindow (actWin->drawWidget),
                     actWin->drawGc.normGC (), x, y, w, h );
    // Draw label text (crude because we can escape widget boundaries)
    XDrawImageString ( actWin->d, XtWindow (actWin->drawWidget),
                       actWin->drawGc.normGC (), x + 5, y + h / 2,
                       dataPvStr.getRaw (), strlen (dataPvStr.getRaw ()) );
#ifdef DEBUG  
    printf("draw\n");
#endif
    return activeGraphicClass::draw (); 
}

// erase widget in responce to "cut" command
// in edit-mode 
int TwoDProfileMonitor::erase (void)
{ 

    // draw rectangle using X primitives
    XDrawRectangle ( actWin->d, XtWindow (actWin->drawWidget),
                    actWin->drawGc.eraseGC (), x, y, w, h );

    return activeGraphicClass::erase (); 
}

// returning to edit mode, pass values are 1 and 2
int TwoDProfileMonitor::deactivate ( int pass )
{ 
    active = 0;
    activeMode = 0;

    if ( dataPv != NULL )
    {
        actWin->appCtx->proc->lock ();
        dataPv->remove_conn_state_callback ( monitorDataConnectState, this );
        dataPv->remove_value_callback ( dataUpdate, this );
        dataPv->release ();
        dataPv = NULL;
        actWin->appCtx->proc->unlock ();
    }

    if ( widthPv != NULL )
    {

        actWin->appCtx->proc->lock ();
        widthPv->remove_conn_state_callback ( monitorWidthConnectState, this );
        widthPv->remove_value_callback ( sizeUpdate, this );
        widthPv->release ();
        widthPv = NULL;
        actWin->appCtx->proc->unlock ();
    }

    if ( heightPv != NULL )
    {

        actWin->appCtx->proc->lock ();
        heightPv->remove_conn_state_callback ( monitorHeightConnectState, this );
        heightPv->remove_value_callback ( sizeUpdate, this );
        heightPv->release ();
        heightPv = NULL;
        actWin->appCtx->proc->unlock ();
    }

    // disconnect PV timeout on pass 1
    if ( pass == 1 )
    {
        // disable deferred processing before anything else
        actWin->appCtx->proc->lock ();
        actWin->remDefExeNode (aglPtr);
        actWin->appCtx->proc->unlock ();
    }

    // now turn off the Widget
    if ( pass == 2 )
    {

        XtUnmanageChild (twoDWidget);
        XtDestroyWidget (twoDWidget);
        widgetDestroyWidget (wd);

    }
  
    return activeGraphicClass::deactivate (pass); 
}


void TwoDProfileMonitor::monitorDataConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) DATA_CONNECT_STATE); 
#ifdef DEBUG
            printf ("TwoDProfMon::monDataConState - set pvNotConnMask to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= DATA_CONNECT_STATE;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}

void TwoDProfileMonitor::monitorWidthConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) WIDTH_CONNECT_STATE); 
#ifdef DEBUG
            printf ("TwoDProfMon::monWidthConState - set pvNotConMask to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= WIDTH_CONNECT_STATE;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}

void TwoDProfileMonitor::monitorHeightConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) HEIGHT_CONNECT_STATE); 
#ifdef DEBUG
            printf ("TwoDProfMon::monHeightConState - set pvNotConMsk to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= HEIGHT_CONNECT_STATE ;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}

void TwoDProfileMonitor::monitorCursorXConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) CURSORX_CONNECT_STATE ); 
#ifdef DEBUG
            printf ("TwoDProfMon::monHeightConState - set pvNotConMsk to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= CURSORX_CONNECT_STATE ;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}

void TwoDProfileMonitor::monitorCursorYConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) CURSORY_CONNECT_STATE ); 
#ifdef DEBUG
            printf ("TwoDProfMon::monHeightConState - set pvNotConMsk to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= CURSORY_CONNECT_STATE ;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}
void TwoDProfileMonitor::monitorOneClickActConnectState (ProcessVariable *pv,
                                                   void *userarg )
{

    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    if (me->activeMode)
    {
        if (pv->is_valid())
        {
            me->pvNotConnectedMask &= ~((unsigned char) ONECLICKACT_CONNECT_STATE ); 
#ifdef DEBUG
            printf ("TwoDProfMon::monOneClickActCConState - set pvNotConMsk to %d\n",
                    me->pvNotConnectedMask);
#endif
            if (!me->pvNotConnectedMask)
            {
                // All PVs connected
                me->needConnectInit = 1;
                me->actWin->addDefExeNode (me->aglPtr);
            }
        }
        else
        {
            me->pvNotConnectedMask |= ONECLICKACT_CONNECT_STATE ;
            me->active = 0;
            me->bufInvalidate();
            me->needDraw = 1;
            me->actWin->addDefExeNode (me->aglPtr);
        }
    }
    me->actWin->appCtx->proc->unlock ();
}

void TwoDProfileMonitor::dataUpdate (ProcessVariable *pv,
                                   void *userarg )
{
    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;

    me->actWin->appCtx->proc->lock ();
    me->actWin->addDefExeNode (me->aglPtr);
    me->actWin->appCtx->proc->unlock ();
}


void TwoDProfileMonitor::sizeUpdate (ProcessVariable *pv,
                                      void *userarg )
{
    TwoDProfileMonitor *me = ( TwoDProfileMonitor *) userarg;
    // Delete the data PV and recreate it.
    // Hopefully this will reinitialise the element count to match
    // the new size.
    me->actWin->appCtx->proc->lock ();
    me->dataPv->remove_value_callback ( dataUpdate, me );
    me->dataPv->remove_conn_state_callback ( monitorDataConnectState, me );
    me->dataPv->release ();
    me->dataPv = the_PV_Factory->create ( me->dataPvStr.getExpanded () );
    me->dataPv->add_conn_state_callback ( monitorDataConnectState, me );
    me->dataPv->add_value_callback ( dataUpdate, me );
    me->actWin->appCtx->proc->unlock ();
}
4 0 1
beginScreenProperties
major 4
minor 0
release 1
x 266
y 60
w 605
h 460
font "arial-medium-r-18.0"
ctlFont "arial-medium-r-18.0"
btnFont "arial-medium-r-18.0"
fgColor index 14
bgColor index 0
textColor index 14
ctlFgColor1 index 14
ctlFgColor2 index 0
ctlBgColor1 index 0
ctlBgColor2 index 14
topShadowColor index 0
botShadowColor index 14
endScreenProperties

# (New Monitor)
object TwoDProfileMonitorClass
beginObjectProperties
major 4
minor 0
release 0
x 15
y 15
w 576
h 432
dataPvStr "$(P)$(R)data"
widthPvStr "$(P)$(R)width"
heightPvStr "$(P)$(R)height"
setCursorXPvStr "$(P)$(R)setCursorX"
setCursorYPvStr "$(P)$(R)setCursorY"
oneClickActPvStr "$(P)$(R)oneClickAct"
dataWidth 1024
pvBasedDataSize 2
endObjectProperties

# (Static Text)
object activeXTextClass
beginObjectProperties
major 4
minor 1
release 0
x 1
y 1
w 23
h 12
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
value {
  "(0,0)"
}
autoSize
endObjectProperties

# (Static Text)
object activeXTextClass
beginObjectProperties
major 4
minor 1
release 0
x 250
y 448
w 29
h 12
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
value {
  "Cursor ("
}
autoSize
endObjectProperties

# (Static Text)
object activeXTextClass
beginObjectProperties
major 4
minor 1
release 0
x 316
y 448
w 3
h 12
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
value {
  ","
}
autoSize
endObjectProperties

# (Static Text)
object activeXTextClass
beginObjectProperties
major 4
minor 1
release 0
x 358
y 448
w 4
h 12
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
value {
  ")"
}
autoSize
endObjectProperties

# (Text Monitor)
object activeXTextDspClass:noedit
beginObjectProperties
major 4
minor 1
release 0
x 292
y 448
w 30
h 12
controlPv "$(P)$(R)setCursorX"
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
autoHeight
limitsFromDb
nullColor index 0
useHexPrefix
newPos
objType "monitors"
endObjectProperties

# (Text Monitor)
object activeXTextDspClass:noedit
beginObjectProperties
major 4
minor 1
release 0
x 330
y 448
w 30
h 12
controlPv "$(P)$(R)setCursorY"
font "arial-medium-r-10.0"
fgColor index 14
bgColor index 0
useDisplayBg
autoHeight
limitsFromDb
nullColor index 0
useHexPrefix
newPos
objType "monitors"
endObjectProperties


Replies:
A patch for libXpm.a (was Re: edm : TwoDProfileMonitorClass : cropping/resizing image) Kate Feng

Navigate by Date:
Prev: Re: ChannelArchiver on Solaris? Matthias Clausen
Next: Help Request: Setting up NIXI-1042/NI-MXI-4/DXP-XMAP with dxpStandalone_2-10 David Ehle
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: edm : TwoDProfileMonitorClass : cropping/resizing image Kate Feng
Next: Re: edm : TwoDProfileMonitorClass : cropping/resizing image Kate Feng
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Sep 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·