| Writing EDM Widgets (document under construction) | ||
|---|---|---|
| Prev | ||
We are now ready to examine the code of a working widget. First, member data and methods supporting edit mode behavior will be examined. Next we will look at widget activation and deactivation. After this, execute mode will be considered and finally the remaining auxillery data and methods will be discussed.
The example widget connects to one numeric process variable. The top portion of the rectangular region occupied by the widget displays the value of the pv as text. Below this, a box is displayed, the size of which corresponds to the value of the pv. The box area is a minimum when the pv's value is equal to the lower display limit and a maximum at the upper display limit. Below this box is a label specified by the user. The box line and fill colors may be specified and are sensitive to the pv's alarm state. The color of the text value and label is the same as the line color. A text font and a text alignment parameter my also be specified.
This file Contains all text used by the widget.
#ifndef __edmBoxComplete_str #define __edmBoxComplete_str 1 #define edmBoxComplete_str1 (char *) "Control PV" #define edmBoxComplete_str2 (char *) "Unknown object" #define edmBoxComplete_str3 (char *) " Properties" #define edmBoxComplete_str4 (char *) "X" #define edmBoxComplete_str5 (char *) "Y" #define edmBoxComplete_str6 (char *) "Width" #define edmBoxComplete_str7 (char *) "Height" #define edmBoxComplete_str8 (char *) "Line Thk" #define edmBoxComplete_str9 (char *) "Line Style" #define edmBoxComplete_str10 (char *) "Line Color" #define edmBoxComplete_str11 (char *) "Alarm Sensitive" #define edmBoxComplete_str12 (char *) "Fill" #define edmBoxComplete_str13 (char *) "Fill Color" #define edmBoxComplete_str14 (char *) "PV" #define edmBoxComplete_str15 (char *) "Min Value" #define edmBoxComplete_str16 (char *) "Max Value" #define edmBoxComplete_str17 (char *) "Font" #define edmBoxComplete_str18 (char *) "Label" #define edmBoxComplete_str19 (char *) "0|1|2|3|4|5|6|7|8|9|10" #define edmBoxComplete_str20 (char *) "Solid|Dash" #define edmBoxComplete_str21 (char *) "error creating pv\n" #define edmBoxComplete_str22 (char *) "edmBoxClass - Process variable must be numeric" #define edmBoxComplete_str23 (char *) "Precision" #endif
#ifndef __edmBoxComplete_h
#define __edmBoxComplete_h 1
#include "act_grf.h"
#include "app_pkg.h"
#include "act_win.h"
#include "pv_factory.h"
#ifdef __edmBoxComplete_cc
#include "edmBoxComplete.str"
static char *dragName[] = {
edmBoxComplete_str1
};
#endif
class edmBoxClass : public activeGraphicClass {
public:
// default constructor
edmBoxClass ( void );
// copy constructor
edmBoxClass (
const edmBoxClass *source );
// destructor
~edmBoxClass ( void );
// returns component name
char *objName ( void );
// Called when user creates object interactively
int createInteractive (
activeWindowClass *aw_obj,
int x,
int y,
int w,
int h );
int editCreate ( void );
int edit ( void );
// called by editCreate and edit
int genericEdit ( void );
// Called when file is opened
int createFromFile (
FILE *fptr,
char *name,
activeWindowClass *actWin );
int old_createFromFile (
FILE *fptr,
char *name,
activeWindowClass *actWin );
// Called when file is saved
int save (
FILE *f );
int old_save (
FILE *f );
// Called when widget is resized; also called by widget
// when size or font might have changed
void updateDimensions ( void );
// Called when edit mode image needs to be drawn
int draw ( void );
// Called when edit mode image needs to be erased
int erase ( void );
int checkResizeSelectBox (
int _x,
int _y,
int _w,
int _h );
int checkResizeSelectBoxAbs (
int _x,
int _y,
int _w,
int _h );
void changeDisplayParams (
unsigned int flag,
char *fontTag,
int alignment,
char *ctlFontTag,
int ctlAlignment,
char *btnFontTag,
int btnAlignment,
int textFgColor,
int fg1Color,
int fg2Color,
int offsetColor,
int bgColor,
int topShadowColor,
int botShadowColor );
void changePvNames (
int flag,
int numCtlPvs,
char *ctlPvs[],
int numReadbackPvs,
char *readbackPvs[],
int numNullPvs,
char *nullPvs[],
int numVisPvs,
char *visPvs[],
int numAlarmPvs,
char *alarmPvs[] );
// Called when execute mode image needs to be drawn
int drawActive ( void );
// Called when execute mode image needs to be erased
int eraseActive ( void );
// Called on expose event and called by widget code to indicate that
// the image buffer is invalid and that all detail should be redrawn
// at next "draw" command
void bufInvalidate ( void );
// Called before widget is activated; all expStringClass objects
// need to be processed
int expand1st (
int numMacros,
char *macros[],
char *expansions[] );
// Called when widget is activated and mux widget has changed a symbol; all
// expStringClass objects need to be processed
int expand2nd (
int numMacros,
char *macros[],
char *expansions[] );
// Called to discover if any expStringClass objects contain macro references
int containsMacros ( void );
// Called when widget is activated
int activate (
int pass,
void *ptr );
// Called when widget is deactivated
int deactivate ( int pass );
// Called periodically so widget may do X Windows I/O to update image
// (and perform other event related activities)
void executeDeferred ( void );
// Called on button-up action
void btnUp (
int x,
int y,
int buttonState,
int buttonNumber,
int *action );
// Called on button-down action
void btnDown (
int x,
int y,
int buttonState,
int buttonNumber,
int *action );
// Called on button-drag action
void btnDrag (
int x,
int y,
int buttonState,
int buttonNumber );
// Called to discover in what actions widget has interest
int getButtonActionRequest (
int *up,
int *down,
int *drag,
int *focus );
// Called to get name of first drag item (this widget has only one)
char *firstDragName ( void );
// Called to get name of next drag item (this widget has only one)
char *nextDragName ( void );
// Called to get value of ith drag item
char *dragValue (
int i );
private:
static const int COLORMODE_STATIC = 0; // color is not alarm sensitive
static const int COLORMODE_ALARM = 1; // color is alarm sensitive
static const int MAJOR_VERSION = 4; // Widget major version number
static const int MINOR_VERSION = 0; // Widget minor version number
static const int RELEASE = 0; // Widget release number
// Called by X when user presses OK button on property dialog form
static void editOk (
Widget w,
XtPointer client,
XtPointer call );
// Called by X when user presses Apply button on property dialog form
static void editApply (
Widget w,
XtPointer client,
XtPointer call );
// Called by editOk and editApply to copy edit buffer values into current
// property values
static void editUpdate (
Widget w,
XtPointer client,
XtPointer call );
// Called by X when user presses Cancel button on property dialog form
static void editCancel (
Widget w,
XtPointer client,
XtPointer call );
// Called by X when user presses Cancel button on property dialog form and
// widget is being created
static void editCancelDelete (
Widget w,
XtPointer client,
XtPointer call );
// X windows makes client code do blinking if color depth is
// anything other than 8 bits
static void doBlink (
void *ptr
);
// Called if widget does not connect within a given time interval
static void unconnectedTimeout (
XtPointer client,
XtIntervalId *id );
// Called when a process variable connects or disconnects
static void monitorPvConnectState (
ProcessVariable *pv,
void *userarg );
// Called when the value of a process variable changes
static void pvUpdate (
ProcessVariable *pv,
void *userarg );
// user selectable attributes
int lineStyle;
int lineWidth;
pvColorClass lineColor;
colorButtonClass lineCb;
int lineColorMode;
int fill;
pvColorClass fillColor;
colorButtonClass fillCb;
int fillColorMode;
fontMenuClass fm;
char fontTag[63+1];
char label[63+1];
expStringClass pvExpStr;
int alignment;
efDouble efReadMin, efReadMax;
double readMin, readMax;
efInt efPrecision;
int precision;
typedef struct editBufTag {
int bufX;
int bufY;
int bufW;
int bufH;
int bufLineWidth;
int bufLineStyle;
int bufLineColor;
int bufLineColorMode;
int bufFill;
int bufFillColor;
int bufFillColorMode;
char bufFontTag[63+1];
char bufLabel[63+1];
char bufPvName[activeGraphicClass::MAX_PV_NAME+1];
efDouble bufEfReadMin;
efDouble bufEfReadMax;
efInt bufEfPrecision;
} editBufType, *editBufPtr;
editBufPtr editBuf; // edit buffer for user selectable attributes
// Text related parameters
// Font metrics
int fontAscent;
int fontDescent;
int fontHeight;
int stringLength;
int stringWidth;
int labelX; // x location of label
int labelY; // y location of label
int textValueY; // x location of text value
int textValueX; // y location of text value
XFontStruct *fs; // X Windows font struct
char format[15+1]; // holds format used to display text value
// Misc
int centerX; // x cood of center of value box
int centerY; // y cood of center of value box
int boxY; // y cood of top-left of value box display area
int boxH; // height of value box display area
// execute mode variables
int init; // 1 if pv has connected at least once
// since activation
int active; // 1 if pv is currently connected
int activeMode; // 1 if widget is in execute mode
int opComplete; // used by activate method
int pvExists; // 1 if pv name is not blank
int pointerMotionDetected; // used by button processing methods
int bufferInvalid; // 1 means that all details need to be drawn/erased
// at next opportunity
// Process variable related information
ProcessVariable *pvId;
int fieldType; // ProcessVariable::Type::real
// ProcessVariable::Type::integer
// ProcessVariable::Type::enumerated
// ProcessVariable::Type::text
int oldStat; // previous alarm status value
int oldSev; // previous alarm severity value
// Misc
double value; // current pv value
double curValue; // copy of current pv value
double prevValue; // previous pv value
double factorW; // for scaling
double factorH; // for scaling
int valueBoxW; // current value box width
int valueBoxH; // current value box height
int valueBoxX; // current value box x coord
int valueBoxY; // current value box y coord
// Flags set in event functions to request deferred processing
int needConnectInit;
int needUpdate;
int needDraw;
int needErase;
int needToDrawUnconnected;
int needToEraseUnconnected;
// X Windows timer used to sense that pv has not connected in timely manner
int unconnectedTimer;
};
// Class factory functions
extern "C" {
void *create_2ed7d2e8_f439_11d2_8fed_00104b8742dfPtr ( void );
void *clone_2ed7d2e8_f439_11d2_8fed_00104b8742dfPtr ( void * );
}
#endif// object: 2ed7d2e8-f439-11d2-8fed-00104b8742df
// lib: 3014b6ee-f439-11d2-ad99-00104b8742df
// define SMARTDRAW if the widget may be part of an overlapping
// stack of widgets
//#define SMARTDRAW 1
#define __edmBoxComplete_cc 1
#include "edmBoxComplete.h"
//---------------------------------------------------------------------------
// default constructor
edmBoxClass::edmBoxClass ( void ) {
// Allocate space for the component name and init
name = new char[strlen("2ed7d2e8_f439_11d2_8fed_00104b8742df")+1];
strcpy( name, "2ed7d2e8_f439_11d2_8fed_00104b8742df" );
// Init class member data
editBuf = NULL;
pvExists = 0;
active = 0;
activeMode = 0;
fill = 0;
lineColorMode = COLORMODE_STATIC;
fillColorMode = COLORMODE_STATIC;
lineWidth = 1;
lineStyle = LineSolid;
readMin = 0;
readMax = 10;
precision = 1;
efReadMin.setNull(1);
efReadMax.setNull(1);
strcpy( fontTag, "" );
strcpy( label, "" );
fs = NULL;
labelX = 0;
labelY = 0;
alignment = XmALIGNMENT_BEGINNING;
unconnectedTimer = 0;
// This makes the blinking color magic work
setBlinkFunction( (void *) doBlink );
}
//---------------------------------------------------------------------------
// copy constructor
edmBoxClass::edmBoxClass
( const edmBoxClass *source ) {
activeGraphicClass *ago = (activeGraphicClass *) this;
// clone base class data
ago->clone( (activeGraphicClass *) source );
// Allocate space for the component name and init
name = new char[strlen("2ed7d2e8_f439_11d2_8fed_00104b8742df")+1];
strcpy( name, "2ed7d2e8_f439_11d2_8fed_00104b8742df" );
editBuf = NULL;
// copy edit mode data and initialize execute mode data
lineColor.copy(source->lineColor);
fillColor.copy(source->fillColor);
lineCb = source->lineCb;
fillCb = source->fillCb;
fill = source->fill;
lineColorMode = source->lineColorMode;
fillColorMode = source->fillColorMode;
strncpy( fontTag, source->fontTag, 63 );
fontTag[63] = 0;
strncpy( label, source->label, 63 );
label[63] = 0;
fs = actWin->fi->getXFontStruct( fontTag );
stringLength = source->stringLength;
fontAscent = source->fontAscent;
fontDescent = source->fontDescent;
fontHeight = source->fontHeight;
stringWidth = source->stringWidth;
labelX = source->labelX;
labelY = source->labelY;
alignment = source->alignment;
lineWidth = source->lineWidth;
lineStyle = source->lineStyle;
pvExpStr.setRaw( source->pvExpStr.rawString );
pvExists = 0;
active = 0;
activeMode = 0;
readMin = source->readMin;
readMax = source->readMax;
precision = source->precision;
efReadMin = source->efReadMin;
efReadMax = source->efReadMax;
efPrecision = source->efPrecision;
unconnectedTimer = 0;
// This makes the blinking color magic work
setBlinkFunction( (void *) doBlink );
}
//---------------------------------------------------------------------------
// Destructor
edmBoxClass::~edmBoxClass ( void ) {
// deallocate dynamic memory
if ( name ) delete name;
if ( unconnectedTimer ) {
XtRemoveTimeOut( unconnectedTimer );
unconnectedTimer = 0;
}
if ( editBuf ) delete editBuf;
// disable blink function
updateBlink( 0 );
}
//---------------------------------------------------------------------------
char *edmBoxClass::objName ( void ) {
// Return component name
return name;
}
//---------------------------------------------------------------------------
int edmBoxClass::createInteractive (
activeWindowClass *aw_obj,
int _x,
int _y,
int _w,
int _h ) {
// All widgets must copy active window object
actWin = (activeWindowClass *) aw_obj;
// Initialize edit mode data so an initial edit mode image
// may be drawn
x = _x;
y = _y;
w = _w;
h = _h;
lineColor.setColorIndex( actWin->defaultFg1Color, actWin->ci );
fillColor.setColorIndex( actWin->defaultBgColor, actWin->ci );
strcpy( fontTag, actWin->defaultCtlFontTag );
alignment = actWin->defaultCtlAlignment;
fs = actWin->fi->getXFontStruct( fontTag );
updateFont( " ", fontTag, &fs,
&fontAscent, &fontDescent, &fontHeight,
&stringWidth );
boxH = h - fontHeight - fontHeight;
if ( boxH < 5 ) {
boxH = 5;
h = boxH + fontHeight + fontHeight;
sboxH = h;
}
boxY = y + fontHeight;
if ( w < 5 ) {
w = 5;
sboxW = 5;
}
// Draw initial edit mode image
this->draw();
// create and popup the property dialog for a newly created object
this->editCreate();
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::editCreate ( void ) {
this->genericEdit();
// Map dialog box form buttons to callbacks
ef.finished( editOk, editApply, editCancelDelete, this );
// Required by display engine
actWin->currentEf = NULL;
// Pop-up the dialog box
ef.popup();
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::edit ( void ) {
this->genericEdit();
// Map dialog box form buttons to callbacks
ef.finished( editOk, editApply, editCancel, this );
// Required by display engine
actWin->currentEf = &ef;
// Pop-up the dialog box
ef.popup();
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::genericEdit ( void ) {
// Create the property dialog box so that user may edit widget attributes
char title[32], *ptr;
// Allocate the edit buffer, this holds values until the OK or Cancel button
// is pressed
if ( !editBuf ) {
editBuf = new editBufType;
}
// Build property dialog title - this will become "Box Properties"
// Get the widget nickname from the component name
ptr = actWin->obj.getNameFromClass( "2ed7d2e8_f439_11d2_8fed_00104b8742df" );
if ( ptr )
strncpy( title, ptr, 31 );
else
strncpy( title, edmBoxComplete_str2, 31 );
Strncat( title, edmBoxComplete_str3, 31 );
// Copy current property values into edit buffer; on OK or Apply
// edit buffer values will be copied back into current property values
editBuf->bufX = x;
editBuf->bufY = y;
editBuf->bufW = w;
editBuf->bufH = h;
editBuf->bufLineColor = lineColor.pixelIndex();
editBuf->bufLineColorMode = lineColorMode;
editBuf->bufFillColor = fillColor.pixelIndex();
editBuf->bufFillColorMode = fillColorMode;
editBuf->bufFill = fill;
editBuf->bufLineWidth = lineWidth;
editBuf->bufLineStyle = lineStyle;
if ( pvExpStr.getRaw() )
strncpy( editBuf->bufPvName, pvExpStr.getRaw(), activeGraphicClass::MAX_PV_NAME );
else
strcpy( editBuf->bufPvName, "" );
editBuf->bufEfReadMin = efReadMin;
editBuf->bufEfReadMax = efReadMax;
editBuf->bufEfPrecision = efPrecision;
strncpy( editBuf->bufLabel, label, 63 );
editBuf->bufLabel[63] = 0;
// Create the property dialog data entry form
ef.create( actWin->top, actWin->appCtx->ci.getColorMap(),
&actWin->appCtx->entryFormX,
&actWin->appCtx->entryFormY, &actWin->appCtx->entryFormW,
&actWin->appCtx->entryFormH, &actWin->appCtx->largestH,
title, NULL, NULL, NULL );
// Add fields to the form
ef.addTextField( edmBoxComplete_str4, 30, &editBuf->bufX );
ef.addTextField( edmBoxComplete_str5, 30, &editBuf->bufY );
ef.addTextField( edmBoxComplete_str6, 30, &editBuf->bufW );
ef.addTextField( edmBoxComplete_str7, 30, &editBuf->bufH );
ef.addOption( edmBoxComplete_str8, edmBoxComplete_str19,
&editBuf->bufLineWidth );
ef.addOption( edmBoxComplete_str9, edmBoxComplete_str20,
&editBuf->bufLineStyle );
ef.addColorButton( edmBoxComplete_str10, actWin->ci, &lineCb,
&editBuf->bufLineColor );
ef.addToggle( edmBoxComplete_str11, &editBuf->bufLineColorMode );
ef.addToggle( edmBoxComplete_str12, &editBuf->bufFill );
ef.addColorButton( edmBoxComplete_str13, actWin->ci, &fillCb,
&editBuf->bufFillColor );
ef.addToggle( edmBoxComplete_str11, &editBuf->bufFillColorMode );
ef.addTextField( edmBoxComplete_str14, 30, editBuf->bufPvName,
activeGraphicClass::MAX_PV_NAME );
ef.addTextField( edmBoxComplete_str15, 30, &editBuf->bufEfReadMin );
ef.addTextField( edmBoxComplete_str16, 30, &editBuf->bufEfReadMax );
ef.addTextField( edmBoxComplete_str23, 30, &editBuf->bufEfPrecision );
ef.addFontMenu( edmBoxComplete_str17, actWin->fi, &fm, fontTag );
fm.setFontAlignment( alignment );
ef.addTextField( edmBoxComplete_str18, 30, editBuf->bufLabel, 63 );
return 1;
}
//---------------------------------------------------------------------------
// called by editApply and editOK
void edmBoxClass::editUpdate (
Widget w,
XtPointer client,
XtPointer call )
{
edmBoxClass *ebo = (edmBoxClass *) client;
// Widget data has changed
ebo->actWin->setChanged();
// All widgets must include next two lines
ebo->eraseSelectBoxCorners();
ebo->erase();
// Copy edit buffer into current property values
ebo->lineColorMode = ebo->editBuf->bufLineColorMode;
if ( ebo->lineColorMode == COLORMODE_ALARM )
ebo->lineColor.setAlarmSensitive();
else
ebo->lineColor.setAlarmInsensitive();
ebo->lineColor.setColorIndex( ebo->editBuf->bufLineColor, ebo->actWin->ci );
ebo->fill = ebo->editBuf->bufFill;
ebo->fillColorMode = ebo->editBuf->bufFillColorMode;
if ( ebo->fillColorMode == COLORMODE_ALARM )
ebo->fillColor.setAlarmSensitive();
else
ebo->fillColor.setAlarmInsensitive();
ebo->fillColor.setColorIndex( ebo->editBuf->bufFillColor, ebo->actWin->ci );
ebo->lineWidth = ebo->editBuf->bufLineWidth;
if ( ebo->editBuf->bufLineStyle == 0 )
ebo->lineStyle = LineSolid;
else if ( ebo->editBuf->bufLineStyle == 1 )
ebo->lineStyle = LineOnOffDash;
ebo->pvExpStr.setRaw( ebo->editBuf->bufPvName );
ebo->efReadMin = ebo->editBuf->bufEfReadMin;
ebo->efReadMax = ebo->editBuf->bufEfReadMax;
ebo->efPrecision = ebo->editBuf->bufEfPrecision;
if ( ebo->efReadMin.isNull() ) {
ebo->readMin = 0;
}
else{
ebo->readMin = ebo->efReadMin.value();
}
if ( ebo->efReadMax.isNull() ) {
ebo->readMax = 10;
}
else{
ebo->readMax = ebo->efReadMax.value();
}
if ( ( ebo->efPrecision.isNull() ) ) {
ebo->precision = 1;
}
else{
ebo->precision = ebo->efPrecision.value();
}
strncpy( ebo->fontTag, ebo->fm.currentFontTag(), 63 );
ebo->fontTag[63] = 0;
ebo->actWin->fi->loadFontTag( ebo->fontTag );
ebo->alignment = ebo->fm.currentFontAlignment();
ebo->fs = ebo->actWin->fi->getXFontStruct( ebo->fontTag );
strncpy( ebo->label, ebo->editBuf->bufLabel, 63 );
ebo->label[63] = 0;
ebo->stringLength = strlen( ebo->label );
ebo->updateFont( ebo->label, ebo->fontTag, &ebo->fs,
&ebo->fontAscent, &ebo->fontDescent, &ebo->fontHeight,
&ebo->stringWidth );
// copy into object dimensions and select box dimensions
ebo->x = ebo->editBuf->bufX;
ebo->sboxX = ebo->editBuf->bufX;
ebo->y = ebo->editBuf->bufY;
ebo->sboxY = ebo->editBuf->bufY;
ebo->w = ebo->editBuf->bufW;
ebo->sboxW = ebo->editBuf->bufW;
ebo->h = ebo->editBuf->bufH;
ebo->sboxH = ebo->editBuf->bufH;
// Check values and do a few calculations
if ( ebo->w < 5 ) {
ebo->w = 5;
ebo->sboxW = ebo->w;
}
ebo->boxH = ebo->h - ebo->fontHeight - ebo->fontHeight;
if ( ebo->boxH < 5 ) {
ebo->boxH = 5;
ebo->h = ebo->boxH + ebo->fontHeight + ebo->fontHeight;
ebo->sboxH = ebo->h;
}
ebo->boxY = ebo->y + ebo->fontHeight;
if ( ebo->readMax > ebo->readMin ) {
ebo->factorW = (double) ( ebo->w - 2 ) / ( ebo->readMax - ebo->readMin );
ebo->factorH = (double) ebo->boxH / ( ebo->readMax - ebo->readMin );
}
else {
ebo->factorW = 1;
ebo->factorH = 1;
}
ebo->centerX = ebo->x + (int) ( ebo->w * 0.5 + 0.5 );
ebo->centerY = ebo->boxY + (int) ( ebo->boxH * 0.5 + 0.5 );
// updateDimensions should be called whenever the widget size
// or text fonts might have changed
ebo->updateDimensions();
}
//---------------------------------------------------------------------------
// X Windows callback function for the apply button on the property dialog
void edmBoxClass::editApply (
Widget w,
XtPointer client,
XtPointer call )
{
edmBoxClass *ebo = (edmBoxClass *) client;
edmBoxClass::editUpdate( w, client, call );
ebo->refresh( ebo );
}
//---------------------------------------------------------------------------
// X Windows callback function for the OK button on the property dialog
void edmBoxClass::editOk (
Widget w,
XtPointer client,
XtPointer call )
{
edmBoxClass *ebo = (edmBoxClass *) client;
edmBoxClass::editUpdate( w, client, call );
delete ebo->editBuf;
ebo->editBuf = NULL;
ebo->ef.popdown();
ebo->operationComplete();
}
//---------------------------------------------------------------------------
// X Windows callback function for the cancel button on the property dialog
void edmBoxClass::editCancel (
Widget w,
XtPointer client,
XtPointer call )
{
edmBoxClass *ebo = (edmBoxClass *) client;
delete ebo->editBuf;
ebo->editBuf = NULL;
ebo->ef.popdown();
ebo->operationCancel();
}
//---------------------------------------------------------------------------
// X Windows callback function for the cancel button on the property dialog
// when the object is being created. If user cancels edit, object creation
// is being canceled thus deleteRequest must be set.
void edmBoxClass::editCancelDelete (
Widget w,
XtPointer client,
XtPointer call )
{
edmBoxClass *ebo = (edmBoxClass *) client;
delete ebo->editBuf;
ebo->editBuf = NULL;
ebo->erase();
ebo->deleteRequest = 1;
ebo->ef.popdown();
ebo->operationCancel();
ebo->drawAll();
}
//---------------------------------------------------------------------------
int edmBoxClass::createFromFile (
FILE *f,
char *name,
activeWindowClass *_actWin )
{
// Read widget properties from file
int major, minor, release, stat;
tagClass tag;
int zero = 0;
int one = 1;
static char *emptyStr = "";
int solid = LineSolid;
static char *styleEnumStr[2] = {
"solid",
"dash"
};
static int styleEnum[2] = {
LineSolid,
LineOnOffDash
};
static int left = XmALIGNMENT_BEGINNING;
static char *alignEnumStr[3] = {
"left",
"center",
"right"
};
static int alignEnum[3] = {
XmALIGNMENT_BEGINNING,
XmALIGNMENT_CENTER,
XmALIGNMENT_END
};
this->actWin = _actWin;
tag.init();
tag.loadR( "beginObjectProperties" );
tag.loadR( "major", &major );
tag.loadR( "minor", &minor );
tag.loadR( "release", &release );
tag.loadR( "x", &x );
tag.loadR( "y", &y );
tag.loadR( "w", &w );
tag.loadR( "h", &h );
tag.loadR( "controlPv", &pvExpStr, emptyStr );
tag.loadR( "lineColor", actWin->ci, &lineColor );
tag.loadR( "lineAlarm", &lineColorMode, &zero );
tag.loadR( "fill", &fill, &zero );
tag.loadR( "fillColor", actWin->ci, &fillColor );
tag.loadR( "fillAlarm", &fillColorMode, &zero );
tag.loadR( "lineWidth", &lineWidth, &one );
tag.loadR( "lineStyle", 2, styleEnumStr, styleEnum, &lineStyle, &solid );
tag.loadR( "min", &efReadMin );
tag.loadR( "max", &efReadMax );
tag.loadR( "precision", &efPrecision );
tag.loadR( "font", 63, fontTag );
tag.loadR( "fontAlign", 3, alignEnumStr, alignEnum, &alignment, &left );
tag.loadR( "label", 63, label, emptyStr );
tag.loadR( "endObjectProperties" );
stat = tag.readTags( f, "endObjectProperties" );
if ( !( stat & 1 ) ) {
actWin->appCtx->postMessage( tag.errMsg() );
}
// If new object version is greater than current version then abort
if ( major > MAJOR_VERSION ) {
postIncompatable();
return 0;
}
// If new object version is "old file format" then abort
if ( major < 4 ) {
postIncompatable();
return 0;
}
// initSelectBox must always be call after getting x,y,w,h
this->initSelectBox(); // call after getting x,y,w,h
// Process pv alarm information
if ( lineColorMode == COLORMODE_ALARM )
lineColor.setAlarmSensitive();
else
lineColor.setAlarmInsensitive();
if ( fillColorMode == COLORMODE_ALARM )
fillColor.setAlarmSensitive();
else
fillColor.setAlarmInsensitive();
// Process min, max, precision
if ( efReadMin.isNull() ) {
readMin = 0;
}
else{
readMin = efReadMin.value();
}
if ( efReadMax.isNull() ) {
readMax = 10;
}
else{
readMax = efReadMax.value();
}
if ( ( efPrecision.isNull() ) ) {
precision = 1;
}
else{
precision = efPrecision.value();
}
// Make fonts available to X Server, get font struct and font metrics
actWin->fi->loadFontTag( fontTag );
fs = actWin->fi->getXFontStruct( fontTag );
stringLength = strlen( label );
updateFont( label, fontTag, &fs,
&fontAscent, &fontDescent, &fontHeight,
&stringWidth );
// updateDimensions should be called whenever the widget size
// or text fonts might have changed
updateDimensions();
// Do various calculations
if ( readMax > readMin ) {
factorW = (double) ( w - 2 ) / ( readMax - readMin );
factorH = (double) boxH / ( readMax - readMin );
}
else {
factorW = 1;
factorH = 1;
}
centerX = x + (int) ( w * 0.5 + 0.5 );
centerY = boxY + (int) ( boxH * 0.5 + 0.5 );
curValue = 0;
return stat;
}
//---------------------------------------------------------------------------
int edmBoxClass::old_createFromFile (
FILE *f,
char *name,
activeWindowClass *_actWin )
{
int r, g, b, index;
int major, minor, release;
unsigned int pixel;
char oneName[activeGraphicClass::MAX_PV_NAME+1];
this->actWin = _actWin;
fscanf( f, "%d %d %d\n", &major, &minor, &release ); actWin->incLine();
if ( major > MAJOR_VERSION ) {
postIncompatable();
return 0;
}
fscanf( f, "%d\n", &x ); actWin->incLine();
fscanf( f, "%d\n", &y ); actWin->incLine();
fscanf( f, "%d\n", &w ); actWin->incLine();
fscanf( f, "%d\n", &h ); actWin->incLine();
this->initSelectBox(); // call after getting x,y,w,h
if ( ( major > 2 ) || ( ( major == 2 ) && ( minor > 0 ) ) ) {
actWin->ci->readColorIndex( f, &index );
actWin->incLine(); actWin->incLine();
lineColor.setColorIndex( index, actWin->ci );
fscanf( f, "%d\n", &lineColorMode ); actWin->incLine();
if ( lineColorMode == COLORMODE_ALARM )
lineColor.setAlarmSensitive();
else
lineColor.setAlarmInsensitive();
fscanf( f, "%d\n", &fill ); actWin->incLine();
actWin->ci->readColorIndex( f, &index );
actWin->incLine(); actWin->incLine();
fillColor.setColorIndex( index, actWin->ci );
}
else if ( major > 1 ) {
fscanf( f, "%d\n", &index ); actWin->incLine();
lineColor.setColorIndex( index, actWin->ci );
fscanf( f, "%d\n", &lineColorMode ); actWin->incLine();
if ( lineColorMode == COLORMODE_ALARM )
lineColor.setAlarmSensitive();
else
lineColor.setAlarmInsensitive();
fscanf( f, "%d\n", &fill ); actWin->incLine();
fscanf( f, "%d\n", &index ); actWin->incLine();
fillColor.setColorIndex( index, actWin->ci );
}
else {
fscanf( f, "%d %d %d\n", &r, &g, &b ); actWin->incLine();
actWin->ci->setRGB( r, g, b, &pixel );
index = actWin->ci->pixIndex( pixel );
lineColor.setColorIndex( index, actWin->ci );
fscanf( f, "%d\n", &lineColorMode ); actWin->incLine();
if ( lineColorMode == COLORMODE_ALARM )
lineColor.setAlarmSensitive();
else
lineColor.setAlarmInsensitive();
fscanf( f, "%d\n", &fill ); actWin->incLine();
fscanf( f, "%d %d %d\n", &r, &g, &b ); actWin->incLine();
actWin->ci->setRGB( r, g, b, &pixel );
index = actWin->ci->pixIndex( pixel );
fillColor.setColorIndex( index, actWin->ci );
}
fscanf( f, "%d\n", &fillColorMode ); actWin->incLine();
if ( fillColorMode == COLORMODE_ALARM )
fillColor.setAlarmSensitive();
else
fillColor.setAlarmInsensitive();
readStringFromFile( oneName, activeGraphicClass::MAX_PV_NAME+1, f );
actWin->incLine();
pvExpStr.setRaw( oneName );
fscanf( f, "%d\n", &lineWidth ); actWin->incLine();
fscanf( f, "%d\n", &lineStyle ); actWin->incLine();
efReadMin.read( f ); actWin->incLine();
efReadMax.read( f ); actWin->incLine();
if ( ( efReadMin.isNull() ) && ( efReadMax.isNull() ) ) {
readMin = 0;
readMax = 10;
}
else{
readMin = efReadMin.value();
readMax = efReadMax.value();
}
if ( ( major > 1 ) || ( minor > 3 ) ) {
readStringFromFile( fontTag, 63+1, f ); actWin->incLine();
readStringFromFile( label, 63+1, f ); actWin->incLine();
actWin->fi->loadFontTag( fontTag );
fs = actWin->fi->getXFontStruct( fontTag );
stringLength = strlen( label );
updateFont( label, fontTag, &fs,
&fontAscent, &fontDescent, &fontHeight,
&stringWidth );
}
else {
strcpy( label, "" );
stringLength = 0;
strcpy( fontTag, actWin->defaultFontTag );
fs = actWin->fi->getXFontStruct( fontTag );
updateFont( label, fontTag, &fs,
&fontAscent, &fontDescent, &fontHeight,
&stringWidth );
}
if ( ( major > 1 ) || ( minor > 4 ) ) {
fscanf( f, "%d\n", &alignment ); actWin->incLine();
}
else {
alignment = XmALIGNMENT_BEGINNING;
}
if ( alignment == XmALIGNMENT_BEGINNING )
labelX = x;
else if ( alignment == XmALIGNMENT_CENTER )
labelX = x + w/2 - stringWidth/2;
else if ( alignment == XmALIGNMENT_END )
labelX = x + w - stringWidth;
labelY = y + h;
boxH = h - fontHeight - fontHeight;
if ( boxH < 5 ) {
boxH = 5;
h = boxH + fontHeight + fontHeight;
}
boxY = y + fontHeight;
if ( readMax > readMin ) {
factorW = (double) ( w - 2 ) / ( readMax - readMin );
factorH = (double) boxH / ( readMax - readMin );
}
else {
factorW = 1;
factorH = 1;
}
centerX = x + (int) ( w * 0.5 + 0.5 );
centerY = boxY + (int) ( boxH * 0.5 + 0.5 );
curValue = 0;
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::save (
FILE *f )
{
// Save widget properties to file
int major, minor, release, stat;
tagClass tag;
int zero = 0;
int one = 1;
static char *emptyStr = "";
int solid = LineSolid;
static char *styleEnumStr[2] = {
"solid",
"dash"
};
static int styleEnum[2] = {
LineSolid,
LineOnOffDash
};
static int left = XmALIGNMENT_BEGINNING;
static char *alignEnumStr[3] = {
"left",
"center",
"right"
};
static int alignEnum[3] = {
XmALIGNMENT_BEGINNING,
XmALIGNMENT_CENTER,
XmALIGNMENT_END
};
major = MAJOR_VERSION;
minor = MINOR_VERSION;
release = RELEASE;
tag.init();
tag.loadW( "beginObjectProperties" );
tag.loadW( "major", &major );
tag.loadW( "minor", &minor );
tag.loadW( "release", &release );
tag.loadW( "x", &x );
tag.loadW( "y", &y );
tag.loadW( "w", &w );
tag.loadW( "h", &h );
tag.loadW( "controlPv", &pvExpStr, emptyStr );
tag.loadW( "lineColor", actWin->ci, &lineColor );
tag.loadBoolW( "lineAlarm", &lineColorMode, &zero );
tag.loadBoolW( "fill", &fill, &zero );
tag.loadW( "fillColor", actWin->ci, &fillColor );
tag.loadBoolW( "fillAlarm", &fillColorMode, &zero );
tag.loadW( "lineWidth", &lineWidth, &one );
tag.loadW( "lineStyle", 2, styleEnumStr, styleEnum, &lineStyle, &solid );
tag.loadW( "min", &efReadMin );
tag.loadW( "max", &efReadMax );
tag.loadW( "precision", &efPrecision );
tag.loadW( "font", fontTag );
tag.loadW( "fontAlign", 3, alignEnumStr, alignEnum, &alignment, &left );
tag.loadW( "label", label, emptyStr );
tag.loadW( "endObjectProperties" );
tag.loadW( "" );
stat = tag.writeTags( f );
return stat;
}
//---------------------------------------------------------------------------
int edmBoxClass::old_save (
FILE *f )
{
int index, stat;
fprintf( f, "%-d %-d %-d\n", MAJOR_VERSION, MINOR_VERSION, RELEASE );
fprintf( f, "%-d\n", x );
fprintf( f, "%-d\n", y );
fprintf( f, "%-d\n", w );
fprintf( f, "%-d\n", h );
index = lineColor.pixelIndex();
actWin->ci->writeColorIndex( f, index );
//fprintf( f, "%-d\n", index );
fprintf( f, "%-d\n", lineColorMode );
fprintf( f, "%-d\n", fill );
index = fillColor.pixelIndex();
actWin->ci->writeColorIndex( f, index );
//fprintf( f, "%-d\n", index );
fprintf( f, "%-d\n", fillColorMode );
if ( pvExpStr.getRaw() )
writeStringToFile( f, pvExpStr.getRaw() );
else
writeStringToFile( f, "" );
fprintf( f, "%-d\n", lineWidth );
fprintf( f, "%-d\n", lineStyle );
stat = efReadMin.write( f );
stat = efReadMax.write( f );
writeStringToFile( f, fontTag );
writeStringToFile( f, label );
fprintf( f, "%-d\n", alignment );
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::draw ( void ) {
// Draw edit mode image
XRectangle xR = { x, y, w, h };
int clipStat;
int blink = 0;
// if widget is being activated or has been deleted, return
if ( activeMode || deleteRequest ) return 1;
// Save foreground color
actWin->drawGc.saveFg();
// Set clipping region
clipStat = actWin->drawGc.addNormXClipRectangle( xR );
// If filled, fill in rectangle with specified color
if ( fill ) {
actWin->drawGc.setFG( fillColor.pixelIndex(), &blink );
XFillRectangle( actWin->d, XtWindow(actWin->drawWidget),
actWin->drawGc.normGC(), x+1, boxY, w-2, boxH );
}
// Set line color, style, and width to specified values
actWin->drawGc.setFG( lineColor.pixelIndex(), &blink );
actWin->drawGc.setLineWidth( lineWidth );
actWin->drawGc.setLineStyle( lineStyle );
// Draw rectangle outline
XDrawRectangle( actWin->d, XtWindow(actWin->drawWidget),
actWin->drawGc.normGC(), x+1, boxY, w-2, boxH );
// Set graphic context font
if ( strcmp( fontTag, "" ) != 0 ) {
actWin->drawGc.setFontTag( fontTag, actWin->fi );
}
// Draw label text
xDrawText( actWin->d, XtWindow(actWin->drawWidget),
&actWin->drawGc, fs, labelX, labelY, alignment,
label );
// Remove clippling region
if ( clipStat & 1 ) actWin->drawGc.removeNormXClipRectangle();
// restore graphic context values
actWin->drawGc.setLineWidth( 1 );
actWin->drawGc.setLineStyle( LineSolid );
actWin->drawGc.restoreFg();
// This makes the blink magic work
updateBlink( blink );
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::erase ( void ) {
// Draw edit mode image
// Colors are not set because the eraseGC is used; the eraseGC contains
// the color of the display background
XRectangle xR = { x, y, w, h };
int clipStat;
// if widget is being activated or has been deleted, return
if ( activeMode || deleteRequest ) return 1;
// Set clipping region
clipStat = actWin->drawGc.addEraseXClipRectangle( xR );
// If filled, erase fill
if ( fill ) {
XFillRectangle( actWin->d, XtWindow(actWin->drawWidget),
actWin->drawGc.eraseGC(), x+1, boxY, w-2, boxH );
}
// Set line style and width to specified values
actWin->drawGc.setLineWidth( lineWidth );
actWin->drawGc.setLineStyle( lineStyle );
// Erase rectangle outline
XDrawRectangle( actWin->d, XtWindow(actWin->drawWidget),
actWin->drawGc.eraseGC(), x+1, boxY, w-2, boxH );
// Set graphic context font
if ( strcmp( fontTag, "" ) != 0 ) {
actWin->drawGc.setFontTag( fontTag, actWin->fi );
}
// Erase label text
xEraseText( actWin->d, XtWindow(actWin->drawWidget),
&actWin->drawGc, fs, labelX, labelY, alignment,
label );
// Remove clippling region
if ( clipStat & 1 ) actWin->drawGc.removeEraseXClipRectangle();
// restore graphic context values
actWin->drawGc.setLineWidth( 1 );
actWin->drawGc.setLineStyle( LineSolid );
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::checkResizeSelectBox (
int _x,
int _y,
int _w,
int _h ) {
// Constrain minimum widget area size, input parameters are
// delta values
int tmpw, tmph, tmpBoxH, ret_stat;
ret_stat = 1;
tmpw = sboxW;
tmph = sboxH;
tmpw += _w;
tmph += _h;
tmpBoxH = tmph - fontHeight - fontHeight;
if ( tmpBoxH < 5 ) ret_stat = 0;
if ( tmpw < 5 ) ret_stat = 0;
return ret_stat;
}
//---------------------------------------------------------------------------
int edmBoxClass::checkResizeSelectBoxAbs (
int _x,
int _y,
int _w,
int _h ) {
// Constrain minimum widget area size, input parameters are
// absolute values
int tmpw, tmph, tmpBoxH, ret_stat;
ret_stat = 1;
tmpw = _w;
tmph = _h;
if ( tmph != -1 ) {
tmpBoxH = tmph - fontHeight - fontHeight;
if ( tmpBoxH < 5 ) ret_stat = 0;
}
if ( tmpw != -1 ) {
if ( tmpw < 5 ) ret_stat = 0;
}
return ret_stat;
}
//---------------------------------------------------------------------------
void edmBoxClass::updateDimensions ( void ) {
// Update values of position and size of widget internal details
boxY = y + fontHeight;
labelY = y + h - fontHeight;
textValueY = y;
if ( alignment == XmALIGNMENT_BEGINNING )
textValueX = x;
else if ( alignment == XmALIGNMENT_CENTER )
textValueX = x + w/2;
else if ( alignment == XmALIGNMENT_END )
textValueX = x + w;
if ( alignment == XmALIGNMENT_BEGINNING )
labelX = x;
else if ( alignment == XmALIGNMENT_CENTER )
labelX = x + w/2;
else if ( alignment == XmALIGNMENT_END )
labelX = x + w;
boxH = h - fontHeight - fontHeight;
if ( boxH < 5 ) {
boxH = 5;
h = boxH + fontHeight + fontHeight;
sboxH = h;
}
if ( w < 5 ) {
w = 5;
sboxW = 5;
}
}
//---------------------------------------------------------------------------
void edmBoxClass::changeDisplayParams (
unsigned int _flag,
char *_fontTag,
int _alignment,
char *_ctlFontTag,
int _ctlAlignment,
char *_btnFontTag,
int _btnAlignment,
int _textFgColor,
int _fg1Color,
int _fg2Color,
int _offsetColor,
int _bgColor,
int _topShadowColor,
int _botShadowColor )
{
// Depending on flag bits set, update various display properties; widgets
// ignore properties that are not applicable
if ( _flag & ACTGRF_FG1COLOR_MASK )
lineColor.setColorIndex( _fg1Color, actWin->ci );
if ( _flag & ACTGRF_BGCOLOR_MASK )
fillColor.setColorIndex( _bgColor, actWin->ci );
if ( _flag & ACTGRF_CTLFONTTAG_MASK ) {
strcpy( fontTag, _ctlFontTag );
alignment = _ctlAlignment;
fs = actWin->fi->getXFontStruct( fontTag );
updateFont( " ", fontTag, &fs,
&fontAscent, &fontDescent, &fontHeight,
&stringWidth );
updateDimensions();
}
}
//---------------------------------------------------------------------------
void edmBoxClass::changePvNames (
int flag,
int numCtlPvs,
char *ctlPvs[],
int numReadbackPvs,
char *readbackPvs[],
int numNullPvs,
char *nullPvs[],
int numVisPvs,
char *visPvs[],
int numAlarmPvs,
char *alarmPvs[] )
{
// Depending on flag bits set, update various process variable
// names; widgets ignore pv names that are not applicable
if ( flag & ACTGRF_CTLPVS_MASK ) {
if ( numCtlPvs ) {
pvExpStr.setRaw( ctlPvs[0] );
}
}
}
//---------------------------------------------------------------------------
int edmBoxClass::drawActive ( void ) {
XRectangle xR = { x, y, w, h };
int clipStat;
char string[31+1];
int ascent, descent, height, width;
int blink = 0;
if ( !init ) {
if ( needToDrawUnconnected ) {
actWin->executeGc.saveFg();
actWin->executeGc.setFG( lineColor.getDisconnectedIndex(), &blink );
actWin->executeGc.setLineWidth( 1 );
actWin->executeGc.setLineStyle( LineSolid );
XDrawRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.normGC(), x, y, w, h );
actWin->executeGc.restoreFg();
needToEraseUnconnected = 1;
updateBlink( blink );
}
}
else if ( needToEraseUnconnected ) {
actWin->executeGc.setLineWidth( 1 );
actWin->executeGc.setLineStyle( LineSolid );
XDrawRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.eraseGC(), x, y, w, h );
needToEraseUnconnected = 0;
}
if ( !enabled || !activeMode || !init ) return 1;
actWin->executeGc.saveFg();
clipStat = actWin->executeGc.addNormXClipRectangle( xR );
if ( fill ) {
actWin->executeGc.setFG( fillColor.getIndex(), &blink );
XFillRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.normGC(), valueBoxX, valueBoxY, valueBoxW, valueBoxH );
}
actWin->executeGc.setFG( lineColor.getIndex(), &blink );
actWin->executeGc.setLineWidth( lineWidth );
actWin->executeGc.setLineStyle( lineStyle );
XDrawRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.normGC(), valueBoxX, valueBoxY, valueBoxW, valueBoxH );
actWin->executeGc.setLineWidth( 1 );
actWin->executeGc.setLineStyle( LineSolid );
snprintf( string, 31, format, value );
if ( strcmp( fontTag, "" ) != 0 ) {
actWin->executeGc.setFontTag( fontTag, actWin->fi );
}
updateFont( string, fontTag, &fs,
&ascent, &descent, &height, &width );
xDrawText( actWin->d, XtWindow(actWin->executeWidget),
&actWin->executeGc, fs, textValueX, textValueY, alignment,
string );
prevValue = value;
if ( bufferInvalid ) {
xDrawText( actWin->d, XtWindow(actWin->executeWidget),
&actWin->executeGc, fs, labelX, labelY, alignment,
label );
bufferInvalid = 0;
}
if ( clipStat & 1 ) actWin->executeGc.removeNormXClipRectangle();
actWin->executeGc.restoreFg();
updateBlink( blink );
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::eraseActive ( void ) {
XRectangle xR = { x, y, w, h };
int clipStat;
char string[31+1];
if ( !enabled || !activeMode || !init ) return 1;
clipStat = actWin->executeGc.addEraseXClipRectangle( xR );
if ( fill ) {
XFillRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.eraseGC(), valueBoxX, valueBoxY, valueBoxW, valueBoxH );
}
actWin->executeGc.setLineWidth( lineWidth );
actWin->executeGc.setLineStyle( lineStyle );
XDrawRectangle( actWin->d, XtWindow(actWin->executeWidget),
actWin->executeGc.eraseGC(), valueBoxX, valueBoxY, valueBoxW, valueBoxH );
actWin->executeGc.setLineWidth( 1 );
actWin->executeGc.setLineStyle( LineSolid );
snprintf( string, 31, format, prevValue );
if ( strcmp( fontTag, "" ) != 0 ) {
actWin->executeGc.setFontTag( fontTag, actWin->fi );
}
xEraseText( actWin->d, XtWindow(actWin->executeWidget),
&actWin->executeGc, fs, textValueX, textValueY, alignment,
string );
if ( bufferInvalid ) {
xEraseText( actWin->d, XtWindow(actWin->executeWidget),
&actWin->executeGc, fs, labelX, labelY, alignment,
label );
}
if ( clipStat & 1 ) actWin->executeGc.removeEraseXClipRectangle();
return 1;
}
//---------------------------------------------------------------------------
void edmBoxClass::bufInvalidate ( void )
{
bufferInvalid = 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::expand1st (
int numMacros,
char *macros[],
char *expansions[] )
{
int stat;
stat = pvExpStr.expand1st( numMacros, macros, expansions );
return stat;
}
//---------------------------------------------------------------------------
int edmBoxClass::expand2nd (
int numMacros,
char *macros[],
char *expansions[] )
{
int stat;
stat = pvExpStr.expand2nd( numMacros, macros, expansions );
return stat;
}
//---------------------------------------------------------------------------
int edmBoxClass::containsMacros ( void ) {
if ( pvExpStr.containsPrimaryMacros() ) return 1;
return 0;
}
//---------------------------------------------------------------------------
int edmBoxClass::activate (
int pass,
void *ptr )
{
int stat;
switch ( pass ) {
case 1: // initialize
opComplete = 0;
break;
case 2: // connect to pv
if ( !opComplete ) {
initEnable();
aglPtr = ptr;
needConnectInit = needUpdate = needDraw = 0;
init = 0;
active = 0;
activeMode = 1;
bufferInvalid = 0;
pointerMotionDetected = 0;
pvId = NULL;
oldStat = oldSev = -1;
value = prevValue = 0;
needToDrawUnconnected = 0;
needToEraseUnconnected = 0;
unconnectedTimer = 0;
if ( !unconnectedTimer ) {
unconnectedTimer = appAddTimeOut( actWin->appCtx->appContext(),
2000, unconnectedTimeout, this );
}
if ( !pvExpStr.getExpanded() ||
( strcmp( pvExpStr.getExpanded(), "" ) == 0 ) ) {
pvExists = 0;
}
else {
pvExists = 1;
lineColor.setConnectSensitive();
fillColor.setConnectSensitive();
}
if ( pvExists ) {
pvId = the_PV_Factory->create( pvExpStr.getExpanded() );
if ( pvId ) {
pvId->add_conn_state_callback( monitorPvConnectState, this );
pvId->add_value_callback( pvUpdate, this );
}
else {
printf( edmBoxComplete_str21 );
}
}
else {
active = 1;
init = 1;
valueBoxW = w-2;
valueBoxX = x+1;
valueBoxH = boxH;
valueBoxY = boxY;
stat = drawActive();
}
opComplete = 1;
}
break;
case 3:
case 4:
case 5:
case 6:
break;
}
return 1;
}
//---------------------------------------------------------------------------
int edmBoxClass::deactivate (
int pass )
{
if ( pass == 1 ) {
if ( unconnectedTimer ) {
XtRemoveTimeOut( unconnectedTimer );
unconnectedTimer = 0;
}
updateBlink( 0 );
activeMode = 0;
if ( pvId ) {
pvId->remove_conn_state_callback( monitorPvConnectState, this );
pvId->remove_value_callback( pvUpdate, this );
pvId->release();
pvId = NULL;
}
}
return 1;
}
//---------------------------------------------------------------------------
void edmBoxClass::btnUp (
int x,
int y,
int buttonState,
int buttonNumber,
int *action )
{
double v, dInc;
*action = 0;
if ( !enabled ) return;
dInc = 10.0;
// wheel
if ( buttonNumber == 4 ) {
buttonNumber = 1;
dInc = 1.0;
}
if ( buttonNumber == 5 ) {
buttonNumber = 1;
buttonState |= ShiftMask;
dInc = 1.0;
}
// wheel
if ( buttonNumber != 1 ) return;
if ( pvExists && !pointerMotionDetected ) {
if ( buttonState & ShiftMask ) {
v = curValue - dInc;
if ( v < readMin ) v = readMin;
}
else {
v = curValue + dInc;
if ( v > readMax ) v = readMax;
}
pvId->put( v );
}
}
//---------------------------------------------------------------------------
void edmBoxClass::btnDown (
int x,
int y,
int buttonState,
int buttonNumber,
int *action )
{
if ( !enabled ) return;
if ( buttonNumber == 4 ) buttonNumber = 1;
if ( buttonNumber == 5 ) buttonNumber = 1;
if ( buttonNumber != 1 ) return;
pointerMotionDetected = 0;
}
//---------------------------------------------------------------------------
void edmBoxClass::btnDrag (
int x,
int y,
int buttonState,
int buttonNumber )
{
double v;
if ( !enabled ) return;
if ( buttonNumber != 1 ) return;
pointerMotionDetected = 1;
if ( pvExists ) {
if ( buttonState & ShiftMask ) {
v = curValue - 1.0;
if ( v < readMin ) v = readMin;
}
else {
v = curValue + 1.0;
if ( v > readMax ) v = readMax;
}
pvId->put( v );
}
}
//---------------------------------------------------------------------------
int edmBoxClass::getButtonActionRequest (
int *up,
int *down,
int *drag,
int *focus )
{
*drag = 1;
*down = 1;
*up = 1;
if ( pvExists )
*focus = 1;
else
*focus = 0;
return 1;
}
//---------------------------------------------------------------------------
void edmBoxClass::executeDeferred ( void ) {
int stat, nc, nu, nd;
if ( actWin->isIconified ) return;
actWin->appCtx->proc->lock();
if ( !activeMode ) {
actWin->remDefExeNode( aglPtr );
actWin->appCtx->proc->unlock();
return;
}
value = curValue;
nc = needConnectInit; needConnectInit = 0;
nu = needUpdate; needUpdate = 0;
nd = needDraw; needDraw = 0;
actWin->remDefExeNode( aglPtr );
actWin->appCtx->proc->unlock();
//--------------
if ( nc ) {
// require process variable to be numeric
if ( ( fieldType == ProcessVariable::Type::real ) ||
( fieldType == ProcessVariable::Type::integer ) ) {
snprintf( format, 15, "%%.%-df", precision );
stat = eraseActive();
if ( readMax > readMin ) {
factorW = (double) ( w - 2 ) / ( readMax - readMin );
factorH = (double) boxH / ( readMax - readMin );
}
else {
factorW = 1;
factorH = 1;
}
centerX = x + (int) ( w * 0.5 + 0.5 );
centerY = boxY + (int) ( boxH * 0.5 + 0.5 );
if ( value > 0.0 ) {
valueBoxW = (int) ( value * factorW + 0.5 );
valueBoxX = centerX - (int) ( (double) valueBoxW * 0.5 + 0.5 );
valueBoxH = (int) ( value * factorH + 0.5 );
valueBoxY = centerY - (int) ( (double) valueBoxH * 0.5 + 0.5 );
}
else {
valueBoxW = 1;
valueBoxX = centerX;
valueBoxH = 1;
valueBoxY = centerY;
}
init = 1;
active = 1;
lineColor.setConnected();
fillColor.setConnected();
bufInvalidate();
#if SMARTDRAW
smartDrawAllActive();
#else
drawActive();
#endif
}
else { // force a draw in the non-active state & post error message
actWin->appCtx->postMessage(
edmBoxComplete_str22 );
active = 0;
init = 1;
valueBoxW = w-2;
valueBoxX = x+1;
valueBoxH = boxH;
valueBoxY = boxY;
lineColor.setDisconnected();
fillColor.setDisconnected();
#if SMARTDRAW
smartDrawAllActive();
#else
drawActive();
#endif
}
}
//--------------
if ( nu ) {
eraseActive();
if ( value > 0.0 ) {
valueBoxW = (int) ( value * factorW + 0.5 );
valueBoxX = centerX - (int) ( (double) valueBoxW * 0.5 + 0.5 );
valueBoxH = (int) ( value * factorH + 0.5 );
valueBoxY = centerY - (int) ( (double) valueBoxH * 0.5 + 0.5 );
}
else {
valueBoxW = 1;
valueBoxX = centerX;
valueBoxH = 1;
valueBoxY = centerY;
}
#if SMARTDRAW
smartDrawAllActive();
#else
drawActive();
#endif
}
//--------------
if ( nd ) {
#if SMARTDRAW
smartDrawAllActive();
#else
drawActive();
#endif
}
}
//---------------------------------------------------------------------------
char *edmBoxClass::firstDragName ( void ) {
if ( !enabled ) return NULL;
dragIndex = 0;
return dragName[dragIndex];
}
//---------------------------------------------------------------------------
char *edmBoxClass::nextDragName ( void ) {
return NULL;
}
//---------------------------------------------------------------------------
char *edmBoxClass::dragValue (
int i ) {
if ( !enabled ) return NULL;
if ( actWin->mode == AWC_EXECUTE ) {
return pvExpStr.getExpanded();
}
else {
return pvExpStr.getRaw();
}
}
//---------------------------------------------------------------------------
// X windows makes client code do blinking if color depth is
// anything other than 8 bits
void edmBoxClass::doBlink (
void *ptr
) {
edmBoxClass *ebo = (edmBoxClass *) ptr;
if ( !ebo->activeMode ) {
if ( ebo->isSelected() ) ebo->drawSelectBoxCorners(); // erase via xor
#if SMARTDRAW
ebo->smartDrawAll();
#else
ebo->draw();
#endif
if ( ebo->isSelected() ) ebo->drawSelectBoxCorners();
}
else {
ebo->actWin->appCtx->proc->lock();
ebo->bufInvalidate();
ebo->needUpdate = 1;
ebo->actWin->addDefExeNode( ebo->aglPtr );
ebo->actWin->appCtx->proc->unlock();
}
}
//---------------------------------------------------------------------------
void edmBoxClass::unconnectedTimeout (
XtPointer client,
XtIntervalId *id )
{
edmBoxClass *ebo = (edmBoxClass *) client;
if ( !ebo->init ) {
ebo->actWin->appCtx->proc->lock();
ebo->bufInvalidate();
ebo->needToDrawUnconnected = 1;
ebo->needUpdate = 1;
ebo->actWin->addDefExeNode( ebo->aglPtr );
ebo->actWin->appCtx->proc->unlock();
}
ebo->unconnectedTimer = 0;
}
//---------------------------------------------------------------------------
void edmBoxClass::monitorPvConnectState (
ProcessVariable *pv,
void *userarg )
{
edmBoxClass *ebo = (edmBoxClass *) userarg;
ebo->actWin->appCtx->proc->lock();
if ( !ebo->activeMode ) {
ebo->actWin->appCtx->proc->unlock();
return;
}
if ( pv->is_valid() ) {
ebo->fieldType = (int) pv->get_type().type;
ebo->curValue = pv->get_double();
if ( ebo->efReadMin.isNull() ) {
ebo->readMin = pv->get_lower_disp_limit();
}
else {
ebo->readMin = ebo->efReadMin.value();
}
if ( ebo->efReadMax.isNull() ) {
ebo->readMax = pv->get_upper_disp_limit();
}
else {
ebo->readMax = ebo->efReadMax.value();
}
if ( ebo->efPrecision.isNull() ) {
ebo->precision = pv->get_precision();
}
else {
ebo->precision = ebo->efPrecision.value();
}
ebo->needConnectInit = 1;
}
else { // lost connection
ebo->active = 0;
ebo->lineColor.setDisconnected();
ebo->fillColor.setDisconnected();
ebo->bufInvalidate();
ebo->needDraw = 1;
}
ebo->actWin->addDefExeNode( ebo->aglPtr );
ebo->actWin->appCtx->proc->unlock();
}
//---------------------------------------------------------------------------
void edmBoxClass::pvUpdate (
ProcessVariable *pv,
void *userarg )
{
class edmBoxClass *ebo = (edmBoxClass *) userarg;
int st, sev;
if ( !ebo->activeMode ) return;
ebo->actWin->appCtx->proc->lock();
ebo->curValue = pv->get_double();
ebo->needUpdate = 1;
st = pv->get_status();
sev = pv->get_severity();
if ( ( st != ebo->oldStat ) || ( sev != ebo->oldSev ) ) {
ebo->oldStat = st;
ebo->oldSev = sev;
ebo->lineColor.setStatus( st, sev );
ebo->fillColor.setStatus( st, sev );
ebo->needDraw = 1;
ebo->bufInvalidate();
}
ebo->actWin->addDefExeNode( ebo->aglPtr );
ebo->actWin->appCtx->proc->unlock();
}
//---------------------------------------------------------------------------
// "C" compatible class factory functions
extern "C" {
void *create_2ed7d2e8_f439_11d2_8fed_00104b8742dfPtr ( void ) {
edmBoxClass *ptr;
ptr = new edmBoxClass;
return (void *) ptr;
}
void *clone_2ed7d2e8_f439_11d2_8fed_00104b8742dfPtr (
void *_srcPtr )
{
edmBoxClass *ptr, *srcPtr;
srcPtr = (edmBoxClass *) _srcPtr;
ptr = new edmBoxClass( srcPtr );
return (void *) ptr;
}
}