From 9d6ac977aa667a3235e7a18068c90c9810c752f4 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 17 Dec 2012 20:54:37 -0800 Subject: [PATCH] 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. --- cmGr.c | 285 +++++++++++++++++++++++++++++++++++++++++------- cmGr.h | 9 +- cmGrPlot.c | 44 +++++++- cmGrPlot.h | 1 + cmGrPlotAudio.c | 2 +- 5 files changed, 295 insertions(+), 46 deletions(-) diff --git a/cmGr.c b/cmGr.c index c71a11e..668cbae 100644 --- a/cmGr.c +++ b/cmGr.c @@ -684,7 +684,7 @@ void _cmGrObjCbVExt( cmGr_t* p, const cmGrObj_t* op, cmGrVExt_t* vext ) } } -bool _cmGrObjCbIsInside( cmGr_t* p, const cmGrObj_t* op, int px, int py, cmGrV_t vx, cmGrV_t vy ) +bool _cmGrObjCbIsInside( cmGr_t* p, const cmGrObj_t* op, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy ) { bool fl = false; if( op->f.isInsideCbFunc != NULL ) @@ -692,7 +692,7 @@ bool _cmGrObjCbIsInside( cmGr_t* p, const cmGrObj_t* op, int px, int py, cmGrV_t cmGrObjFuncArgs_t a; _cmGrObjSetupFuncArgs(&a,p,(cmGrObj_t*)op); a.cbArg = op->f.isInsideCbArg; - fl = op->f.isInsideCbFunc(&a,px,py,vx,vy); + fl = op->f.isInsideCbFunc(&a,evtFlags,px,py,vx,vy); } return fl; } @@ -1751,7 +1751,7 @@ void _cmGrObjRootVExt( cmGrObjFuncArgs_t* args, cmGrVExt_t* vext ) cmGrObjWorldExt( args->objH, vext ); } -bool _cmGrObjRootIsInside( cmGrObjFuncArgs_t* args, int px, int py, cmGrV_t vx, cmGrV_t vy ) +bool _cmGrObjRootIsInside( cmGrObjFuncArgs_t* args, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy ) { cmGrVExt_t vext; _cmGrObjRootVExt(args,&vext); @@ -2154,8 +2154,38 @@ void _cmGrSetSelectPoints(cmGr_t* p, const cmGrVPt_t* pt0, const cmGrVPt_t* pt1 } +void _cmGrScrollExtents( cmGr_t* p, cmGrPSz_t* tot, cmGrPSz_t* vis, cmGrPSz_t* max, cmGrPPt_t* pos ) +{ + + assert( p->rootObj != NULL ); + + if( tot != NULL ) + { + tot->w = round(p->rootObj->wext.sz.w * p->pext.sz.w / p->vext.sz.w); + tot->h = round(p->rootObj->wext.sz.h * p->pext.sz.h / p->vext.sz.h); + } + + if( vis != NULL ) + { + vis->w = round(p->vext.sz.w * p->pext.sz.w / p->vext.sz.w); + vis->h = round(p->vext.sz.h * p->pext.sz.h / p->vext.sz.h); + } + + if( max != NULL ) + { + max->w = tot->w - vis->w; + max->h = tot->h - vis->h; + } + + if( pos != NULL ) + { + pos->x = _cmGrScrollH(p); + pos->y = _cmGrScrollV(p); + } +} + // vx,vy are in the same coord's as op->vext -cmGrObj_t* _cmGrFindObjRec( cmGr_t* p, cmGrObj_t* op, int px, int py, cmGrV_t vx, cmGrV_t vy ) +cmGrObj_t* _cmGrFindObjRec( cmGr_t* p, cmGrObj_t* op, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy ) { cmGrObj_t* rop = NULL; cmGrObj_t* top; @@ -2165,27 +2195,234 @@ cmGrObj_t* _cmGrFindObjRec( cmGr_t* p, cmGrObj_t* op, int px, int py, cmGrV_t vx _cmGrObjCbVExt(p,op,&vext); // is vx,vy inside op - this is equiv to: cmGrVExtIsXyInside(&vext,vx,vy) - if( _cmGrObjCbIsInside(p,op,px,py,vx,vy) ) + if( _cmGrObjCbIsInside(p,op,evtFlags,px,py,vx,vy) ) rop = op; if( op->children != NULL ) { cmGrVPt_t pt; if( _cmGrParentToLocal(p,op,vx,vy,&pt) ) - if((top = _cmGrFindObjRec(p,op->children,px,py,vx,vy)) != NULL ) + if((top = _cmGrFindObjRec(p,op->children,evtFlags,px,py,vx,vy)) != NULL ) rop = top; } if( op->rsib != NULL ) - if((top = _cmGrFindObjRec(p,op->rsib,px,py,vx,vy)) != NULL ) + if((top = _cmGrFindObjRec(p,op->rsib,evtFlags,px,py,vx,vy)) != NULL ) rop = top; return rop; } +cmGrObj_t* _cmGrEventMsDown( cmGr_t* p, unsigned evtFlags, cmGrKeyCodeId_t key, int px, int py, cmGrV_t gx, cmGrV_t gy ) +{ + // store the phys loc. of the ms dn event + cmGrPPtSet(&p->msDnPPt,px,py); -bool cmGrEvent( cmGrH_t h, unsigned flags, cmGrKeyCodeId_t key, int px, int py ) + // get a pointer to an object + cmGrObj_t* op = _cmGrFindObjRec(p, p->rootObj, evtFlags, px, py, gx, gy ); + + // if the mouse did not go down in an object that accepts mouse down events + // or the object was a root object + if( op == NULL || op->parent == NULL ) + return NULL; + + // store the object and coord's where the mouse went down. + cmGrVExt_t vext; + p->msDnObj = op; // set the msDnObj + + // convert the phys ms dn point to the virt point inside op->parent.wext + _cmGrXY_PtoV(p, op->parent, px, py, &p->msDnVPt ); + + p->msVPt = p->msDnVPt; // set the current ms virt pt + p->localPt = p->msDnVPt; // set the current local pt + + // notifiy the app of the local coord's + _cmGrCallback(p,kLocalPtCbGrId,0,kInvalidKeyCodeGrId); + + // get the ms down obj virt extents + _cmGrObjCbVExt(p,op,&vext); + + // store the offset from the lower left to the ms dn point + p->msDnVOffs.w = p->msDnVPt.x - vext.loc.x; + p->msDnVOffs.h = p->msDnVPt.y - vext.loc.y; + + // notify the object that the mouse went down + if(_cmGrObjCbEvent(p,op,evtFlags,key,px,py)) + return op; + return NULL; +} + +cmGrObj_t* _cmGrEventMsUp( cmGr_t* p, unsigned evtFlags, cmGrKeyCodeId_t key, int px, int py, cmGrV_t gx, cmGrV_t gy ) +{ + bool fl = false; + cmGrObj_t* op = NULL; + + cmGrPPt_t upPPt; + cmGrPPtSet(&upPPt,px,py); + + // if a click occured ... + if( cmGrPPtIsEqual(&p->msDnPPt,&upPPt ) ) + { + // ... and the click is in a non-root object which accepts click events ... + if( p->msDnObj!= NULL && p->msDnObj->parent!=NULL && _cmGrObjCbIsInside(p,p->msDnObj,evtFlags | kMsClickGrFl, px, py, gx, gy) ) + { + // ... then generate a click event + unsigned newEvtFlags = cmClrFlag(evtFlags,kMsUpGrFl) | kMsClickGrFl; + fl = _cmGrObjCbEvent(p,p->msDnObj,newEvtFlags,key,px,py); + op = p->msDnObj; + } + else // ... else if the click occurred in the root object + //if( p->msDnObj==NULL || p->msDnObj->parent==NULL) + { + cmGrVPt_t pt; + cmGrVPtSet(&pt,gx,gy); + + bool shFl = cmIsFlag(evtFlags,kShiftKeyGrFl); + _cmGrSetSelectPoints( p, shFl ? NULL : &pt, shFl ? &pt : NULL ); + + } + } + + // if op is NULL then there was no-mouse down object to match with + // this mouse-up event - find an object to match with the mouse-up event + if( op == NULL ) + op = _cmGrFindObjRec(p, p->rootObj, evtFlags, px, py, gx, gy ); + + // if a mouse-up object was found then + if( op != NULL && op->parent != NULL) + { + + // notify the object under the mouse that the mouse went up + if( _cmGrObjCbEvent(p,op,evtFlags,key,px,py) ) + fl = true; + + // convert the phys ms dn point to the virt point inside op->parent.wext + _cmGrXY_PtoV(p, op->parent, px, py, &p->msVPt ); + + } + + _cmGrCallback(p,kFocusCbGrId,0,kInvalidKeyCodeGrId); + + p->msDnObj = NULL; + + return fl ? op : NULL; +} + +cmGrObj_t* _cmGrEventMsMove( cmGr_t* p, unsigned evtFlags, cmGrKeyCodeId_t key, int px, int py, cmGrV_t gx, cmGrV_t gy ) +{ + bool fl = false; + cmGrObj_t* op = _cmGrFindObjRec(p, p->rootObj, evtFlags, px, py, gx, gy ); + + if( op != NULL && op->parent != NULL ) + { + + fl = _cmGrObjCbEvent(p,op,evtFlags,key,px,py); + } + + return fl ? op : NULL; +} + +cmGrObj_t* _cmGrEventMsDrag( cmGr_t* p, unsigned evtFlags, cmGrKeyCodeId_t key, int px, int py, cmGrV_t gx, cmGrV_t gy ) +{ + bool fl = false; + cmGrObj_t* op = _cmGrFindObjRec(p, p->rootObj, evtFlags, px, py, gx, gy ); + + if( op != NULL && op->parent != NULL ) + { + // set the current virtual point + _cmGrXY_PtoV(p, p->msDnObj->parent, px, py, &p->msVPt ); + + // callback the dragged object + fl = _cmGrObjCbEvent(p,p->msDnObj,evtFlags,key,px,py); + + // if the px,py is outside the root phys extents then scroll + if( !cmGrPExtIsXyInside(&p->pext,px,py) ) + { + bool hFl = false, vFl=false; + cmGrPSz_t tot,vis,max; + cmGrPPt_t pos; + _cmGrScrollExtents(p, &tot, &vis, &max, &pos ); + + if( px < cmGrPExtL(&p->pext) ) + hFl = _cmGrSetScrollH(p, cmMax(0, _cmGrScrollH(p) - (cmGrPExtL(&p->pext) - px))); + else + if( px > cmGrPExtR(&p->pext) ) + hFl = _cmGrSetScrollH(p, cmMin(max.w, _cmGrScrollH(p) + (px - cmGrPExtR(&p->pext)))); + + if( py < cmGrPExtT(&p->pext) ) + vFl = _cmGrSetScrollV(p, cmMax(0, _cmGrScrollV(p) - (cmGrPExtT(&p->pext) - py))); + else + if( py > cmGrPExtB(&p->pext) ) + vFl = _cmGrSetScrollV(p, cmMin(max.h, _cmGrScrollV(p) + (py - cmGrPExtB(&p->pext)))); + + + fl = fl || vFl || hFl; + } + } + return fl ? op : NULL; +} + +bool cmGrEvent( cmGrH_t h, unsigned evtFlags, cmGrKeyCodeId_t key, int px, int py ) +{ + bool fl = false; + cmGrObj_t* op = NULL; + cmGr_t* p = _cmGrHandleToPtr(h); + cmGrVPtSet(&p->localPt,0,0); + + // convert the phys points to points in the root coord system + cmGrV_t gx = _cmGr_X_PtoV(p,px); + cmGrV_t gy = _cmGr_Y_PtoV(p,py); + + // set the global point + cmGrVPtSet(&p->globalPt,gx,gy); + + // inform the app of the possibly new global point + _cmGrCallback(p,kGlobalPtCbGrId,0,kInvalidKeyCodeGrId); + + switch( evtFlags & kEvtMask) + { + case kKeyUpGrFl: + _cmGrCallback(p,kKeyUpCbGrId,evtFlags,key); + break; + + case kKeyDnGrFl: + _cmGrCallback(p,kKeyDnCbGrId,evtFlags,key); + break; + + case kMsDownGrFl: + op = _cmGrEventMsDown(p,evtFlags,key,px,py,gx,gy); + break; + + case kMsUpGrFl: // handle mouse-up, mouse-click, and focus events + op = _cmGrEventMsUp(p,evtFlags,key,px,py,gx,gy); + break; + + case kMsMoveGrFl: + op = _cmGrEventMsMove(p,evtFlags,key,px,py,gx,gy); + break; + + case kMsDragGrFl: + op = _cmGrEventMsDrag(p,evtFlags,key,px,py,gx,gy); + break; + + } + + if( op != NULL ) + { + // convert gx,gy to be inside op->wext + cmGrVPtSet(&p->localPt,gx,gy); + _cmGrXY_GlobalToLocal(p,op,&p->localPt); + + _cmGrCallback(p,kLocalPtCbGrId,0,kInvalidKeyCodeGrId); + + fl = true; + } + + return fl; +} + +bool cmGrEvent1( cmGrH_t h, unsigned flags, cmGrKeyCodeId_t key, int px, int py ) { bool fl = false; cmGr_t* p = _cmGrHandleToPtr(h); @@ -2201,7 +2438,7 @@ bool cmGrEvent( cmGrH_t h, unsigned flags, cmGrKeyCodeId_t key, int px, int _cmGrCallback(p,kGlobalPtCbGrId,0,kInvalidKeyCodeGrId); // find the obj under the mouse - if((op = _cmGrFindObjRec(p,p->rootObj,px,py,gx,gy)) != NULL ) + if((op = _cmGrFindObjRec(p,p->rootObj,flags&kEvtMask,px,py,gx,gy)) != NULL ) { // convert gx,gy to be inside op->wext cmGrVPtSet(&p->localPt,gx,gy); @@ -2414,39 +2651,13 @@ void cmGrPhysExtents( cmGrH_t h, cmGrPExt_t* exts ) cmGr_t* p = _cmGrHandleToPtr(h); *exts = p->pext; } - - void cmGrScrollExtents( cmGrH_t h, cmGrPSz_t* tot, cmGrPSz_t* vis, cmGrPSz_t* max, cmGrPPt_t* pos ) { cmGr_t* p = _cmGrHandleToPtr(h); - - assert( p->rootObj != NULL ); - - if( tot != NULL ) - { - tot->w = round(p->rootObj->wext.sz.w * p->pext.sz.w / p->vext.sz.w); - tot->h = round(p->rootObj->wext.sz.h * p->pext.sz.h / p->vext.sz.h); - } - - if( vis != NULL ) - { - vis->w = round(p->vext.sz.w * p->pext.sz.w / p->vext.sz.w); - vis->h = round(p->vext.sz.h * p->pext.sz.h / p->vext.sz.h); - } - - if( max != NULL ) - { - max->w = tot->w - vis->w; - max->h = tot->h - vis->h; - } - - if( pos != NULL ) - { - pos->x = _cmGrScrollH(p); - pos->y = _cmGrScrollV(p); - } + _cmGrScrollExtents(p,tot,vis,max,pos); } + bool cmGrSetScrollH( cmGrH_t h, int x ) { return _cmGrSetScrollH( _cmGrHandleToPtr(h), x ); } diff --git a/cmGr.h b/cmGr.h index f8bd415..cf12087 100644 --- a/cmGr.h +++ b/cmGr.h @@ -595,7 +595,7 @@ extern "C" { typedef int (*cmGrDistanceObjCb_t)( cmGrObjFuncArgs_t* args, int x, int y ); typedef bool (*cmGrEventObjCb_t)( cmGrObjFuncArgs_t* args, unsigned flags, unsigned key, int px, int py ); typedef void (*cmGrVExtObjCb_t)( cmGrObjFuncArgs_t* args, cmGrVExt_t* vext ); - typedef bool (*cmGrIsInsideObjCb_t)( cmGrObjFuncArgs_t* args, int px, int py, cmGrV_t vx, cmGrV_t vy ); + typedef bool (*cmGrIsInsideObjCb_t)( cmGrObjFuncArgs_t* args, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy ); typedef struct cmGrObjFunc_str { @@ -625,9 +625,12 @@ extern "C" { cmGrVExtObjCb_t vextCbFunc; void* vextCbArg; - // Return true if the point is inside this obj. vx,vy is in the the same coord's as op->vext (i.e. vx,vy is inside op->parent->wext) + // Called to determine which object is under the mouse and whether the event can + // handle the event as described by the 'evtFlags' args. + // Return true if the point is inside this obj. vx,vy is in the the same coord's + // as op->vext (i.e. vx,vy is inside op->parent->wext) and the object will accept + // the event implied by the 'evtFlags' argument. // The simple answer to this call is cmGrVExtIsXyInside( *vext, vx, vy ). - // Called to determine which object is under the mouse. cmGrIsInsideObjCb_t isInsideCbFunc; void* isInsideCbArg; } cmGrObjFunc_t; diff --git a/cmGrPlot.c b/cmGrPlot.c index 158a01b..a50a471 100644 --- a/cmGrPlot.c +++ b/cmGrPlot.c @@ -678,13 +678,43 @@ bool _cmGrPlotObjEvent( cmGrObjFuncArgs_t* args, unsigned flags, unsigned key, i return fl; } +bool _cmGrPlotObjIsBorderClick( const cmGrPExt_t* pext, int px, int py ) +{ + int dist = 3; -bool _cmGrPlotObjIsInside( cmGrObjFuncArgs_t* args, int px, int py, cmGrV_t vx, cmGrV_t vy ) + 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 ); @@ -698,6 +728,10 @@ bool _cmGrPlotObjIsInside( cmGrObjFuncArgs_t* args, int px, int py, cmGrV_t vx, 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); } @@ -791,11 +825,11 @@ cmGrPlRC_t cmGrPlotObjCreate( // set the default colors - op->drawColors[kFocusPlGrId] = 0xcd853f; - op->fillColors[kFocusPlGrId] = 0xdeb887; + op->drawColors[kSelectPlGrId] = 0xcd853f; + op->fillColors[kSelectPlGrId] = 0xdeb887; - op->drawColors[kSelectPlGrId] = 0x483d8b; - op->fillColors[kSelectPlGrId] = 0x8470ff; + op->drawColors[kFocusPlGrId] = 0x483d8b; + op->fillColors[kFocusPlGrId] = 0x8470ff; op->drawColors[kEnablePlGrId] = 0x000000; op->fillColors[kEnablePlGrId] = 0x009ff7; diff --git a/cmGrPlot.h b/cmGrPlot.h index 0ed21aa..a7eb762 100644 --- a/cmGrPlot.h +++ b/cmGrPlot.h @@ -43,6 +43,7 @@ extern "C" { kNoFillGrPlFl = 0x0020, // Do not draw the fill area of this object kNoBorderGrPlFl = 0x0040, // Do not draw the border of this object kNoLabelGrPlFl = 0x0080, // Do not draw the label for this object + kBorderSelGrPlFl= 0x0100, // This object is selected by clicking near it's border }; // object state flags diff --git a/cmGrPlotAudio.c b/cmGrPlotAudio.c index b7f0491..48d02f4 100644 --- a/cmGrPlotAudio.c +++ b/cmGrPlotAudio.c @@ -131,7 +131,7 @@ bool _cmGrPlObjAfRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH ) return true; } -bool _cmGrPlObjAfIsInside( cmGrObjFuncArgs_t* args, int px, int py, cmGrV_t vx, cmGrV_t vy ) +bool _cmGrPlObjAfIsInside( cmGrObjFuncArgs_t* args, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy ) { cmGrPlObjAf_t* op = (cmGrPlObjAf_t*)args->cbArg;