Pikchr

Patch for textcolor
Login

Patch for textcolor

(1.1) By sam atman (mnemnion) on 2024-04-15 20:47:09 edited from 1.0 [source]

While experimenting with the other branch, I ran into text and object color being coupled. This is a patch which adds a textcolor attribute, which should behave the same as color and fill (mostly). It is independent of the larger branch.

Here's a fiddle of the result.

To match the existing behavior, text color will continue to match the color attribute, unless textcolor is set. The two may be set in any order, but just once each.

As with color and fill, the default can be changed by setting a textcolor variable. But use of color on an object will override this. The fiddle illustrates the behavior of the change. It would be possible to check the user variable list and only override pObj->textcolor if it isn't set, which would change the result of "fifth box", but that seems inconsistent.

It might be nicer if all three were fully independent, but that would be a breaking change, so this patch is conservative. I indicated the lines which could be removed to make textcolor independent of color.

Without further ado...

License

Zero-Clause BSD license:

Copyright (C) 2024-4-15 Sam Atman <atmanistan@gmail.com>

Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.

Patch

Now edited to copy the textcolor property, so that same respects the textcolor property of the preceding element, as well as to check ->textcolor rather than ->color when deciding whether to add a fill property in pik_append_txt.

I'm not sure the last one was important; I experimentally deleted the fill from the <text> element and, as expected, it defaults to currentcolor, or at least black. And the place I see ->color set to a negative value is in move, INVIS uses a negative->sw instead, so that branch appears to be unreachable.

If it's desirable that a negative textcolor value produce invisible text, that conditional could set fill to "transparent".

