libcm/cmGrPlot.c
kevin 9d6ac977aa Changed cmGr,cmGrPlot,cmGrPlotAudio to better handle events.
Rewrote cmGr.c::cmGrEvent()
Callback cmGrIsInsideObj() now must evaluate both if the mouse point is
inside the object and also if the object can handle the event. This
allows the actual plot object which can handle an event to be identified
by cmGrEvent().

_cmGrPlotObjEvent() still needs to be updated to account for these changes.
2012-12-17 20:54:37 -08:00

1364 lines
36 KiB
C

#include "cmGlobal.h"
#include "cmFloatTypes.h"
#include "cmRpt.h"
#include "cmErr.h"
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmGr.h"
#include "cmGrDevCtx.h"
#include "cmGrPlot.h"
#include "cmVectOpsTemplateMain.h"
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
struct cmGrPl_str;
typedef struct cmGrPlotObj_str
{
cmGrH_t grH; // the canvas this object is drawn on
cmGrObjH_t grObjH; // the grObj this object is based on
cmGrPlObjTypeId_t typeId;
unsigned cfgFlags;
unsigned stateFlags;
cmGrVExt_t vext;
cmChar_t* label;
unsigned labelFlags;
int labelAngle;
cmGrColor_t labelColor;
int loffs;
int toffs;
int roffs;
int boffs;
cmGrColor_t drawColors[ kMaxPlGrId ];
cmGrColor_t fillColors[ kMaxPlGrId ];
unsigned fontId;
unsigned fontSize;
unsigned fontStyle;
void* userPtr;
unsigned userByteCnt; // 0 if userPtr does not need to be realease on object destruction
cmGrPlotCbFunc_t cbFunc;
void* cbArg;
struct cmGrPl_str* p; // owning plot object manager
struct cmGrPlotObj_str* parent; // containing object
struct cmGrPlotObj_str* xAnchor; // x-location reference object
struct cmGrPlotObj_str* yAnchor; // y-location reference object
struct cmGrPlotObj_str* next;
struct cmGrPlotObj_str* prev;
} cmGrPlotObj_t;
typedef struct cmGrPl_str
{
cmCtx_t* ctx; //
cmErr_t err; //
cmGrPlotObj_t* list; // plot object linked list
cmGrPlotObj_t* fop; // focused object ptr
cmGrPlotCbFunc_t cbFunc; // dflt callback function
void* cbArg; // dflt callback function arg.
} cmGrPl_t;
cmGrPlH_t cmGrPlNullHandle = cmSTATIC_NULL_HANDLE;
cmGrPlObjH_t cmGrPlObjNullHandle = cmSTATIC_NULL_HANDLE;
//------------------------------------------------------------------------------------------------------------------
// Plot Private Functions
//------------------------------------------------------------------------------------------------------------------
cmGrPl_t* _cmGrPlHandleToPtr( cmGrPlH_t h )
{
cmGrPl_t* p = (cmGrPl_t*)h.h;
assert(p!=NULL);
return p;
}
cmGrPlotObj_t* _cmGrPlObjHandleToPtr( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = (cmGrPlotObj_t*)oh.h;
assert( op!=NULL);
return op;
}
cmGrPlRC_t _cmGrPlotObjDelete( cmGrPlotObj_t* op )
{
if( op==NULL || cmGrObjIsValid( op->grH, op->grObjH)==false )
return kOkGrPlRC;
cmGrPl_t* p = op->p;
// destroy the cmGrObj - which will call _cmGrPlotObjDestroy()
if( cmGrObjDestroy( op->grH, &op->grObjH ) != kOkGrRC )
return cmErrMsg( &p->err, kGrFailGrPlRC, "Delete failed on the object label='%s' id=%i\n",cmStringNullGuard( op->label ), cmGrObjId(op->grObjH) );
if( op->userByteCnt != 0 )
{
cmMemFree(op->userPtr);
op->userByteCnt = 0;
}
return kOkGrPlRC;
}
void _cmGrPlotObjUnlink( cmGrPlotObj_t* op )
{
cmGrPl_t* p = op->p;
if( op->next != NULL )
op->next->prev = op->prev;
if( op->prev != NULL )
op->prev->next = op->next;
if( p->list == op )
p->list = op->next;
}
void _cmGrPlotObjLink( cmGrPl_t* p, cmGrPlotObj_t* op )
{
if( p->list != NULL )
p->list->prev = op;
op->next = p->list;
op->prev = NULL;
p->list = op;
}
// Destroy all objects
cmGrPlRC_t _cmGrPlotClear( cmGrPl_t* p )
{
cmGrPlRC_t rc = kOkGrPlRC;
cmGrPlotObj_t* op = p->list;
while( op!=NULL )
{
cmGrPlotObj_t* t = op->next;
if((rc = _cmGrPlotObjDelete(op)) != kOkGrPlRC )
break;
op = t;
}
return rc;
}
// Destroy the plot mgr
cmGrPlRC_t _cmGrPlotDestroy( cmGrPl_t* p )
{
cmGrPlRC_t rc;
if((rc = _cmGrPlotClear(p)) != kOkGrPlRC )
return rc;
cmMemFree(p);
return kOkGrPlRC;
}
bool _cmGrPlotObjIsVisible( cmGrPlotObj_t* op )
{ return cmIsNotFlag(op->cfgFlags,kNoDrawGrPlFl); }
bool _cmGrPlotObjIsEnabled( cmGrPlotObj_t* op )
{
// invisible objects are never enabled
if( _cmGrPlotObjIsVisible(op) == false )
return false;
return cmIsFlag(op->stateFlags,kEnabledGrPlFl);
}
bool _cmGrPlotObjIsFocused(cmGrPlotObj_t* op)
{ return _cmGrPlotObjIsEnabled(op) && op->p->fop==op; }
bool _cmGrPlotObjIsSelected(cmGrPlotObj_t* op)
{ return _cmGrPlotObjIsFocused(op) || cmIsFlag(op->stateFlags,kSelectGrPlFl); }
void _cmGrPlotObjSetupCbArg( cmGrPlotCbArg_t* a, cmGrPlotObj_t* op, cmGrPlCbSelId_t selId )
{
cmGrPlObjH_t oH;
oH.h = op;
memset(a,0,sizeof(a));
a->ctx = op->p->ctx;
a->cbArg = op->cbArg;
a->selId = selId;
a->objH = oH;
}
bool _cmGrPlotObjCb( cmGrPlotObj_t* op, cmGrPlCbSelId_t selId, unsigned deltaFlags )
{
if( op->cbFunc != NULL )
{
cmGrPlotCbArg_t a;
_cmGrPlotObjSetupCbArg(&a,op,selId);
a.deltaFlags = deltaFlags;
return op->cbFunc(&a);
}
return true;
}
void _cmGrPlotObjSetFocus( cmGrPlotObj_t* op )
{
// if 'op' is not enabled then it cannot receive the focus
if( _cmGrPlotObjIsEnabled(op) == false )
return;
// if the focus cannot be set on 'op' - then try op->parent
for(; op!=NULL; op=op->parent)
if( cmIsNotFlag(op->cfgFlags,kNoFocusGrPlFl) && cmIsNotFlag(op->cfgFlags,kNoDrawGrPlFl) )
break;
// if the focus is changing to a new object
if( op != NULL && op->p->fop != op )
{
if( op->p->fop != NULL )
{
// if the application callback returns false then do no release focus from the current object
if(_cmGrPlotObjCb(op->p->fop, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false )
return;
cmGrPlotObj_t* fop = op->p->fop;
op->p->fop = NULL;
// notify focus loser
_cmGrPlotObjCb(fop, kStateChangeGrPlId, kFocusGrPlFl );
}
// if the application callback returns false then do not give focus to the selected object
if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false )
return;
op->p->fop = op;
// notify focus winner
_cmGrPlotObjCb(op, kStateChangeGrPlId, kFocusGrPlFl );
}
}
void _cmGrPlotObjSetSelect( cmGrPlotObj_t* op, bool clearFl )
{
// if the object is disabled or not selectable
if( _cmGrPlotObjIsEnabled(op)==false || cmIsFlag(op->cfgFlags,kNoSelectGrPlFl | kNoDrawGrPlFl) )
return;
unsigned stateFlags = op->stateFlags;
// if the application callback returns false then do change the select state of the object
if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kSelectGrPlFl ) == false )
return;
if( clearFl )
{
cmGrObjH_t parentObjH = cmGrObjParent(op->grObjH);
cmGrPlotObj_t* cop = op->p->list;
// clear the select flag on all objects that share op->parent
for(; cop!=NULL; cop=cop->next)
if( cmHandlesAreEqual(cmGrObjParent(cop->grObjH),parentObjH) )
cop->stateFlags = cmClrFlag(cop->stateFlags,kSelectGrPlFl);
}
op->stateFlags = cmTogFlag(stateFlags,kSelectGrPlFl);
// notify state change
_cmGrPlotObjCb(op, kStateChangeGrPlId, kSelectGrPlFl );
}
const cmGrColor_t _cmGrPlotColor( cmGrPlotObj_t* op, cmGrColor_t* array )
{
if( _cmGrPlotObjIsFocused(op) )
return array[kFocusPlGrId];
if( _cmGrPlotObjIsSelected(op) )
return array[kSelectPlGrId];
if( _cmGrPlotObjIsEnabled(op) )
return array[kEnablePlGrId];
return array[kDisablePlGrId];
}
unsigned _cmGrPlotObjTriShapeToFlags( unsigned typeId)
{
switch(typeId)
{
case kUTriGrPlId: return kTopGrFl;
case kDTriGrPlId: return kBottomGrFl;
case kLTriGrPlId: return kLeftGrFl;
case kRTriGrPlId: return kRightGrFl;
default:
{ assert(0); }
}
return 0;
}
//------------------------------------------------------------------------------------------------------------------
// Plot Object Callback Functions
//------------------------------------------------------------------------------------------------------------------
cmGrRC_t _cmGrPlotObjCreate( cmGrObjFuncArgs_t* args )
{
cmGrPlotObj_t* op = args->cbArg;
_cmGrPlotObjCb(op,kCreatedCbSelGrPlId,0);
// return kOkGrRC to indicate that the create was successful
return kOkGrRC;
}
void _cmGrPlotObjDestroy( cmGrObjFuncArgs_t* args )
{
cmGrPlotObj_t* op = args->cbArg;
// TODO: is it possible to prevent destruction by returning
// 'false' from the used defined callback. This feature is
// slightly complicated by the fact
// that in some circumstances the destroy request is not
// optional - for example when the program is closing.
_cmGrPlotObjCb(op,kDestroyedCbSelGrPlId,0);
_cmGrPlotObjUnlink( op );
cmMemFree(op->label);
cmMemFree(op);
}
void _cmGrPlotObjGetVExt( cmGrPlotObj_t* op, cmGrVExt_t* vext )
{
switch( op->typeId )
{
case kStarGrPlId:
case kCrossGrPlId:
case kPlusGrPlId:
case kDiamondGrPlId:
case kUTriGrPlId:
case kDTriGrPlId:
case kLTriGrPlId:
case kRTriGrPlId:
case kRectGrPlId:
case kLineGrPlId:
case kEllipseGrPlId:
{
*vext = op->vext;
}
break;
case kHLineGrPlId:
case kVLineGrPlId:
{
cmGrVExt_t wext;
cmGrObjH_t oh = cmGrObjParent(op->grObjH);
cmGrObjWorldExt(oh,&wext);
// TODO: Put a check somewhere which can report an error
// message when the parents world extent is not yet set.
// Horz and Vert lines depend on the their parent's
// world extents being set first. There is no automatic
// way to set the parent world extents because we don't
// know the range of values which the data set will cover.
// Any number picked could result in a range much to large
// thereby leaving the data invisible. It therefore must
// be up to the application to set a good range.
assert( cmGrVExtIsNotNullOrEmpty(&wext) );
vext->loc.x = op->typeId==kHLineGrPlId ? wext.loc.x : op->vext.loc.x;
vext->loc.y = op->typeId==kVLineGrPlId ? wext.loc.y : op->vext.loc.y;
vext->sz.w = op->typeId==kHLineGrPlId ? wext.sz.w : op->vext.sz.w;
vext->sz.h = op->typeId==kVLineGrPlId ? wext.sz.h : op->vext.sz.h;
}
break;
default:
{ assert(0); }
}
// add up the anchor offsets until the first object in the container
cmGrPlotObj_t* ap = op->xAnchor;
for(; ap!=NULL; ap=ap->xAnchor)
{
vext->loc.x += ap->vext.loc.x;
if( ap->xAnchor==ap->parent)
break;
}
ap = op->yAnchor;
for(; ap!=NULL; ap=ap->yAnchor)
{
vext->loc.y += ap->vext.loc.y;
if( ap->yAnchor==ap->parent)
break;
}
}
void _cmGrPlotObjVExt( cmGrObjFuncArgs_t* args, cmGrVExt_t* vext )
{
cmGrPlotObj_t* op = args->cbArg;
_cmGrPlotObjGetVExt(op, vext);
}
bool _cmGrPlotObjRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH )
{
cmGrPlotObj_t* op = args->cbArg;
cmGrPExt_t pext;
cmGrVExt_t vext;
if( !_cmGrPlotObjIsVisible(op) )
return false;
// get the virtual extents of this object
_cmGrPlotObjVExt( args, &vext );
// convert the virtual ext's to phys ext's
cmGrVExt_VtoP( op->grH, op->grObjH, &vext, &pext);
// expand the ext's according to the physical offsets
cmGrPExtExpand(&pext,op->loffs,op->toffs,op->roffs,op->boffs);
switch( op->typeId )
{
case kLineGrPlId:
//cmGrDcSetColor( dcH, _cmGrPlotColor(op,op->drawColors) );
//cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext) );
//break;
case kStarGrPlId:
case kCrossGrPlId:
case kPlusGrPlId:
case kEllipseGrPlId:
case kDiamondGrPlId:
case kUTriGrPlId:
case kDTriGrPlId:
case kLTriGrPlId:
case kRTriGrPlId:
case kRectGrPlId:
case kHLineGrPlId:
case kVLineGrPlId:
{
if( cmIsNotFlag(op->cfgFlags,kNoFillGrPlFl) )
{
// set the fill color
cmGrDcSetColor( dcH, _cmGrPlotColor(op,op->fillColors) );
// draw the fill
switch(op->typeId)
{
case kEllipseGrPlId:
cmGrDcFillEllipse( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
case kDiamondGrPlId:
cmGrDcFillDiamond( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
case kUTriGrPlId:
case kDTriGrPlId:
case kLTriGrPlId:
case kRTriGrPlId:
cmGrDcFillTriangle( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h, _cmGrPlotObjTriShapeToFlags(op->typeId));
break;
case kStarGrPlId:
case kCrossGrPlId:
case kPlusGrPlId:
case kRectGrPlId:
case kHLineGrPlId:
case kVLineGrPlId:
cmGrDcFillRect( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
case kLineGrPlId:
break;
default:
{ assert(0); }
}
}
if( cmIsNotFlag(op->cfgFlags,kNoBorderGrPlFl) )
{
// set the border color
cmGrDcSetColor( dcH, _cmGrPlotColor(op,op->drawColors) );
// draw the border
switch(op->typeId)
{
case kEllipseGrPlId:
cmGrDcDrawEllipse( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
case kDiamondGrPlId:
cmGrDcDrawDiamond( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
case kUTriGrPlId:
case kDTriGrPlId:
case kLTriGrPlId:
case kRTriGrPlId:
cmGrDcDrawTriangle( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h, _cmGrPlotObjTriShapeToFlags(op->typeId));
break;
case kStarGrPlId:
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext));
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtB(&pext), cmGrPExtR(&pext), cmGrPExtT(&pext));
cmGrDcDrawLine( dcH, cmGrPExtL(&pext) + cmGrPExtW(&pext)/2, cmGrPExtT(&pext), cmGrPExtL(&pext) + cmGrPExtW(&pext)/2, cmGrPExtB(&pext));
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2, cmGrPExtR(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2);
break;
case kCrossGrPlId:
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext));
cmGrDcDrawLine( dcH, cmGrPExtR(&pext), cmGrPExtT(&pext), cmGrPExtL(&pext), cmGrPExtB(&pext));
break;
case kPlusGrPlId:
cmGrDcDrawLine( dcH, cmGrPExtL(&pext) + cmGrPExtW(&pext)/2, cmGrPExtT(&pext), cmGrPExtL(&pext) + cmGrPExtW(&pext)/2, cmGrPExtB(&pext));
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2, cmGrPExtR(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2);
break;
case kLineGrPlId:
cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext) );
break;
case kRectGrPlId:
case kHLineGrPlId:
case kVLineGrPlId:
cmGrDcDrawRect( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h);
break;
default:
{ assert(0); }
}
}
if( (op->label != NULL) && cmIsNotFlag(op->cfgFlags, kNoLabelGrPlFl) )
{
unsigned cc = cmGrDcColor(dcH);
cmGrDcSetColor(dcH,op->labelColor);
cmGrDcDrawTextJustify( dcH, op->fontId, op->fontSize, op->fontStyle, op->label, &pext, op->labelFlags );
cmGrDcSetColor(dcH,cc);
/*
cmGrPSz_t sz;
cmGrPPt_t pt;
cmGrDcFontSetAndMeasure( dcH, op->fontId, op->fontSize, op->fontStyle, op->label, &sz );
cmGrPExtCtr( &pext, &pt );
cmGrDcDrawText( dcH, op->label, pt.x - sz.w/2, pt.y + sz.h/2 );
*/
}
}
break;
default:
{ assert(0); }
}
return true;
}
int _cmGrPlotObjDistance( cmGrObjFuncArgs_t* args, int x, int y )
{
return 0;
}
bool _cmGrPlotObjEvent( cmGrObjFuncArgs_t* args, unsigned flags, unsigned key, int px, int py )
{
cmGrPlotObj_t* op = args->cbArg;
bool fl = false;
cmGrPlotCbArg_t a;
if( op->cbFunc != NULL )
{
cmGrPlotObj_t* cb_op = op;
// if this is a key up/dn event and 'op' is not the 'focused op' then callback
// callback on the 'focused op' instead of this 'op'.
if( (cmIsFlag(flags,kKeyDnGrFl) || cmIsFlag(flags,kKeyUpGrFl)) && op->p->fop != op )
cb_op = op->p->fop;
_cmGrPlotObjSetupCbArg(&a,cb_op,kPreEventCbSelGrPlId);
a.eventFlags = flags;
a.eventKey = key;
a.eventX = px;
a.eventY = py;
if( op->cbFunc(&a) == false )
return true;
}
switch( flags & kEvtMask )
{
case kMsDownGrFl:
break;
case kMsUpGrFl:
_cmGrPlotObjSetFocus( op );
fl = true;
break;
case kMsClickGrFl:
_cmGrPlotObjSetSelect(op, cmIsNotFlag(flags,kCtlKeyGrFl) );
fl = true;
break;
case kMsDragGrFl:
{
cmGrVExt_t vext;
cmGrVExt_t wext;
if( cmIsFlag(op->cfgFlags,kNoDragGrPlFl | kNoDrawGrPlFl) )
return false;
// get the parent world extents
cmGrObjWorldExt( cmGrObjParent( args->objH ), &wext );
// calc the new position of the obj
cmGrV_t x = args->msVPt.x - args->msDnVOffs.w;
cmGrV_t y = args->msVPt.y - args->msDnVOffs.h;
cmGrVExtSet(&vext,x,y,op->vext.sz.w,op->vext.sz.h);
// the obj must be remain inside the parent wext
cmGrVExtContain(&wext,&vext);
// calculate the obj's location as an offset from it's anchors
cmGrPlotObj_t* ap = op->xAnchor;
for(; ap!=NULL; ap=ap->xAnchor)
vext.loc.x -= ap->vext.loc.x;
ap = op->yAnchor;
for(; ap!=NULL; ap=ap->yAnchor)
vext.loc.y -= ap->vext.loc.y;
if( !cmGrVExtIsEqual(&op->vext,&vext) )
{
// move the object
op->vext.loc.x = vext.loc.x;
op->vext.loc.y = vext.loc.y;
fl = true;
}
}
break;
case kKeyDnGrFl:
case kKeyUpGrFl:
break;
}
// notify the app of the event
if( op->cbFunc != NULL )
{
a.selId = kEventCbSelGrPlId;
op->cbFunc(&a);
}
return fl;
}
bool _cmGrPlotObjIsBorderClick( const cmGrPExt_t* pext, int px, int py )
{
int dist = 3;
if( cmVOR_PtToLineDistance(cmGrPExtL(pext),cmGrPExtT(pext),cmGrPExtL(pext),cmGrPExtB(pext),px,py) < dist )
return true;
if(cmVOR_PtToLineDistance(cmGrPExtR(pext),cmGrPExtT(pext),cmGrPExtR(pext),cmGrPExtB(pext),px,py) < dist )
return true;
if( cmVOR_PtToLineDistance(cmGrPExtL(pext),cmGrPExtT(pext),cmGrPExtR(pext),cmGrPExtT(pext),px,py) < dist )
return true;
if(cmVOR_PtToLineDistance(cmGrPExtL(pext),cmGrPExtB(pext),cmGrPExtR(pext),cmGrPExtB(pext),px,py) < dist )
return true;
return false;
}
bool _cmGrPlotObjIsInside( cmGrObjFuncArgs_t* args, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy )
{
cmGrVExt_t vext;
cmGrPExt_t pext;
cmGrPlotObj_t* op = args->cbArg;
// no matter the type of event the object must be visible and enabled to respond to it
if(!_cmGrPlotObjIsVisible(op)|| !_cmGrPlotObjIsEnabled(op) )
return false;
// objects that are not selectable are also not clickable
if( cmIsFlag(evtFlags,kMsClickGrFl) && cmIsFlag(op->cfgFlags,kNoSelectGrPlFl) )
return false;
// non-draggable objects can't be dragged.
if( cmIsFlag(evtFlags,kMsDragGrFl) && cmIsFlag(op->cfgFlags,kNoDragGrPlFl) )
return false;
// get the virtual extents of this object
_cmGrPlotObjVExt( args, &vext );
// convert the virtual ext's to phys ext's
cmGrVExt_VtoP(args->grH,args->objH,&vext,&pext);
// expand the ext's according to the off's
cmGrPExtExpand(&pext,op->loffs,op->toffs,op->roffs,op->boffs);
if( op->typeId == kLineGrPlId )
if( cmVOR_PtToLineDistance(cmGrPExtL(&pext),cmGrPExtT(&pext),cmGrPExtR(&pext),cmGrPExtB(&pext),px,py) < 3 )
return true;
// if this is a click event and this is a border selectable object
if( cmIsFlag(evtFlags,kMsClickGrFl) && cmIsFlag(op->cfgFlags,kBorderSelGrPlFl) )
return _cmGrPlotObjIsBorderClick(&pext,px,py);
// check if the px,py is inside pext
return cmGrPExtIsXyInside(&pext,px,py);
}
void _cmGrPlotFuncObjSetupDefault(cmGrObjFunc_t *f, void* arg )
{
f->createCbFunc = _cmGrPlotObjCreate;
f->createCbArg = arg;
f->destroyCbFunc = _cmGrPlotObjDestroy;
f->destroyCbArg = arg;
f->renderCbFunc = _cmGrPlotObjRender;
f->renderCbArg = arg;
f->distanceCbFunc = _cmGrPlotObjDistance;
f->distanceCbArg = arg;
f->eventCbFunc = _cmGrPlotObjEvent;
f->eventCbArg = arg;
f->vextCbFunc = _cmGrPlotObjVExt;
f->vextCbArg = arg;
f->isInsideCbFunc = _cmGrPlotObjIsInside;
f->isInsideCbArg = arg;
}
//------------------------------------------------------------------------------------------------------------------
// Plot Object Public Functions
//------------------------------------------------------------------------------------------------------------------
cmGrPlRC_t cmGrPlotObjCreate(
cmGrPlH_t hh,
cmGrH_t grH,
cmGrPlObjH_t* hp,
unsigned id,
cmGrPlObjH_t parentPlObjH,
cmGrPlObjH_t xAnchorPlObjH,
cmGrPlObjH_t yAnchorPlObjH,
cmGrPlObjTypeId_t typeId,
unsigned cfgFlags,
cmReal_t x,
cmReal_t y,
cmReal_t w,
cmReal_t h,
const cmChar_t* label,
const cmGrVExt_t* wext )
{
cmGrPlRC_t rc;
cmGrObjFunc_t funcs;
if((rc = cmGrPlotObjDestroy(hp)) != kOkGrPlRC )
return rc;
cmGrPl_t* p = _cmGrPlHandleToPtr(hh);
cmGrPlotObj_t* op = cmMemAllocZ(cmGrPlotObj_t,1);
_cmGrPlotObjLink(p,op);
_cmGrPlotFuncObjSetupDefault(&funcs,op);
// setup the object
op->grH = grH;
op->typeId = typeId;
op->cfgFlags = cfgFlags;
op->stateFlags = kEnabledGrPlFl;
op->label = label==NULL ?NULL : cmMemAllocStr(label);
op->labelFlags = kHorzCtrJsGrFl | kVertCtrJsGrFl;
op->labelAngle = 0;
op->labelColor = kBlackGrId;
op->grObjH = cmGrObjNullHandle;
op->parent = cmGrPlotObjIsValid(parentPlObjH) ? _cmGrPlObjHandleToPtr(parentPlObjH) : NULL;
op->xAnchor = cmGrPlotObjIsValid(xAnchorPlObjH) ? _cmGrPlObjHandleToPtr(xAnchorPlObjH) : NULL;
op->yAnchor = cmGrPlotObjIsValid(yAnchorPlObjH) ? _cmGrPlObjHandleToPtr(yAnchorPlObjH) : NULL;
op->p = p;
op->fontId = kHelveticaFfGrId;
op->fontSize = 12;
op->fontStyle = kNormalFsGrFl;
op->cbFunc = p->cbFunc;
op->cbArg = p->cbArg;
if( cmIsFlag(op->cfgFlags,kSymbolGrPlFl) )
{
int ww = w==0 ? kDefaultSymW : w;
int hh = h==0 ? kDefaultSymH : h;
op->loffs = ww/2;
op->roffs = ww/2;
op->toffs = hh/2;
op->boffs = hh/2;
w = 0;
h = 0;
}
cmGrVExtSet(&op->vext,x,y,w,h);
// set the default colors
op->drawColors[kSelectPlGrId] = 0xcd853f;
op->fillColors[kSelectPlGrId] = 0xdeb887;
op->drawColors[kFocusPlGrId] = 0x483d8b;
op->fillColors[kFocusPlGrId] = 0x8470ff;
op->drawColors[kEnablePlGrId] = 0x000000;
op->fillColors[kEnablePlGrId] = 0x009ff7;
op->drawColors[kDisablePlGrId] = 0xbebebe;
op->fillColors[kDisablePlGrId] = 0xd3d3de;
unsigned grObjCfgFlags = 0;
cmGrObjH_t parentGrH = op->parent == NULL ? cmGrObjNullHandle : op->parent->grObjH;
// create the graphics system object - during this call a
// call is made to funcs.create().
if( cmGrObjCreate(grH, &op->grObjH, parentGrH, &funcs, id, grObjCfgFlags, wext ) != kOkGrRC )
{
rc = cmErrMsg(&p->err,kGrFailGrPlRC,"Graphic system object create failed for object (id=%i).",id);
goto errLabel;
}
if( hp != NULL )
hp->h = op;
errLabel:
if( rc != kOkGrPlRC )
_cmGrPlotObjDelete(op);
return rc;
}
cmGrPlRC_t cmGrPlotObjDestroy( cmGrPlObjH_t* hp )
{
cmGrPlRC_t rc = kOkGrPlRC;
if( hp==NULL || cmGrPlotObjIsValid(*hp)==false )
return kOkGrPlRC;
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(*hp);
if((rc = _cmGrPlotObjDelete(op)) != kOkGrPlRC )
return rc;
hp->h = NULL;
return rc;
}
bool cmGrPlotObjIsValid( cmGrPlObjH_t h )
{ return h.h != NULL; }
cmGrPlH_t cmGrPlotObjMgrHandle( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
cmGrPlH_t grPlH;
grPlH.h = op->p;
return grPlH;
}
cmGrObjH_t cmGrPlotObjHandle( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->grObjH;
}
cmGrPlObjH_t cmGrPlotObjParent( cmGrPlObjH_t oh )
{
cmGrPlObjH_t p_oh;
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
p_oh.h = op->parent;
return p_oh;
}
cmGrPlObjH_t cmGrPlotObjXAnchor( cmGrPlObjH_t oh )
{
cmGrPlObjH_t p_oh;
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
p_oh.h = op->xAnchor;
return p_oh;
}
cmGrPlObjH_t cmGrPlotObjYAnchor( cmGrPlObjH_t oh )
{
cmGrPlObjH_t p_oh;
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
p_oh.h = op->yAnchor;
return p_oh;
}
void cmGrPlotObjSetId( cmGrPlObjH_t oh, unsigned id )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
cmGrObjSetId( op->grObjH, id );
}
void cmGrPlotObjSetUserPtr( cmGrPlObjH_t oh, void* userPtr )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
if( op->userByteCnt != 0 )
{
cmMemFree(op->userPtr);
op->userByteCnt = 0;
}
op->userPtr = userPtr;
}
void cmGrPlotObjAllocUser( cmGrPlObjH_t oh, const void* data, unsigned byteCnt )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
if( op->userByteCnt != byteCnt )
{
if( op->userByteCnt != 0 )
{
cmMemFree(op->userPtr);
op->userByteCnt = 0;
}
op->userPtr = cmMemAlloc(char,byteCnt);
op->userByteCnt = byteCnt;
}
memcpy(op->userPtr,data,byteCnt);
}
void* cmGrPlotObjUserPtr( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->userPtr;
}
unsigned cmGrPlotObjId( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return cmGrObjId(op->grObjH);
}
void cmGrPlotObjSetLabel( cmGrPlObjH_t oh, const cmChar_t* label )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
if( label == op->label || (label != NULL && op->label!=NULL && strcmp(label,op->label)==0 ))
return;
cmMemPtrFree(&op->label);
if( label != NULL )
{
assert( op->label == NULL );
op->label = cmMemAllocStr(label);
}
}
const cmChar_t* cmGrPlotObjLabel( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->label;
}
void cmGrPlotObjSetLabelAttr( cmGrPlObjH_t oh, unsigned flags, int angle, const cmGrColor_t color )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->labelFlags = flags;
op->labelAngle = angle;
op->labelColor = color;
}
unsigned cmGrPlotObjLabelFlags( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->labelFlags;
}
int cmGrPlotObjLabelAngle( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->labelAngle;
}
const cmGrColor_t cmGrPlotObjLabelColor( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->labelColor;
}
void cmGrPlotObjSetStateFlags( cmGrPlObjH_t oh, unsigned flags )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
if( cmIsFlag(flags,kVisibleGrPlFl) != _cmGrPlotObjIsVisible(op) )
{
if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kVisibleGrPlFl ) == false )
return;
op->cfgFlags = cmTogFlag(op->cfgFlags,kNoDrawGrPlFl);
_cmGrPlotObjCb(op, kStateChangeGrPlId, kVisibleGrPlFl );
}
if( cmIsFlag(flags,kEnabledGrPlFl) != _cmGrPlotObjIsEnabled(op) )
{
if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kEnabledGrPlFl ) == false )
return;
op->stateFlags = cmTogFlag(op->cfgFlags,kEnabledGrPlFl);
_cmGrPlotObjCb(op, kStateChangeGrPlId, kEnabledGrPlFl );
}
bool fl;
if( cmIsFlag(flags,kSelectGrPlFl) != (fl=_cmGrPlotObjIsSelected(op)) )
_cmGrPlotObjSetSelect(op, !fl );
if( cmIsFlag(flags,kFocusGrPlFl) != (fl=_cmGrPlotObjIsFocused(op)) )
if( fl )
_cmGrPlotObjSetFocus(op);
}
unsigned cmGrPlotObjStateFlags( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return
(_cmGrPlotObjIsEnabled(op) ? kEnabledGrPlFl : 0)
| (_cmGrPlotObjIsVisible(op) ? kVisibleGrPlFl : 0)
| (_cmGrPlotObjIsFocused(op) ? kFocusGrPlFl : 0)
| (_cmGrPlotObjIsSelected(op) ? kSelectGrPlFl : 0);
}
void cmGrPlotObjSetCfgFlags( cmGrPlObjH_t oh, unsigned flags )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->cfgFlags = flags;
}
void cmGrPlotObjClrCfgFlags( cmGrPlObjH_t oh, unsigned flags )
{
unsigned curFlags = cmGrPlotObjCfgFlags(oh);
cmGrPlotObjSetCfgFlags(oh, cmClrFlag(curFlags,flags));
}
void cmGrPlotObjTogCfgFlags( cmGrPlObjH_t oh, unsigned flags )
{
unsigned curFlags = cmGrPlotObjCfgFlags(oh);
cmGrPlotObjSetCfgFlags(oh, cmTogFlag(curFlags,flags));
}
unsigned cmGrPlotObjCfgFlags( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->cfgFlags;
}
cmGrPlRC_t cmGrPlotObjSetPhysExt( cmGrPlObjH_t oh, int loffs, int toffs, int roffs, int boffs )
{
cmGrPlRC_t rc = kOkGrPlRC;
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->loffs = loffs;
op->toffs = toffs;
op->roffs = roffs;
op->boffs = boffs;
return rc;
}
void cmGrPlotObjPhysExt( cmGrPlObjH_t oh, int* loffs, int* toffs, int* roffs, int* boffs )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
if( loffs != NULL )
*loffs = op->loffs;
if( toffs != NULL )
*toffs = op->toffs;
if( roffs != NULL )
*roffs = op->roffs;
if( boffs != NULL )
*boffs = op->boffs;
}
void cmGrPlotObjVExt( cmGrPlObjH_t oh, cmGrVExt_t* vext )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
_cmGrPlotObjGetVExt(op, vext);
}
void cmGrPlotObjSetFontFamily( cmGrPlObjH_t oh, unsigned id )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->fontId = id;
}
unsigned cmGrPlotObjFontFamily( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->fontId;
}
void cmGrPlotObjSetFontStyle( cmGrPlObjH_t oh, unsigned style )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->fontStyle = style;
}
unsigned cmGrPlotObjFontStyle( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->fontStyle;
}
void cmGrPlotObjSetFontSize( cmGrPlObjH_t oh, unsigned size )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
op->fontSize = size;
}
unsigned cmGrPlotObjFontSize( cmGrPlObjH_t oh )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
return op->fontSize;
}
void cmGrPlotObjSetLineColor( cmGrPlObjH_t oh, cmGrPlStateId_t id, const cmGrColor_t c )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
assert( id < kMaxPlGrId );
op->drawColors[ id ] = c;
}
const cmGrColor_t cmGrPlotObjLineColor( cmGrPlObjH_t oh, cmGrPlStateId_t id )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
assert( id < kMaxPlGrId );
return op->drawColors[id];
}
const cmGrColor_t cmGrPlotObjCurLineColor( cmGrPlObjH_t h )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(h);
return _cmGrPlotColor(op,op->drawColors);
}
void cmGrPlotObjSetFillColor( cmGrPlObjH_t oh, cmGrPlStateId_t id, const cmGrColor_t c )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
assert( id < kMaxPlGrId );
op->fillColors[ id ] = c;
}
const cmGrColor_t cmGrPlotObjFillColor( cmGrPlObjH_t oh, cmGrPlStateId_t id )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh);
assert( id < kMaxPlGrId );
return op->fillColors[id];
}
const cmGrColor_t cmGrPlotObjCurFillColor( cmGrPlObjH_t h )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(h);
return _cmGrPlotColor(op,op->fillColors);
}
void cmGrPlotObjSetCb( cmGrPlObjH_t h, cmGrPlotCbFunc_t func, void* arg )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(h);
op->cbFunc = func;
op->cbArg = arg;
}
cmGrPlotCbFunc_t cmGrPlotObjCbFunc( cmGrPlObjH_t h )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(h);
return op->cbFunc;
}
void* cmGrPlotObjCbArg( cmGrPlObjH_t h )
{
cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(h);
return op->cbArg;
}
void cmGrPlotObjDrawAbove( cmGrPlObjH_t bH, cmGrPlObjH_t aH )
{
cmGrPlotObj_t* bop = _cmGrPlObjHandleToPtr(bH);
cmGrPlotObj_t* aop = _cmGrPlObjHandleToPtr(aH);
cmGrObjDrawAbove(bop->grObjH,aop->grObjH);
}
//------------------------------------------------------------------------------------------------------------------
// Plot Object Manager Functions
//------------------------------------------------------------------------------------------------------------------
cmGrPlRC_t cmGrPlotCreate( cmCtx_t* ctx, cmGrPlH_t* hp )
{
cmGrPlRC_t rc;
if((rc = cmGrPlotDestroy(hp)) != kOkGrPlRC )
return rc;
cmGrPl_t* p = cmMemAllocZ(cmGrPl_t,1);
cmErrSetup(&p->err,&ctx->rpt,"cmGrPlot");
p->ctx = ctx;
hp->h = p;
if( rc != kOkGrPlRC )
_cmGrPlotDestroy(p);
return rc;
}
cmGrPlRC_t cmGrPlotDestroy( cmGrPlH_t* hp )
{
cmGrPlRC_t rc;
if( hp==NULL || cmGrPlotIsValid(*hp) == false )
return kOkGrPlRC;
cmGrPl_t* p = _cmGrPlHandleToPtr(*hp);
if((rc = _cmGrPlotDestroy(p)) != kOkGrPlRC )
return rc;
hp->h = NULL;
return rc;
}
bool cmGrPlotIsValid( cmGrPlH_t h )
{ return h.h != NULL; }
cmGrPlRC_t cmGrPlotClear( cmGrPlH_t h )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
return _cmGrPlotClear(p);
}
cmErr_t* cmGrPlotErr( cmGrPlH_t h )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
return &p->err;
}
cmRpt_t* cmGrPlotRpt( cmGrPlH_t h )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
return p->err.rpt;
}
cmGrPlObjH_t cmGrPlotObjectIdToHandle( cmGrPlH_t h, unsigned id )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
cmGrPlObjH_t oh = cmGrPlObjNullHandle;
cmGrPlotObj_t* op = p->list;
for(; op!=NULL; op=op->next)
if( cmGrObjId(op->grObjH) == id )
{
oh.h = op;
break;
}
return oh;
}
unsigned cmGrPlotObjectCount( cmGrPlH_t h )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
cmGrPlotObj_t* op = p->list;
unsigned n = 0;
for(; op!=NULL; ++n )
op=op->next;
return n;
}
cmGrPlObjH_t cmGrPlotObjectIndexToHandle( cmGrPlH_t h, unsigned index )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
cmGrPlotObj_t* op = p->list;
unsigned i = 0;
cmGrPlObjH_t oh = cmGrPlObjNullHandle;
for(; i<index && op!=NULL; ++i)
op = op->next;
if( op != NULL )
oh.h = op;
return oh;
}
void cmGrPlotKeyEvent( cmGrPlH_t h, cmGrH_t grH, unsigned eventFlags, cmGrKeyCodeId_t keycode )
{
assert( cmIsFlag(eventFlags,kKeyDnGrFl | kKeyUpGrFl));
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
if( p->fop != NULL && cmHandlesAreEqual(p->fop->grH,grH) )
{
cmGrObjFuncArgs_t a;
memset(&a,0,sizeof(a));
a.cbArg = p->fop;
a.ctx = p->ctx;
a.grH = grH;
a.objH = p->fop->grObjH;
_cmGrPlotObjEvent(&a, eventFlags, keycode, 0, 0 );
}
}
void cmGrPlotSetCb( cmGrPlH_t h, cmGrPlotCbFunc_t func, void* arg )
{
cmGrPl_t* p = _cmGrPlHandleToPtr(h);
p->cbFunc = func;
p->cbArg = arg;
}