Tk Source Code

View Ticket
Login
EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Ticket UUID: bc602049ab64d6acece3c43f15d0ca236f532f06
Title: Treeview with custom background expands when switching themes
Type: Bug Version: 8.6.11
Submitter: anonymous Created on: 2022-08-15 18:59:48
Subsystem: 88. Themed Tk Assigned To: fvogel
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2022-09-04 14:06:19
Resolution: Fixed Closed By: fvogel
    Closed on: 2022-09-04 14:06:19
Description:

I have created a few ttk themes (most notably Sun Valley and Azure), where I provide both a dark and a light variant of the theme. Some users have noted that when switching between themes, the treeview widget expands horizontally.

I have done some tests with other ttk themes and it turns out that this problem is caused by the fact that the treeview has a custom image background (Treeview.field element), and this problem exists with all ttk themes that use a custom image background for the treeview.

Here is a short example that illustrates the bug:

package require Tk

image create photo tvbg -data {
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAnXAAAJ1wG
xbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAACJJREFUOI
1jPLF9+38GKgImaho2auCogaMGjho4auBQMhAAyR0DXUEyypsAAAAASUVORK5CYII=
}

ttk::style theme create foo -parent clam -settings {
  ttk::style element create Treeview.field image tvbg
}

ttk::style theme use foo

pack [ttk::treeview .tree]
pack [ttk::button .btn -text "theme use" -command {ttk::style theme use foo}]

I suspect that something is wrong with the recalculation of the treeview width, because the treeview increases in width exactly as much as the width of the element's image (in this case 20px), or when using a -border 2 for example, then by 20-2-2=16 pixels, so basically there's an extra column of images.

User Comments: fvogel added on 2022-09-04 14:06:19:

Thank you for your feedback!

I have now merged branch bug-bc602049ab containing a new test treeview-bc602049ab exercising the original testcase with added -width 0 -height 0, and a documentation complement in ttk_image.n about this case. The other changes merged from that branch are cosmetic.

Many thanks to Peter Spjuth again.


anonymous added on 2022-09-04 08:42:34:
Huge thanks to everyone for helping to fix this issue! After all, using "-width 0 -height 0" to fix this unwanted behavior is kind of logical.

Thank you all,
rdbende

fvogel added on 2022-08-29 20:24:16:

Peter, this is simply brilliant, many thanks for your feedback!

After digging into this more and more I came to the same conclusion: my "fix" [d507fe93] is plain wrong, for the exact reason you give.

What I didn't have is the idea to specify "-width 0 -height 0", which solves the problem indeed. How logical and brilliant! The ttk code correctly constructs the size of the treeview from the elements used in its layout. But TreeviewSize() thinks that this size is the size of the padding only. But this is only true until the field element gets reengineered to become an image, like in the original testcase. With such an image field element specified with "-width 0 -height 0" it is still displayed without taking any size in the treeview layout. Brilliant!

Note that in the original script, even just after packing the widget, the height of the widget is wrong (20 pixels too large) too, due to the same cause: the background image has 20x20 pixels size. On 'ttk::style theme use ...', the widget resizes because after its size is computed the calculated width gets entirely redistributed among the (displayed) columns. Then upon next 'ttk::style theme use ...' the width is added once more to the sum of the (displayed) columns widths. And so on. This does not happen for the height because the widget height does not get redistributed among the rows of the widget, but the widget height is nevertheless wrong.


pspjuth added on 2022-08-29 20:22:12:

I think the core of the matter is that the treearea element is a null element and the Treeview kind of fakes things around it. Things like Ttk_LayoutSize and Ttk_PlaceLayout do not get the full picture and thus do not do a consistent job. Now, this is happening within the magic core of Ttk which I no way can claim to have understood yet, so I'm guessing a bit here.

Rewriting the core of Treeview to use a real element might make things better but I do not think it would take things all the way here, and thus not making that kind of effort worth it.

Maybe just accept that an image that is not meant to claim space should use -width 0 -height 0, and update the image factory documentation with this recommendation.


pspjuth added on 2022-08-28 22:22:50:
The only workaround I can find is to do this:

```
ttk::style element create Treeview.field image tvbg -width 0 -height 0
```

thus creating an element that do not request any size.

The proposed change in bug-bc602049ab I do not think can work since it no longer adds the padding and any -padding setting will fail.

fvogel added on 2022-08-25 20:44:54:

I think I have found an error in the code, which was producing this problem.

See commit [d507fe933c]. This fixes the wrong behavior exercised by the original test script.

However this change triggers two failures in the test suite, that I have yet to understand:

==== treeview-9.2 scrolling on see command - bug [14188104c3] FAILED
---- Result was:
0.0 0.9 1
---- Result should have been (exact matching):
0.0 1.0 1
==== treeview-9.2 FAILED

==== treeview-ce470f20fd-4 changing -stretch resizes columns FAILED
---- Result was:
60 50 60 50 58 50 1
---- Result should have been (exact matching):
60 50 60 50 60 50 1
==== treeview-ce470f20fd-4 FAILED

Please test branch bug-bc602049ab and report any weird behavior or regression with the ttk::treeview widget.


fvogel added on 2022-08-20 13:11:58:
After digging a bit into this, I believe this is a conceptual bug. When running "ttk::style theme use ..." a virtual event <<ThemeChanged>> is generated for all ttk widgets.

This event is handled in CoreEventProc (ttkWidget.c lines 308+). This code calls UpdateLayout(), which recomputes the size of the treeview layout using TreeviewSize(). TreeviewSize() calls Ttk_LayoutSize(), which calls Ttk_NodeListSize(), which calls Ttk_NodeSize() as needed for all nodes.

When the treeview widget has no background image, this goes well because the resulting size is zero (or just the padding), leading to a treeview size of the width of the columns: *widthPtr = padWidth + TreeWidth(tv) is simply TreeWidth(tv) in TreeviewSize() since padWidth returned by Ttk_LayoutSize() is zero.

But when the treeview has a background image element added as in the demo script, then the call to Ttk_LayoutSize() (ttkTreeview.c:1650) returns 20 (instead of zero) for both padWidth and padHeight, i.e. it states that the treeview field element has size 20x20, which is the size of the elementary image that gets replicated to fill the treeview background (see "Image stretching" in the ttk_image man page).

Basically, with a background image element the treeview layout size depends on the size of the image displayed in that background. This just sounds like it makes sense, except there is this undesirable effect that the present ticket is reporting.

I'm unsure about what should be done in this situation. Ideas...?

oehhar added on 2022-08-15 19:08:01:

Thanks for reporting.

I can reproduce with Tk 8.6.12

Here is the original github ticket for reference: https://github.com/rdbende/Azure-ttk-theme/issues/40#issuecomment-1215618136