Tk Source Code

View Ticket
Login
Ticket UUID: 5f739d22533a85c47db9ffb5e698f51a3c7d817d
Title: Inconsistency in whether widgets allow negative borderwidths
Type: Bug Version: 9.0
Submitter: marc_culler Created on: 2024-07-08 21:55:02
Subsystem: 23. Option Parsing Assigned To: marc_culler
Priority: 5 Medium Severity: Minor
Status: Open Last Modified: 2024-08-26 09:20:02
Resolution: None Closed By: nobody
    Closed on:
Description:
In Tk 9.0 a Canvas widget can have a negative borderwidth (whatever
that is supposed to mean):

% canvas .c
.c
% .c configure -borderwidth -2
% .c configure -borderwidth
-borderwidth borderWidth BorderWidth 0 -2

But a button cannot have a negative borderwidth:

% button .b
.b
% .b configure -borderwidth -2
% .b configure -borderwidth
-borderwidth borderWidth BorderWidth 2 0

Surely this inconsistency is not intentional, right?  So I think this is
a bug.
User Comments: jan.nijtmans added on 2024-08-26 09:20:02:

It turned out that for "frame", width and height was still not handled correctly.

fixed that now.

I'm sure there are more ...., so keeping open


marc_culler (claiming to be Marc Culler) added on 2024-07-12 16:32:46:
I see that the scrollbar manual page has already been edited as I suggested.
(I was looking at the online manual).  So all that is needed is to set
borderwidth to 0 when a negative value is specified.

marc_culler (claiming to be Marc Culler) added on 2024-07-12 16:26:07:
Here is a really weird one, which also does not seem to behave the way
the manual says:

% scrollbar .sb
.sb
% .sb configure -borderwidth -2
% .sb configure -borderwidth
-borderwidth borderWidth BorderWidth 0 -2
% .sb configure -elementborderwidth 3
% .sb configure -elementborderwidth
-elementborderwidth elementBorderWidth BorderWidth {} 3
% .sb configure -elementborderwidth -3
% .sb configure -elementborderwidth
-elementborderwidth elementBorderWidth BorderWidth {} {}

So borderwidth is allowed to have a negative value but elementborderwidth
is set to '' if it is assigned a negative value.

The manual says (about elementborderwidth):
"If this value is less than zero, the value of the -borderwidth option is used in its place."

It would seem that feature could never be activated, since the value
is never less than 0, although it might be ''.  One would need to
read the code to learn that setting the option to {} causes the struct
field to be set to INT_MIN, which is actually a negative value.

Also, the manual says that the -borderwidth is always non-negative:
"Specifies a non-negative value indicating the width of the 3-D border
 to draw around the outside of the widget"

There are many ways to interpret the manual, but the intent is revealed
by looking at tkUnixScrlbr.c, which says in TkDisplayScrollbar:

    elementBorderWidth = scrollPtr->elementBorderWidth;
    if (elementBorderWidth < 0) {
        elementBorderWidth = scrollPtr->borderWidth;
    }

(The other platforms ignore the option altogether.)

So one way to make the behavior agree with the manual would be to
(1) replace negative values of borderwidth by 0; and
(2) edit the manual to say "negative value or {}" and perhaps point
out that the default value is {}.

jan.nijtmans added on 2024-07-12 06:37:13:

But ... be carefull: If the TK_OPTION_NULL_OK flag is set it's slightly different

Then it's best to turn the invalid value into "", so it won't be taken into account.


jan.nijtmans added on 2024-07-12 05:23:31:

>Can I do it like this?

+1


marc_culler (claiming to be Marc Culler) added on 2024-07-12 01:46:24:
Can I do it like this?

#define FIX_NEGATIVE_OPTION(widget, option)          \
	if (widget->option < 0) {                    \
	    widget->option = 0;                      \
	    if (widget->optionPtr) {                 \
		Tcl_DecrRefCount(widget->optionPtr); \
	    }                                        \
	    widget->optionPtr = Tcl_NewIntObj(0);    \
	    Tcl_IncrRefCount(widget->optionPtr);     \
	}


:^)

jan.nijtmans added on 2024-07-11 21:49:05:

And [c15c895b789cd7b6|here] is the fix for those examples :-)

Good luck, doing this for all options with the same consistency ...


marc_culler (claiming to be Marc Culler) added on 2024-07-09 15:28:36:
Here is another inconsistency.   A button treats negative width and height
values differently from how it treats negative borderwidth values in Tk 9.0:

% button .b
.b
% .b configure -width -100 -height -100
% .b configure -width
-width width Width 0 -100
% .b configure -height
-height height Height 0 -100

marc_culler (claiming to be Marc Culler) added on 2024-07-09 02:26:36:
Another way to drive unit testers crazy is to change the wording of
error messages, causing tests which check the error message to start
giving false negatives.

I think the best strategy for Python would be to raise a Python exception
if a negative value is supplied to an option which is *planned* to not
use the TK_OPTION_NEG_OK attribute, even if the restriction is not yet
enforced by actual Tk widgets.  That way when Tk gets around to finishing
TIP 698 no extra work will be needed for Python.

One way around the error message issue would be to add a prefix to
each message containing a numerical code.  Then the unit tests only
need to check the code, and Tk can change the wording to our heart's
content. IF a message changes from:
  "Tcl_CreateInterp error 123: can't create global namespace"
to
  "Tcl_CreateInterp error 123: cannot create global namespace"
then it will not break any correctly written unit tests.

PS If I were allowed to offer an opinion about the discussion in [0439e1e1a]
I would say that making a message more "formal" by changing can't
to cannot while still omitting articles and using incomplete sentences
seems Quixotic.

marc_culler (claiming to be Marc Culler) added on 2024-07-09 01:46:29:
In the tkinter unit tests they test assigning a list of values for each option
of each widget type.  They use configure to set the opeion and then use configure
or cget to read the option.  The test compares the input and the output.

They have a set of comparison functions that are supposed to cover the
different possibilities.  But if the behavior varies by widget type, option
name, and Tk version, it makes for a lot of extra work.  And if it also varies
over time with the same Tk version that makes it really hard.  It seems like
it would be better if it just depended on the Tk version and the option name,
and if there weren't too many different behaviors among the different
options.

jan.nijtmans added on 2024-07-08 22:38:36:

In Tk 8.6:

% button .b
.b
% .b configure -borderwidth -2
% .b configure -borderwidth
-borderwidth borderWidth BorderWidth 2 -2

This suggests that buttons accepts a negative borderwidth, but in fact it doesn't. See also TIP #698. I think the best way to handle this is as described in the TIP. The second-best way (as some - but not all - widgets already do) is change the negative value to 0 or {}. This is done in Tk 9 for 'button' and 'message', but not yet for other widgets.

Indeed, this is not done consistently yet