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
<2010>
2011
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
<2010>
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|