/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
/* PROC LEGEND - Render an automatic legend. Plotting procs supply legend entries */
#include "pl.h"
#define MAXLEGENT 80 /* max # of legend entries */
#define MAXLEGTEXT 2000 /* max amount of legend text, including labels
and details attributes */
#define DOWN 0
#define ACROSS 1
extern int PLG_init_bb2(), PLG_get_bb2();
static int NLE = 0;
static int LEavail = 0;
static int LEtype[MAXLEGENT];
static int LEparm1[MAXLEGENT];
static int LEparm2[MAXLEGENT];
static int LEparm3[MAXLEGENT];
static int LElabel[MAXLEGENT];
static int LEtag[MAXLEGENT];
static char Ltext[MAXLEGTEXT];
/* ================================ */
int
PLP_legend_initstatic()
{
NLE = 0;
LEavail = 0;
return(0);
}
/* ================================ */
int
PLP_legend()
{
int i;
char attr[NAMEMAXLEN], val[256];
char *line, *lineval;
int nt, lvp;
int first;
int align;
double adjx, adjy;
char buf[256];
double x, y;
char format;
int outline;
int nlines, maxlen;
double yy;
char textdetails[256];
int reverseorder;
int j;
double seglen;
double hsep, msep;
int do_outline;
int colortext;
int specifyorder;
int ix, ixx, k;
double swatchsize;
int noclear;
char holdstdcolor[COLORLEN];
char color[COLORLEN];
int buflen;
char url[MAXPATH];
char *s;
char symcode[80];
double radius;
double extent;
double startx, starty;
double sampwidth, colchunksep, colbreak;
double rowchunksep;
int nlinesym, maxtwidth, maxthi;
int wraplen;
double orig_x, orig_y, bx1, by1, bx2, by2;
int dobox, bstate;
char frame[128];
char backcolor[COLORLEN];
double bmx1, bmy1, bmx2, bmy2;
char title[128], titledetails[128];
double titx, tity;
TDH_errprog( "pl proc legend" );
/* initialize */
x = -9999.0;
y = -9999.0;
format = DOWN;
strcpy( textdetails, "" );
reverseorder = 0;
seglen = 0.5;
msep = 0.0;
hsep = 0.3; /* was 1.2; changed scg 8/12/05 */
do_outline = 0;
colortext = 0;
strcpy( PL_bigbuf, "" );
specifyorder = 0;
ix = 0;
swatchsize = 0.1;
noclear = 0;
extent = -1.0;
colchunksep = 0.35;
rowchunksep = 0.1;
nlinesym = 2;
wraplen = 0;
dobox = 0;
strcpy( frame, "no" );
strcpy( backcolor, Ecurbkcolor );
bmx1 = bmy1 = bmx2 = bmy2 = 0.08;
strcpy( title, "" );
strcpy( titledetails, "" );
/* get attributes.. */
first = 1;
while( 1 ) {
line = getnextattr( first, attr, val, &lvp, &nt );
if( line == NULL ) break;
first = 0;
lineval = &line[lvp];
if( stricmp( attr, "location" )==0 ) {
/* note: location x = beginning of LABEL; y = top */
if( lineval[0] != '\0' ) getcoords( "location", lineval, &x, &y );
}
else if( stricmp( attr, "textdetails" )==0 ) strcpy( textdetails, lineval );
else if( stricmp( attr, "seglen" )==0 ) seglen = atof( val );
else if( stricmp( attr, "sep" )==0 ) ; /* superseded by the 'separation' attribute */
else if( stricmp( attr, "separation" )==0 ) {
hsep = atof( val );
msep = atof( val );
if( PLS.usingcm ) { hsep /= 2.54; msep /= 2.54; }
}
else if( stricmp( attr, "colortext" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) colortext = 1;
else colortext = 0;
}
else if( stricmp( attr, "outlinecolors" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) do_outline = 1;
else do_outline = 0;
}
else if( stricmp( attr, "noclear" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) noclear = 1;
else noclear = 0;
}
else if( stricmp( attr, "format" )==0 ) {
format = tolower( val[0] );
if( format == 'd' || format == 'm' ) format = DOWN;
else if( format == 'a' || format == 's' ) format = ACROSS;
}
else if( stricmp( attr, "specifyorder" )==0 ) {
getmultiline( "specifyorder", lineval, MAXBIGBUF, PL_bigbuf );
specifyorder = 1;
}
else if( stricmp( attr, "swatchsize" )==0 ) {
if( val[0] != '\0' ) {
swatchsize = atof( val );
if( PLS.usingcm ) swatchsize /= 2.54;
}
else swatchsize = 0.1;
}
else if( stricmp( attr, "reverseorder" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) reverseorder = 1;
else reverseorder = 0;
}
else if( stricmp( attr, "reset" )==0 ) {
NLE = 0;
return( 0 );
}
/* the following attributes added for 2.32 - scg 8/12/05 ....... */
else if( stricmp( attr, "extent" )==0 ) {
extent = atof( val );
if( PLS.usingcm ) extent /= 2.54;
}
else if( stricmp( attr, "chunksep" )==0 ) { /* additional amount of separation between column chunks or row chunks */
colchunksep = atof( val );
rowchunksep = atof( val );
if( PLS.usingcm ) { colchunksep /= 2.54; rowchunksep /= 2.54; }
}
else if( stricmp( attr, "nlinesym" )== 0 ) { /* 1 2 or 0 */
nlinesym = atoi( val );
if( nlinesym > 2 ) nlinesym = 2;
}
else if( stricmp( attr, "wraplen" )==0 ) wraplen = atoi( val );
else if( stricmp( attr, "frame" )==0 ) {
dobox = 1;
strcpy( frame, lineval );
}
else if( stricmp( attr, "backcolor" )==0 ) {
dobox = 1;
strcpy( backcolor, val );
}
else if( stricmp( attr, "boxmargin" )==0 ) {
char foo1[40], foo2[40];
nt = sscanf( lineval, "%s %s", foo1, foo2 );
if( nt == 1 ) {
if( PLS.usingcm ) bmx1 /= 2.54;
bmy1 = bmx2 = bmy2 = bmx1;
}
else PL_getbox( "boxmargin", lineval, &bmx1, &bmy1, &bmx2, &bmy2 );
}
else if( stricmp( attr, "title" )==0 ) {
dobox = 1;
strcpy( title, lineval );
}
else if( stricmp( attr, "titledetails" )==0 ) strcpy( titledetails, lineval );
else Eerr( 1, "attribute not recognized", attr );
}
if( NLE < 1 ) return( 0 ); /* silent is better here ... scg 5/5/04 */
/*********** now do the plotting work.. **********/
/* box init stuff.. */
if( dobox ) {
bstate = 0;
PLG_init_bb2();
Esquelch( "on" );
}
/* default location */
if( x < -9000.0 ) {
if( scalebeenset() ) { x = EXhi - 1.5; y = EYhi - 0.1; }
else { x = 6.0; y = 2.0; }
}
orig_x = x; orig_y = y;
RENDER:
ix = 0;
buflen = strlen( PL_bigbuf );
startx = x; starty = y;
if( format == DOWN ) {
if( extent < 0.0 ) colbreak = 0.0; /* always at y = 0 */
else colbreak = starty - extent; /* extent was specified.. do it */
}
maxtwidth = 0; /* keep track of the max text width in column */
maxthi = 0; /* keep track of the max text #lines in column (since individual entries can wrap with "\n" */
textdet( "textdetails", textdetails, &align, &adjx, &adjy, -2, "R", 1.0 );
y -= Ecurtextheight;
for( i = 0; i < NLE; i++ ) {
/* fprintf( stderr, "%d|%s|%s|%s\n", LEtype[i], &Ltext[LElabel[i]], &Ltext[LEparm1[i]], &Ltext[LEparm2[i]] ); */
if( specifyorder ) {
/* get next line in orderspec.. */
NEXTORDERLINE:
GL_getchunk( buf, PL_bigbuf, &ix, "\n" );
if( ix >= buflen ) break;
/* now search for matching entry.. */
for( k = 0; k < NLE; k++ ) {
if( strnicmp( buf, &Ltext[LElabel[k]], strlen(buf) )==0) {
j = k;
break;
}
}
if( k == NLE ) {
/* following changed, scg 2/27/02 */
/* Eerr( 2894, "No legend entry matched", buf ); */
goto NEXTORDERLINE;
/* continue; */
}
}
else if( reverseorder ) j = ((NLE-1)-i);
else j = i;
yy = y+(Ecurtextheight*0.4);
/* draw swatch(es), depending on type */
if( LEtype[j] == LEGEND_COLOR ) {
sampwidth = swatchsize+0.1;
if( format == ACROSS && x > startx ) x += sampwidth;
sscanf( &Ltext[LEparm1[j]], "%s", color );
if( strcmp( color, backcolor ) ==0 ) outline = 1;
else outline = do_outline;
if( outline ) { Elinetype( 0, 0.5, 1.0 ); Ecolor( Estandard_color ); }
Ecblock( x-(swatchsize+0.1), y, x-0.1, y+swatchsize, color, outline );
}
else if( LEtype[j] == LEGEND_LINE ) {
sampwidth = seglen+0.1;
if( format == ACROSS && x > startx ) x += sampwidth;
linedet( &Ltext[LElabel[j]], &Ltext[LEparm1[j]], 1.0 );
Emov( x-(seglen+0.1), yy );
Elin( x-0.1, yy );
}
else if( LEtype[j] == LEGEND_LINEMARK ) { /* tiny line marks that can be used in scatterplots */
sampwidth = 0.2;
if( format == ACROSS && x > startx ) x += sampwidth;
linedet( &Ltext[LElabel[j]], &Ltext[LEparm1[j]], 1.0 );
if( strcmp( &Ltext[LEparm2[j]], "v" )==0 ) { Emov( x-0.15, yy+0.05 ); Elin( x-0.15, yy-0.05 ); } /* vertical */
else { Emov( x-0.2, yy ); Elin( x-0.1, yy ); } /* horizontal */
}
else if( LEtype[j] == LEGEND_SYMBOL ) {
symdet( "symbol", &Ltext[LEparm1[j]], symcode, &radius );
sampwidth = 0.17 + radius;
if( format == ACROSS && x > startx ) x += sampwidth;
Emark( x-0.17, yy, symcode, radius );
}
else if( LEtype[j] == LEGEND_TEXT ) {
sampwidth = 0.8; /* just a guess */
if( format == ACROSS && x > startx ) x += sampwidth;
/* parm1 is text, parm2 is textdetails */
textdet( &Ltext[LElabel[j]], &Ltext[LEparm2[j]], &align, &adjx, &adjy, -2, "R", 1.0 );
Emov( x-0.1, y );
Erightjust( &Ltext[LEparm1[j]] );
}
else if( LEtype[j] == (LEGEND_LINE + LEGEND_SYMBOL) ) {
sampwidth = seglen+0.1;
if( format == ACROSS && x > startx ) x += sampwidth;
/* parm1 is linedetails, parm2 is symboldetails */
linedet( &Ltext[LElabel[j]], &Ltext[LEparm1[j]], 1.0 );
Emov( x-(seglen+0.1), yy );
Elin( x-0.1, yy );
symdet( "symbol", &Ltext[LEparm2[j]], symcode, &radius );
if( nlinesym == 1 ) Emark( x-((seglen/2.0)+0.1), yy, symcode, radius );
else if ( nlinesym == 2 ) {
Emark( x-(seglen), yy, symcode, radius );
Emark( x-0.18, yy, symcode, radius );
}
}
else if( LEtype[j] == (LEGEND_TEXT + LEGEND_SYMBOL) ) {
sampwidth = 0.8; /* just a guess */
if( format == ACROSS && x > startx ) x += sampwidth;
/* parm1 is text, parm2 is textdetails, parm3 is symboldetails */
symdet( "symbol", &Ltext[LEparm3[j]], symcode, &radius );
Emark( x-0.17, yy, symcode, radius );
textdet( &Ltext[LElabel[j]], &Ltext[LEparm2[j]], &align, &adjx, &adjy, -2, "R", 1.0 );
Emov( x-0.17, y+(Ecurtextheight*0.2) );
Ecentext( &Ltext[LEparm1[j]] );
}
s = &Ltext[ LElabel[ j ]];
/* check for embedded url.. */
url[0] = '\0';
if( strnicmp( s, "url:", 4 )==0 ) {
ixx = 0;
strcpy( url, GL_getok( &s[4], &ixx ) );
s = &Ltext[ LElabel[j] + ixx + 4 + 1 ];
}
if( wraplen ) GL_wraptext( s, wraplen );
/* get #lines and maxlen of label */
measuretext( s, &nlines, &maxlen );
if( maxlen > maxtwidth ) maxtwidth = maxlen;
if( nlines > maxthi ) maxthi = nlines;
/* render label */
if( colortext ) {
if( LEtype[j] == LEGEND_COLOR ) Ecolor( color );
strcpy( holdstdcolor, Estandard_color );
strcpy( Estandard_color, "" ); /* this prevents textdet() from changing the color 7/12/01 */
}
textdet( "textdetails", textdetails, &align, &adjx, &adjy, -2, "R", 1.0 );
Emov( x + adjx, y + adjy );
Etext( s );
if( colortext ) strcpy( Estandard_color, holdstdcolor );
if( PLS.clickmap && url[0] ) {
clickmap_entry( 'r', url, 0, x+adjx, y+adjy,
x+adjx+(maxlen*Ecurtextwidth), y+adjy+(nlines*Ecurtextheight), 1, 0, "" );
}
/* determine position for next legend entry.. */
if( format == DOWN ) {
y -= ((Ecurtextheight * nlines) + 0.03 ) + msep;
if( y < colbreak ) { /* start a new column - added scg 8/12/05 */
/* x = x + ((double)maxtwidth*Ecurtextwidth) + sampwidth + colchunksep; */
x = x + ((double)maxtwidth*Ecurtextwidth) + sampwidth + colchunksep;
y = starty - Ecurtextheight;
maxtwidth = 0;
}
}
else if( format == ACROSS ) { /* single line */
/* if( hsep > 0.0 ) x += ((Ecurtextwidth * maxlen ) + sampwidth + hsep); */ /* sampwidth added scg 8/12/05 */
if( hsep > 0.0 ) x += ((Ecurtextwidth * maxlen ) + hsep);
else x += ((Ecurtextwidth * maxlen ) + 1.2);
if( extent > 0.0 && ((x-startx) > extent) ) { /* start a new row - added scg 8/12/05 */
y -= ((Ecurtextheight * maxthi) + rowchunksep);
x = startx;
maxthi = 0;
}
}
}
if( dobox ) {
PLG_get_bb2( &bx1, &by1, &bx2, &by2 ); /* get bb so we know where to place the title.. */
if( title[0] != '\0' ) { /* do invisible title 1st time thru to influence bb, then really draw it 2nd time thru.. */
textdet( "titledetails", titledetails, &align, &adjx, &adjy, 0, "R", 1.0 );
if( align == '?' ) align = 'C';
convertnl( title );
measuretext( title, &nlines, &maxlen );
if( bstate == 0 ) { titx = bx1+((bx2-bx1)/2.0)+adjx; tity = by2+(nlines*Ecurtextheight)+adjy; }
Emov( titx, tity );
Edotext( title, align );
}
Esquelch( "off" );
if( bstate == 0 ) {
/* now that we know the extent of the legend, do box now;
* then we'll go back and draw the legend on top of it */
PLG_get_bb2( &bx1, &by1, &bx2, &by2 ); /* may have changed if there was a title.. */
if( stricmp( frame, "bevel" )==0 ) {
Ecblock( bx1-bmx1, by1-bmy1, bx2+bmx2, by2+bmy2, backcolor, 0 );
Ecblockdress( bx1-bmx1, by1-bmy1, bx2+bmx2, by2+bmy2, 0.07, "0.6", "0.8", 0.0, "" );
}
else if( stricmp( frame, "no" ) == 0 ) Ecblock( bx1-bmx1, by1-bmy1, bx2+bmx2, by2+bmy2, backcolor, 0 );
else {
linedet( "frame", frame, 1.0 );
Ecblock( bx1-bmx1, by1-bmy1, bx2+bmx2, by2+bmy2, backcolor, 1 );
}
bstate = 1;
x = orig_x; y = orig_y;
goto RENDER;
}
}
/* now reset so a new legend can be accumulated.. */
if( !noclear ) NLE = 0;
return( 0 );
}
/* ===================================== */
/* ADD_LEGENT - used by procs to add a legend entry */
int
PL_add_legent( typ, label, tag, parm1, parm2, parm3 )
int typ;
char *label, *tag, *parm1, *parm2, *parm3;
{
char *errmsg;
errmsg = "Sorry, too much legend content";
convertnl( label );
LEtype[ NLE ] = typ;
LElabel[ NLE ] = LEavail;
if( LEavail + strlen( label ) >= MAXLEGTEXT )
return( Eerr( 8478, errmsg, "" ) );
strcpy( &Ltext[ LEavail ], label );
LEavail += (strlen( label ) + 1);
LEtag[ NLE ] = LEavail;
if( LEavail + strlen( tag ) >= MAXLEGTEXT )
return( Eerr( 8478, errmsg, "" ) );
strcpy( &Ltext[ LEavail ], tag );
LEavail += (strlen( tag ) + 1);
if( LEavail + strlen( parm1 ) >= MAXLEGTEXT )
return( Eerr( 8478, errmsg, "" ) );
LEparm1[ NLE ] = LEavail;
strcpy( &Ltext[ LEavail ], parm1 );
LEavail += (strlen( parm1 ) + 1);
if( LEavail + strlen( parm2 ) >= MAXLEGTEXT )
return( Eerr( 8478, errmsg, "" ) );
LEparm2[ NLE ] = LEavail;
strcpy( &Ltext[ LEavail ], parm2 );
LEavail += (strlen( parm2 ) + 1);
if( LEavail + strlen( parm3 ) >= MAXLEGTEXT )
return( Eerr( 8478, errmsg, "" ) );
LEparm3[ NLE ] = LEavail;
strcpy( &Ltext[ LEavail ], parm3 );
LEavail += (strlen( parm3 ) + 1);
NLE++;
return( 0 );
}
/* ========================================= */
/* GET_LEGENT - get a legend entry based on tag */
int
PL_get_legent( tag, parm1, parm2, parm3 )
char *tag, *parm1, *parm2, *parm3;
{
int i;
for( i = 0; i < NLE; i++ ) if( strcmp( tag, &Ltext[ LEtag[i] ] )==0 ) break;
if( i == NLE ) return( 1 ); /* tag not found.. */
if( parm1 != NULL ) strcpy( parm1, &Ltext[ LEparm1[i] ] );
if( parm2 != NULL ) strcpy( parm2, &Ltext[ LEparm2[i] ] );
if( parm3 != NULL ) strcpy( parm3, &Ltext[ LEparm3[i] ] );
return( 0 );
}
/* ========================================= */
/* GET_LEGENT_RG - get a legend entry based numeric comparison with tag */
int
PL_get_legent_rg( val, parm1, parm2, parm3 )
double val;
char *parm1, *parm2, *parm3;
{
int i;
double atof();
for( i = 0; i < NLE; i++ ) if( val >= atof( &Ltext[ LEtag[i] ] ) ) break;
if( i == NLE ) return( 1 ); /* tag not found.. */
if( parm1 != NULL ) strcpy( parm1, &Ltext[ LEparm1[i] ] );
if( parm2 != NULL ) strcpy( parm2, &Ltext[ LEparm2[i] ] );
if( parm3 != NULL ) strcpy( parm3, &Ltext[ LEparm3[i] ] );
return( 0 );
}
/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
syntax highlighted by Code2HTML, v. 0.9.1