```

Index: pikchr.y

--- pikchr.y +++ pikchr.y @@ -293,10 +293,11 @@ #define A_FROM 0x0100 #define A_CW 0x0200 #define A_AT 0x0400 #define A_TO 0x0800 /* one or more movement attributes */ #define A_FIT 0x1000 +#define A_TEXTCOLOR 0x2000

/* A single graphics object / struct PObj { const PClass *type; / Object type or class / @@ -311,18 +312,19 @@ PNum sw; / "thickness" property. (Mnemonic: "stroke width")/ PNum dotted; / "dotted" property. <=0.0 for off / PNum dashed; / "dashed" property. <=0.0 for off / PNum fill; / "fill" property. Negative for off / PNum color; / "color" property */

  • PNum textcolor; /* "textcolor" property*/ PPoint with; /* Position constraint from WITH clause / char eWith; / Type of heading point on WITH clause / char cw; / True for clockwise arc / char larrow; / Arrow at beginning (<- or <->) / char rarrow; / Arrow at end (-> or <->) / char bClose; / True if "close" is seen / char bChop; / True if "chop" is seen / unsigned char nTxt; / Number of text values / unsigned mProp; / Masks of properties set so far / unsigned mCalc; / Values computed from other constraints / PToken aTxt[5]; / Text with .eCode holding TP flags / int iLayer; / Rendering order */ @@ -567,17 +569,18 @@

// assert() statements are undocumented and are intended for testing and // debugging use only. If the equality comparison of the assert() fails // then an error message is generated. statement(A) ::= ASSERT LP expr(X) EQ(OP) expr(Y) RP. {A=pik_assert(p,X,&OP,Y);} {A=pik_position_assert(p,&X,&OP,&Y);} statement(A) ::= DEFINE ID(ID) CODEBLOCK(C). {A=0; pik_add_macro(p,&ID,&C);}

lvalue(A) ::= ID(A). lvalue(A) ::= FILL(A). lvalue(A) ::= COLOR(A). +lvalue(A) ::= TEXTCOLOR(A). lvalue(A) ::= THICKNESS(A).

// PLACENAME might actually be a color name (ex: DarkBlue). But we // cannot make it part of expr due to parsing ambiguities. The // rvalue non-terminal means "general expression or a colorname" @@ -665,10 +668,11 @@ dashproperty(A) ::= DASHED(A).

// Color properties colorproperty(A) ::= FILL(A). colorproperty(A) ::= COLOR(A). +colorproperty(A) ::= TEXTCOLOR(A).

// Properties with no argument boolproperty ::= CW. {p->cur->cw = 1;} boolproperty ::= CCW. {p->cur->cw = 0;} boolproperty ::= LARROW. {p->cur->larrow=1; p->cur->rarrow=0; } @@ -986,10 +990,11 @@ { "linewid", 0.5 }, { "movewid", 0.5 }, { "ovalht", 0.5 }, { "ovalwid", 1.0 }, { "scale", 1.0 },

  • { "textcolor", 0.0 }, { "textht", 0.5 }, { "textwid", 0.75 }, { "thickness", 0.015 }, };

@@ -2515,12 +2520,12 @@ pik_append(p, " font-weight="bold"", -1); } if( t->eCode & TP_MONO ){ pik_append(p, " font-family="monospace"", -1); }

  • if( pObj->color>=0.0 ){
  • pik_append_clr(p, " fill="", pObj->color, """,0);
  • if( pObj->textcolor>=0.0 ){
  • pik_append_clr(p, " fill="", pObj->textcolor, """,0); } xtraFontScale = p->fontScale; if( xtraFontScale<=0.99 || xtraFontScale>=1.01 ){ pik_append_num(p, " font-size="", xtraFontScale100.0); pik_append(p, "%"", 2); @@ -2953,10 +2958,11 @@ if( pClass ){ pNew->type = pClass; pNew->sw = pik_value(p, "thickness",9,0); pNew->fill = pik_value(p, "fill",4,0); pNew->color = pik_value(p, "color",5,0);
  • pNew->textcolor = pik_value(p, "textcolor",9,0); pClass->xInit(p, pNew); return pNew; } pik_error(p, pId, "unknown object type"); pik_elem_free(p, pNew); @@ -3089,11 +3095,11 @@ ** To be ok, bit mThis must be clear and no more than one of ** the bits identified by mBlockers may be set. / static int pik_param_ok( Pik *p, / For storing the error message (if any) */
  • PObj pObj, / The object under construction */
  • PObj pObj, / The object under construction / PToken *pId, / Make the error point to this token / int mThis / Value we are trying to set */ ){ if( pObj->mProp & mThis ){ pik_error(p, pId, "value is already set"); @@ -3155,10 +3161,18 @@ pObj->fill = rClr; break; case T_COLOR: if( pik_param_ok(p, pObj, pId, A_COLOR) ) return; pObj->color = rClr;
  • // without these lines we would have a breaking change
  • if( !(pObj->mProp & A_TEXTCOLOR)){
  • pObj->textcolor = rClr;
  • }
  • break;
  • case T_TEXTCOLOR:
  • if( pik_param_ok(p, pObj, pId, A_TEXTCOLOR) ) return;
  • pObj->textcolor = rClr; break; } if( pObj->type->xNumProp ){ pObj->type->xNumProp(p, pObj, pId); } @@ -4056,10 +4070,11 @@ pObj->sw = pOther->sw; pObj->dashed = pOther->dashed; pObj->dotted = pOther->dotted; pObj->fill = pOther->fill; pObj->color = pOther->color;
  • pObj->textcolor = pOther->textcolor; pObj->cw = pOther->cw; pObj->larrow = pOther->larrow; pObj->rarrow = pOther->rarrow; pObj->bClose = pOther->bClose; pObj->bChop = pOther->bChop; @@ -4150,10 +4165,11 @@ case T_THICKNESS: v = pObj->sw; break; case T_DASHED: v = pObj->dashed; break; case T_DOTTED: v = pObj->dotted; break; case T_FILL: v = pObj->fill; break; case T_COLOR: v = pObj->color; break;
  • case T_TEXTCOLOR: v = pObj->textcolor; break; case T_X: v = pObj->ptAt.x; break; case T_Y: v = pObj->ptAt.y; break; case T_TOP: v = pObj->bbox.ne.y; break; case T_BOTTOM: v = pObj->bbox.sw.y; break; case T_LEFT: v = pObj->bbox.sw.x; break; @@ -4704,10 +4720,11 @@ { "south", 5, T_EDGEPT, 0, CP_S }, { "sqrt", 4, T_FUNC1, FN_SQRT, 0 }, { "start", 5, T_START, 0, CP_START }, { "sw", 2, T_EDGEPT, 0, CP_SW }, { "t", 1, T_TOP, 0, CP_N },
  • { "textcolor", 9, T_TEXTCOLOR, 0, 0 }, { "the", 3, T_THE, 0, 0 }, { "then", 4, T_THEN, 0, 0 }, { "thick", 5, T_THICK, 0, 0 }, { "thickness", 9, T_THICKNESS, 0, 0 }, { "thin", 4, T_THIN, 0, 0 },

(2) By sam atman (mnemnion) on 2024-04-15 01:39:32 in reply to 1.0 [link] [source]

Here's a second one which fixes a bug with hex parsing.

It was interpreting a value like 9xff0000 as 9, because it accepted any digit in the tokenizer before the x, but then pik_atof validated it differently and handed it to strtod, which was happy to convert the 9 to a double. This changes such malformed input into a syntax error.

I affirm this patch to be covered by the same license as in the post I'm replying to.

Index: pikchr.y
==================================================================
--- pikchr.y
+++ pikchr.y
@@ -5026,11 +5026,11 @@
         int nDigit;
         int isInt = 1;
         if( c!='.' ){
           nDigit = 1;
           for(i=1; (c = z[i])>='0' && c<='9'; i++){ nDigit++; }
-          if( i==1 && (c=='x' || c=='X') ){
+          if( i==1 && (c=='x' || c=='X') && z[0] == '0' ){
             for(i=2; (c = z[i])!=0 && isxdigit(c); i++){}
             pToken->eType = T_NUMBER;
             return i;
           }
         }else{

(3) By drh on 2024-04-15 12:00:54 in reply to 2 [link] [source]

Can you please print a copy of the (newly added) Pikchr Contributors Agreement, sign it, and send me a scan via email?

(4) By sam atman (mnemnion) on 2024-04-15 16:26:28 in reply to 3 [link] [source]

It would be my pleasure. Sent.