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;