libcm/cmGrDevCtx.c
kevin 9a65b1bbaa cmGrDevCtx.c Added _cmGrDcOffs() macros.
This change is goes with cmGrFltk.cpp calls to cmGrDevCtxResize() which
now set the location as well as the size of the device context.
2013-02-08 23:44:56 -08:00

572 rindas
15 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"
#define _cmGrDcOffsX(p,xx) (xx) // ((p)->pext.loc.x + (xx))
#define _cmGrDcOffsY(p,yy) (yy) // ((p)->pext.loc.y + (yy))
cmGrDcH_t cmGrDcNullHandle = cmSTATIC_NULL_HANDLE;
// cmGrDcRecd is used to store the state of the
// device context on the cmGrDC_t stack.
typedef struct cmGrDcRecd_str
{
cmGrColor_t color;
unsigned fontId;
unsigned fontStyle;
unsigned fontSize;
unsigned penWidth;
unsigned penStyle;
struct cmGrDcRecd_str* next;
struct cmGrDcRecd_str* prev;
} cmGrDcRecd_t;
typedef struct cmGrDc_str
{
cmErr_t err;
cmGrDev_t* dd; // device driver used by this context
void* ddArg; // user assigned device driver callback arg
cmGrDcRecd_t* list; // First recd on the stack (not the top).
cmGrDcRecd_t* cur; // Top recd on the stack.
cmGrPExt_t pext; // x,y is offset added to all drawing coordinates
// w,h is size of drawing area
} cmGrDc_t;
// Note: recd's prior to p->cur are available.
// Recd's after p->cur are on the stack.
cmGrDc_t* _cmGrDcHandleToPtr( cmGrDcH_t h )
{
cmGrDc_t* p = (cmGrDc_t*)h.h;
assert( p != NULL );
return p;
}
void _cmGrDcRecdPrint( const cmChar_t* label, const cmGrDcRecd_t* r )
{
printf("%s r:%i g:%i b:%i fid:%i fs:0x%x fsz:%i pw:%i ps:0x%x\n",
cmStringNullGuard(label),
cmGrColorToR(r->color),cmGrColorToG(r->color),cmGrColorToB(r->color),
r->fontId,r->fontStyle,r->fontSize,r->penWidth,r->penStyle);
}
// Make a duplicate of the current record (if it exists)
// and insert it prior to the current record.
// make the new record current.
void _cmGrDcPush( cmGrDc_t* p )
{
if( p->cur == NULL )
{
assert( p->list == NULL );
cmGrDcRecd_t* r = cmMemAllocZ( cmGrDcRecd_t, 1);
p->dd->get_color( p->ddArg, &r->color );
r->fontId = p->dd->get_font_family(p->ddArg );
r->fontSize = p->dd->get_font_size( p->ddArg );
r->fontStyle = p->dd->get_font_style( p->ddArg );
r->penWidth = p->dd->get_pen_width( p->ddArg );
r->penStyle = p->dd->get_pen_style( p->ddArg );
p->list = r;
p->cur = r;
}
else
{
cmGrDcRecd_t* r = p->cur->prev;
// if no prev recd exists ...
if( r == NULL )
{
// .... then allocate one
r = cmMemAllocZ( cmGrDcRecd_t, 1 );
*r = *p->cur;
p->cur->prev = r;
r->next = p->cur;
}
else
{
// ... otherwise use the prev one
cmGrDcRecd_t* nrp = r->next;
cmGrDcRecd_t* prp = r->prev;
*r = *p->cur;
r->next = nrp;
r->prev = prp;
}
// make the new recd the cur recd
p->cur = r;
// if the new recd is the first on the list
// then update the list begin pointer
if( p->cur->prev == NULL )
p->list = p->cur;
}
//_cmGrDcRecdPrint("push:", p->cur );
}
cmGrDcRC_t _cmGrDcPop(cmGrDc_t* p )
{
if( p->cur==NULL || p->cur->next == NULL )
return cmErrMsg(&p->err,kStackFaultGrDcRC,"Cannot pop the last context record off the stack.");
p->cur = p->cur->next;
p->dd->set_color( p->ddArg, p->cur->color );
p->dd->set_font_family( p->ddArg, p->cur->fontId );
p->dd->set_font_size( p->ddArg, p->cur->fontSize );
p->dd->set_font_style( p->ddArg, p->cur->fontStyle );
p->dd->set_pen_width( p->ddArg, p->cur->penWidth );
p->dd->set_pen_style( p->ddArg, p->cur->penStyle );
//_cmGrDcRecdPrint("pop:", p->cur );
return kOkGrDcRC;
}
cmGrDcRC_t _cmGrDcDestroy( cmGrDc_t* p )
{
cmGrDcRecd_t* rp = p->list;
while( rp!=NULL )
{
cmGrDcRecd_t* tp = rp->next;
cmMemFree( rp );
rp = tp;
}
p->dd->destroy(p->ddArg);
cmMemFree(p);
return kOkGrDcRC;
}
cmGrDcRC_t cmGrDevCtxCreate( cmCtx_t* ctx, cmGrDcH_t* hp, cmGrDev_t* dd, void* ddArg, int x, int y, int w, int h )
{
cmGrDcRC_t rc;
if((rc = cmGrDevCtxDestroy(hp)) != kOkGrDcRC )
return rc;
cmGrDc_t* p = cmMemAllocZ(cmGrDc_t,1);
cmErrSetup(&p->err,&ctx->rpt,"cmGrDevCtx");
p->dd = dd;
p->ddArg = ddArg;
cmGrPExtSet(&p->pext,x,y,w,h);
if( dd->create(ddArg,w,h) == false )
{
cmErrMsg(&p->err,kDevDrvFailGrDcRC,"Device driver create failed.");
goto errLabel;
}
_cmGrDcPush(p); // create the default context
hp->h = p;
errLabel:
if(rc != kOkGrDcRC )
_cmGrDcDestroy(p);
return rc;
}
cmGrDcRC_t cmGrDevCtxDestroy( cmGrDcH_t* hp )
{
cmGrDcRC_t rc;
if( hp==NULL || cmGrDevCtxIsValid(*hp)==false )
return kOkGrDcRC;
cmGrDc_t* p = _cmGrDcHandleToPtr(*hp);
if((rc = _cmGrDcDestroy(p)) != kOkGrDcRC )
return rc;
hp->h = NULL;
return rc;
}
bool cmGrDevCtxIsValid( cmGrDcH_t h )
{ return h.h != NULL; }
cmGrDcRC_t cmGrDevCtxResize( cmGrDcH_t h, int x, int y, int ww, int hh )
{
cmGrDcRC_t rc = kOkGrDcRC;
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
// store the current drawing context state
_cmGrDcPush(p);
if( p->dd->create(p->ddArg,ww,hh) == false )
{
cmErrMsg(&p->err,kDevDrvFailGrDcRC,"Device driver create failed on resize.");
goto errLabel;
}
cmGrPExtSet(&p->pext,x,y,ww,hh);
errLabel:
// force the current state to be reapplied to the new drawing context
_cmGrDcPop(p);
return rc;
}
void cmGrDevCtxSize( cmGrDcH_t h, cmGrPExt_t* pext )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
*pext = p->pext;
pext->loc.x *= -1;
pext->loc.y *= -1;
}
void cmGrDevCtxBeginDraw( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->begin_draw( p->ddArg );
}
void cmGrDevCtxEndDraw( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->end_draw( p->ddArg );
}
void cmGrDevCtxDraw( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw( p->ddArg, -p->pext.loc.x, -p->pext.loc.y );
}
void cmGrDcPushCtx( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
_cmGrDcPush(p);
}
void cmGrDcPopCtx( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
_cmGrDcPop(p);
}
unsigned cmGrDcColor( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->color;
}
void cmGrDcSetColorRgb( cmGrDcH_t h, unsigned char r, unsigned char g, unsigned char b )
{
cmGrDcSetColor(h,cmGrRgbToColor(r,g,b));
}
void cmGrDcSetColor( cmGrDcH_t h, cmGrColor_t color )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->set_color( p->ddArg, color );
}
unsigned cmGrDcFontFamily( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->fontId;
}
void cmGrDcSetFontFamily( cmGrDcH_t h, unsigned fontId )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->cur->fontId = fontId;
p->dd->set_font_family( p->ddArg, fontId );
}
unsigned cmGrDcFontStyle( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->fontStyle;
}
void cmGrDcSetFontStyle( cmGrDcH_t h, unsigned style )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->cur->fontStyle = style;
p->dd->set_font_style( p->ddArg, style );
}
unsigned cmGrDcFontSize( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->fontSize;
}
void cmGrDcSetFontSize( cmGrDcH_t h, unsigned size )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->cur->fontSize = size;
p->dd->set_font_size( p->ddArg, size );
}
unsigned cmGrDcPenWidth( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->penWidth;
}
void cmGrDcSetPenWidth( cmGrDcH_t h, unsigned width )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->cur->penWidth = width;
p->dd->set_pen_width( p->ddArg, width );
}
unsigned cmGrDcPenStyle( cmGrDcH_t h )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return p->cur->penStyle;
}
void cmGrDcSetPenStyle( cmGrDcH_t h, unsigned style )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->cur->penStyle = style;
p->dd->set_pen_style( p->ddArg, style );
}
void cmGrDcDrawLine( cmGrDcH_t h, int x0, int y0, int x1, int y1 )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_line( p->ddArg, _cmGrDcOffsX(p,x0), _cmGrDcOffsY(p,y0), _cmGrDcOffsX(p,x1), _cmGrDcOffsY(p,y1) );
}
void cmGrDcDrawRect( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_rect( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcDrawRectPExt( cmGrDcH_t h, const cmGrPExt_t* pext )
{ cmGrDcDrawRect( h, cmGrPExtL(pext), cmGrPExtT(pext), cmGrPExtW(pext), cmGrPExtH(pext) ); }
void cmGrDcFillRect( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->fill_rect( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcDrawEllipse( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_ellipse( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcFillEllipse( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->fill_ellipse( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcDrawDiamond( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_diamond( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcFillDiamond( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->fill_diamond( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh );
}
void cmGrDcDrawTriangle( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh, unsigned dirFlag )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_triangle( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh, dirFlag );
}
void cmGrDcFillTriangle( cmGrDcH_t h, int x, int y, unsigned ww, unsigned hh, unsigned dirFlag )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->fill_triangle( p->ddArg, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), ww, hh, dirFlag );
}
void cmGrDcMeasure( cmGrDcH_t h, const cmChar_t* text, cmGrPSz_t* sz )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
if( text == NULL )
cmGrPSzSet(sz,0,0);
else
{
unsigned ww,hh;
p->dd->measure_text( p->ddArg, text, &ww, &hh );
sz->w = ww;
sz->h = hh;
}
}
void cmGrDcDrawText( cmGrDcH_t h, const cmChar_t* text, int x, int y )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_text( p->ddArg, text, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y) );
}
void cmGrDcDrawTextRot( cmGrDcH_t h, const cmChar_t* text, int x, int y, int angle )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_text_rot( p->ddArg, text, _cmGrDcOffsX(p,x), _cmGrDcOffsY(p,y), angle );
}
void cmGrDcReadImage( cmGrDcH_t h, unsigned char* a, const cmGrPExt_t* pext )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->read_image( p->ddArg, a, _cmGrDcOffsX(p,pext->loc.x), _cmGrDcOffsY(p,pext->loc.y), pext->sz.w, pext->sz.h );
}
void cmGrDcDrawImage( cmGrDcH_t h, const unsigned char* a, const cmGrPExt_t* pext )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
p->dd->draw_image( p->ddArg, a, _cmGrDcOffsX(p,pext->loc.x), _cmGrDcOffsY(p,pext->loc.y), pext->sz.w, pext->sz.h );
}
void cmGrDcSetFont( cmGrDcH_t h, unsigned fontId, unsigned size, unsigned style )
{
cmGrDcSetFontFamily(h,fontId);
cmGrDcSetFontSize( h,size);
cmGrDcSetFontStyle( h,style);
}
void cmGrDcFontSetAndMeasure(cmGrDcH_t h, unsigned fontId, unsigned size, unsigned style, const cmChar_t* text, cmGrPSz_t* sz )
{
cmGrDcSetFont(h,fontId,size,style);
cmGrDcMeasure(h,text,sz);
}
void cmGrDcDrawTextJustify( cmGrDcH_t h, unsigned fontId, unsigned size, unsigned style, const cmChar_t* text, const cmGrPExt_t* pext, unsigned flags )
{
int x = cmGrPExtCtrX(pext);
int y = cmGrPExtCtrY(pext);
if( cmIsFlag(flags,kNorthJsGrFl) )
y = cmGrPExtT(pext);
else
if( cmIsFlag(flags,kSouthJsGrFl) )
y = cmGrPExtB(pext);
if( cmIsFlag(flags,kEastJsGrFl) )
x = cmGrPExtR(pext);
else
if( cmIsFlag(flags,kWestJsGrFl) )
x = cmGrPExtL(pext);
cmGrDcDrawTextJustifyPt(h,fontId,size,style,text,flags,x,y);
}
void cmGrDcDrawTextJustifyPt( cmGrDcH_t h, unsigned fontId, unsigned size, unsigned style, const cmChar_t* text, unsigned flags, int xx, int yy )
{
cmGrPSz_t sz;
cmGrDcFontSetAndMeasure(h, fontId, size, style, text, &sz );
int x,y;
if( cmIsFlag(flags,kRightJsGrFl) )
x = xx;
else
if( cmIsFlag(flags,kLeftJsGrFl) )
x = xx - sz.w;
else
x = xx - sz.w/2;
if( cmIsFlag(flags,kBottomJsGrFl) )
y = yy;
else
if( cmIsFlag(flags,kTopJsGrFl) )
y = yy + sz.h;
else
y = yy + sz.h/2;
cmGrPExt_t r;
cmGrPExtSet(&r,x,y,sz.w,sz.h);
// Note: Checking for visibility should not be necessary however
// there appears to be a problem with the FLTK text output whereby
// text coordinates over 0xffff wrap around and may appear in the
// visible region.
if( cmGrDcRectIsVisible(h,&r) )
{
/*
if( text!=NULL && (strncmp(text,"loc:138",7)==0 || strcmp(text,"loc:8 ")==0))
{
printf("%s %i %i %i %i\n",text,x,y,sz.w,xx);
cmGrPExtPrint(text,&r);
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
cmGrPExt_t res;
cmGrPExtIntersect(&res,&p->pext,&r );
cmGrPExtPrint(text,&p->pext);
cmGrPExtPrint("isect:",&res);
printf("%i\n",cmGrPExtIsNotNullOrEmpty(&res));
}
*/
cmGrDcDrawText(h, text, x+.5, y+.5 );
}
//cmGrPExt_t pext;
//cmGrDcDrawTextJustifyRect(h, fontId, size, style, text, flags, xx, yy, &pext );
//cmGrDcDrawRectPExt(h,&pext);
}
void cmGrDcDrawTextJustifyRect( cmGrDcH_t h, unsigned fontId, unsigned size, unsigned style, const cmChar_t* text, unsigned flags, int xx, int yy, cmGrPExt_t* pext )
{
cmGrPSz_t sz;
cmGrDcFontSetAndMeasure(h, fontId, size, style, text, &sz );
int x,y;
if( cmIsFlag(flags,kRightJsGrFl) )
x = xx;
else
if( cmIsFlag(flags,kLeftJsGrFl) )
x = xx - sz.w;
else
x = xx - sz.w/2;
if( cmIsFlag(flags,kBottomJsGrFl) )
y = yy;
else
if( cmIsFlag(flags,kTopJsGrFl) )
y = yy + sz.h;
else
y = yy + sz.h/2;
cmGrPExtSet( pext, x, y-sz.h, sz.w+1, sz.h );
}
bool cmGrDcPointIsVisible( cmGrDcH_t h, int x, int y )
{
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
return cmGrVExtIsXyInside(&p->pext,x,y);
}
bool cmGrDcRectIsVisible( cmGrDcH_t h, const cmGrPExt_t* r )
{
cmGrPExt_t res;
cmGrDc_t* p = _cmGrDcHandleToPtr(h);
cmGrPExtIntersect(&res,&p->pext,r );
return cmGrPExtIsNotNullOrEmpty(&res);
}