Subject: | Tk::Canvas: -dash, Bitmap |
Here are some patches against bugs in Tk-804.027. I've
tested them on Linux only. Some of the fixes may have to
go into the original Tk code and documentation.
Correcting the handling of the -dash option for canvas items
------------------------------------------------------------
The problems addressed by this patch are:
(1) For all canvas items supporting the option -dash, any pattern
specified as a list of exactly two identical integers, e.g.
-dash => [ 4, 4 ]
is ignored, and a solid line is drawn.
(2) With a list consisting of a single integer, or a scalar integer,
e.g.
-dash => [ 4 ]
-dash => 4
no error is reported.
(3) Error reporting is broken in some cases (producing weird
messages about bad utf8 encoding), e.g.
-dash => ',;'
-dash => [ 'x', 4 ]
(4) The feature of specifying dash patterns by a string consisting
of [.,-_ ] isn't implemented according to the documentation:
(a) The '.' should produce a "dot", but results in a 2x1-rectangle.
Since all other values are longer, there is no way to produces
"dots".
(b) According to the examples, a defult gap has the same width as a
dash resulting from a ",". An additional space, however,
increments the preceding gap by the -width value plus 1, which
is surprising and, moreover, doesn't scale well with increased
width.
(5) If some dash or gap length resulting from a string specification
exceeds the capacity of a char (UCHAR_MAX), the result is
silently taken modulo 256. Using UCHAR_MAX appears to be closer
to the real value. (Perhaps raising a fatal error would be
even better.)
(6) Outlines of rectangles and ovals are drawn as solid lines
whenever the width is greater than or equal to the gap.
The fix of (4) is bound to change the behaviour of existing
programs using this form of dash specifications. If this must
be avoided, the documentation would have to be rewritten.
Affected files: pTk/tkCanvUtil.c, pTk/tkRectOval.c, pod/Canvas.pod
Documenting and checking a restriction on canvas bitmaps
--------------------------------------------------------
This patch does two things:
First it documents the restriction that a set of canvas bitmaps
specified as the normal, active and disabled bitmap must have
identical dimensions.
Second, it adds a check, resulting in an error if this is rule
violated.
Trying to use bitmaps of various x- and/or y-sizes results in
the active or disabled bitmap to appear in wrong positions
with respect to the anchor. Fixing this (e.g. by computing the
minimum-maximum rectangle across all bitmaps) doesn't help
because drawing a bitmap is still restricted to the bitmap's
own rectangle. Even if this were fixed, it'd still not be
satisfactory. Consider the case where the cursor hits the
'normal' bitmap in an area that is not covered by the 'active'
bitmap. This would then result in the 'active' bitmap replacing
the 'normal' one - but then the cursor won't be on the bitmap
any more, so that the 'normal' one would return, and so on.
Affected files: pTk/tkCanvBmap.c, pod/Canvas.pod
{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\froman\fcharset0 Times New Roman;}{\f1\fswiss\fcharset0 Arial;}}
\viewkind4\uc1\pard\f0\fs20 --- pTk/tkCanvUtil.c.old Sun Dec 26 19:06:26 2004\fs24 \line\fs20 +++ pTk/tkCanvUtil.c Sun Dec 26 19:06:58 2004\fs24 \line\fs20 @@ -798,9 +798,7 @@\fs24 \line\fs20 if ((*value == '.') || (*value == ',') ||\fs24 \line\fs20 (*value == '-') || (*value == '_')) \{\fs24 \line\fs20 i = DashConvert( NULL, value, -1, 0.0);\fs24 \line\fs20 - if (i>0) \{\fs24 \line\fs20 - i = strlen(value);\fs24 \line\fs20 - \} else \{\fs24 \line\fs20 + if (i<0) \{\fs24 \line\fs20 goto badDashList;\fs24 \line\fs20\}\fs24 \line\fs20 if (i > (int) sizeof(char *)) \{\fs24 \line\fs20 @@ -812,7 +810,8 @@\fs24 \line\fs20 dash->number = -i;\fs24 \line\fs20 return TCL_OK;\fs24 \line\fs20\}\fs24 \line\fs20 - if (Tcl_ListObjGetElements(interp, ovalue, &argc, &objv) != TCL_OK)\fs24 \line\fs20\{\fs24 \line\fs20 + if (Tcl_ListObjGetElements(interp, ovalue, &argc, &objv) != TCL_OK\fs24 \line\fs20 ||\fs24 \line\fs20 + argc <= 1) \{\fs24 \line\fs20 Tcl_ResetResult(interp);\fs24 \line\fs20 badDashList:\fs24 \line\fs20 Tcl_AppendResult(interp, "bad dash list \\"", value,\fs24 \line\fs20 @@ -841,7 +840,7 @@\fs24 \line\fs20 i < 1 || i>255) \{\fs24 \line\fs20 Tcl_ResetResult(interp);\fs24 \line\fs20 Tcl_AppendResult(interp, "expected integer in the range\fs24 \line\fs20 1..255 but got \\"",\fs24 \line\fs20 - *largv, "\\"", NULL);\fs24 \line\fs20 + Tcl_GetString(*largv), "\\"",\fs24 \line\fs20 NULL);\fs24 \line\fs20 goto syntaxError;\fs24 \line\fs20\}\fs24 \line\fs20 *pt++ = i;\fs24 \line\fs20 @@ -1054,8 +1053,6 @@\fs24 \line\fs20 gcValues->dash_offset = outline->offset;\fs24 \line\fs20 if (dash->number >= 2) \{\fs24 \line\fs20 gcValues->dashes = 4;\fs24 \line\fs20 - \} else if (dash->number > 0) \{\fs24 \line\fs20 - gcValues->dashes = dash->pattern.array[0];\fs24 \line\fs20\} else \{\fs24 \line\fs20 gcValues->dashes = (char) (4 * width);\fs24 \line\fs20\}\fs24 \line\fs20 @@ -1141,7 +1138,7 @@\fs24 \line\fs20 return 0;\fs24 \line\fs20\}\fs24 \line\line\fs20 - if ((dash->number<-1) || ((dash->number == -1) &&\fs24 \line\fs20 (dash->pattern.array[1]!=','))) \{\fs24 \line\fs20 + if ( dash->number<=-2 ) \{\fs24 \line\fs20 char *q;\fs24 \line\fs20 int i = -dash->number;\fs24 \line\line\fs20 @@ -1151,8 +1148,7 @@\fs24 \line\fs20 XSetDashes(((TkCanvas *)canvas)->display, outline->gc,\fs24 \line\fs20 outline->offset, q, i);\fs24 \line\fs20 values.line_style = LineOnOffDash;\fs24 \line\fs20 ckfree(q);\fs24 \line\fs20 - \} else if ( dash->number>2 || (dash->number==2 &&\fs24 \line\fs20 - (dash->pattern.array[0]!=dash->pattern.array[1]))) \{\fs24 \line\fs20 + \} else if ( dash->number>=2 ) \{\fs24 \line\fs20 p = (char *) (dash->number > (int) sizeof(char *)) ?\fs24 \line\fs20 dash->pattern.pt : dash->pattern.array;\fs24 \line\fs20 XSetDashes(((TkCanvas *)canvas)->display, outline->gc,\fs24 \line\fs20 outline->offset, p, dash->number);\fs24 \line\fs20 values.line_style = LineOnOffDash;\fs24 \line\fs20 @@ -1262,13 +1258,9 @@\fs24 \line\fs20 return 0;\fs24 \line\fs20\}\fs24 \line\line\fs20 - if ((dash->number > 2) || (dash->number < -1) || (dash->number==2\fs24 \line\fs20 &&\fs24 \line\fs20 - (dash->pattern.array[0] != dash->pattern.array[1])) ||\fs24 \line\fs20 - ((dash->number == -1) && (dash->pattern.array[1] !=\fs24 \line\fs20 ','))) \{\fs24 \line\fs20 + if ( (dash->number >= 2) || (dash->number <= -2) ) \{\fs24 \line\fs20 if (dash->number < 0) \{\fs24 \line\fs20 dashList = (int) (4 * width + 0.5);\fs24 \line\fs20 - \} else if (dash->number<3) \{\fs24 \line\fs20 - dashList = dash->pattern.array[0];\fs24 \line\fs20\} else \{\fs24 \line\fs20 dashList = 4;\fs24 \line\fs20\}\fs24 \line\fs20 @@ -1449,7 +1441,7 @@\fs24 \line\fs20 double width;\fs24 \line\fs20\{\fs24 \line\fs20 int result = 0;\fs24 \line\fs20 - int size, intWidth;\fs24 \line\fs20 + int size, intWidth, actWidth;\fs24 \line\line\fs20 if (n<0) \{\fs24 \line\fs20 n = strlen(p);\fs24 \line\fs20 @@ -1463,7 +1455,7 @@\fs24 \line\fs20 case ' ':\fs24 \line\fs20 if (result) \{\fs24 \line\fs20 if (l) \{\fs24 \line\fs20 - l[-1] += intWidth + 1;\fs24 \line\fs20 + l[-1] += intWidth;\fs24 \line\fs20\}\fs24 \line\fs20 continue;\fs24 \line\fs20\} else \{\fs24 \line\fs20 @@ -1471,23 +1463,25 @@\fs24 \line\fs20\}\fs24 \line\fs20 break;\fs24 \line\fs20 case '_':\fs24 \line\fs20 - size = 8;\fs24 \line\fs20 + size = 4;\fs24 \line\fs20 break;\fs24 \line\fs20 case '-':\fs24 \line\fs20 - size = 6;\fs24 \line\fs20 + size = 3;\fs24 \line\fs20 break;\fs24 \line\fs20 case ',':\fs24 \line\fs20 - size = 4;\fs24 \line\fs20 + size = 2;\fs24 \line\fs20 break;\fs24 \line\fs20 case '.':\fs24 \line\fs20 - size = 2;\fs24 \line\fs20 + size = 1;\fs24 \line\fs20 break;\fs24 \line\fs20 default:\fs24 \line\fs20 return -1;\fs24 \line\fs20\}\fs24 \line\fs20 if (l) \{\fs24 \line\fs20 - *l++ = size * intWidth;\fs24 \line\fs20 - *l++ = 4 * intWidth;\fs24 \line\fs20 + actWidth = size * intWidth;\fs24 \line\fs20 + *l++ = actWidth > UCHAR_MAX ? UCHAR_MAX : actWidth;\fs24 \line\fs20 + actWidth = 2 * intWidth;\fs24 \line\fs20 + *l++ = actWidth > UCHAR_MAX ? UCHAR_MAX : actWidth;\fs24 \line\fs20\}\fs24 \line\fs20 result += 2;\fs24 \line\fs20\}\fs24 \line\fs20 --- pTk/tkRectOval.c.old Tue Dec 28 07:39:21 2004\fs24 \line\fs20 +++ pTk/tkRectOval.c Tue Dec 28 08:07:29 2004\fs24 \line\fs20 @@ -476,8 +476,6 @@\fs24 \line\fs20 if (mask && \\\fs24 \line\fs20 rectOvalPtr->outline.width != 0 && \\\fs24 \line\fs20 rectOvalPtr->outline.color != NULL) \{\fs24 \line\fs20 - gcValues.cap_style = CapProjecting;\fs24 \line\fs20 - mask |= GCCapStyle;\fs24 \line\fs20 newGC = Tk_GetGC(tkwin, mask, &gcValues);\fs24 \line\fs20\} else \{\fs24 \line\fs20 newGC = None;\fs24 \line\fs20 --- pTk/tkCanvBmap.c.old Wed Nov 24 11:13:10 2004\fs24 \line\fs20 +++ pTk/tkCanvBmap.c Sat Dec 18 22:46:23 2004\fs24 \line\fs20 @@ -331,6 +331,8 @@\fs24 \line\fs20 XColor *bgColor;\fs24 \line\fs20 Pixmap bitmap;\fs24 \line\fs20 Tk_State state;\fs24 \line\fs20 + int width, height;\fs24 \line\fs20 + int width1, height1;\fs24 \line\line\fs20 tkwin = Tk_CanvasTkwin(canvas);\fs24 \line\fs20 if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc,\fs24 \line\fs20 @@ -353,6 +355,28 @@\fs24 \line\fs20 itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;\fs24 \line\fs20\}\fs24 \line\line\fs20 + /* Check that bitmaps have same width and height */\fs24 \line\fs20 + Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)),\fs24 \line\fs20 bmapPtr->bitmap,\fs24 \line\fs20 + &width, &height);\fs24 \line\fs20 + if (bmapPtr->activeBitmap!=None) \{\fs24 \line\fs20 + Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)),\fs24 \line\fs20 + bmapPtr->activeBitmap,\fs24 \line\fs20 + &width1, &height1);\fs24 \line\fs20 + if (width != width1 || height != height1) \{\fs24 \line\fs20 + Tcl_SetResult(interp, "active bitmap dimensions differ",\fs24 \line\fs20 TCL_STATIC);\fs24 \line\fs20 + return TCL_ERROR;\fs24 \line\fs20 + \}\fs24 \line\fs20 + \}\fs24 \line\fs20 + if (bmapPtr->disabledBitmap!=None) \{\fs24 \line\fs20 + Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)),\fs24 \line\fs20 + bmapPtr->disabledBitmap,\fs24 \line\fs20 + &width1, &height1);\fs24 \line\fs20 + if (width != width1 || height != height1) \{\fs24 \line\fs20 + Tcl_SetResult(interp, "disabled bitmap dimensions differ",\fs24 \line\fs20 TCL_STATIC);\fs24 \line\fs20 + return TCL_ERROR;\fs24 \line\fs20 + \}\fs24 \line\fs20 + \}\fs24 \line\fs20 +\fs24 \line\fs20 if (state==TK_STATE_HIDDEN) \{\fs24 \line\fs20 ComputeBitmapBbox(canvas, bmapPtr);\fs24 \line\fs20 return TCL_OK;\fs24 \line\fs20 --- pod/Canvas.pod.old Sat Dec 25 10:34:16 2004\fs24 \line\fs20 +++ pod/Canvas.pod Sun Dec 26 18:45:41 2004\fs24 \line\fs20 @@ -346,26 +346,29 @@\fs24 \line\fs20 The first possible syntax is a list of integers. Each element\fs24 \line\fs20 represents the number of pixels of a line segment. Only the odd\fs24 \line\fs20 segments are drawn using the "outline" color. The other segments\fs24 \line\fs20 -are drawn transparant.\fs24 \line\fs20 +are drawn transparent.\fs24 \line\line\fs20 The second possible syntax is a character list containing only\fs24 \line\fs20 -5 possible characters B<[.,-_ ]>. The space can be used\fs24 \line\fs20 -to enlarge the space between other line elements, and can not\fs24 \line\fs20 -occur as the first position in the string. Some examples:\fs24 \line\fs20 +5 possible characters B<[.,-_ ]>, with the first 4 characters\fs24 \line\fs20 +producing a segment of length 1 to 4, respectively, followed\fs24 \line\fs20 +by a transparent segment of length 2. The space can be used\fs24 \line\fs20 +repeatedly to enlarge the space between other line elements\fs24 \line\fs20 +by 1, and can not occur as the first position in the string.\fs24 \line\fs20 +The main difference of this syntax with the previous is that it\fs24 \line\fs20 +it shape-conserving. This means that all values in the dash\fs24 \line\fs20 +list will be multiplied by the line width before display. This\fs24 \line\fs20 +assures that "." will always be displayed as a dot and "-"\fs24 \line\fs20 +always as a dash regardless of the line width.\fs24 \line\fs20 +\fs24 \line\fs20 +Some examples, for a line width of 2:\fs24 \line\line\fs20 -dash . = -dash [2,4]\fs24 \line\fs20 -dash - = -dash [6,4]\fs24 \line\fs20 -dash -. = -dash [6,4,2,4]\fs24 \line\fs20 -dash -.. = -dash [6,4,2,4,2,4]\fs24 \line\fs20 - -dash '. ' = -dash [2,8]\fs24 \line\fs20 + -dash '. ' = -dash [2,6]\fs24 \line\fs20 -dash ',' = -dash [4,4]\fs24 \line\line\fs20 -The main difference of this syntax with the previous is that it\fs24 \line\fs20 -it shape-conserving. This means that all values in the dash\fs24 \line\fs20 -list will be multiplied by the line width before display. This\fs24 \line\fs20 -assures that "." will always be displayed as a dot and "-"\fs24 \line\fs20 -always as a dash regardless of the line width.\fs24 \line\fs20 -\fs24 \line\fs20 On systems where only a limited set of dash patterns, the dash\fs24 \line\fs20 pattern will be displayed as the most close dash pattern that\fs24 \line\fs20 is available. For example, on Windows only the first 4 of the\fs24 \line\fs20 @@ -1355,14 +1358,14 @@\fs24 \line\fs20 =item B<-disabledbitmap> =E<gt> I<bitmap>\fs24 \line\line\fs20 Specifies the bitmaps to display in the item in its normal, active and\fs24 \line\fs20 -disabled states.\fs24 \line\fs20 +disabled states. All bitmaps must have the same width and height.\fs24 \line\fs20 I<Bitmap> may have any of the forms accepted by B<Tk_GetBitmap>.\fs24 \line\line\fs20 =item B<-foreground> =E<gt> I<color>\fs24 \line\line\fs20 -=item B<-activeforeground> =E<gt> I<bitmap>\fs24 \line\fs20 +=item B<-activeforeground> =E<gt> I<color>\fs24 \line\line\fs20 -=item B<-disabledforeground> =E<gt> I<bitmap>\fs24 \line\fs20 +=item B<-disabledforeground> =E<gt> I<color>\fs24 \line\line\fs20 Specifies the color to use for each of the bitmap's '1' valued pixels\fs24 \line\fs20 in its normal, active and disabled states.\fs24 \par
\f1\fs20\par
}