How to migrate to Tile

Now that Tile is at 0.7.5 and all 'compatbility options' have been removed, it is impossible to convert many applications to use Tile with the simple recipe of "namespace import -force ttk::*" and a bit of manual tweaking (this was reasonably possible with Tile < 0.7). In fact even Tk's built in dialogs will throw errors all over the place with such an approach. This page is here to help (hopefully!).

I believe the first lesson in migration is a mental one. Tile is designed to be different. Tk was designed so that everything "just works", but Tile is designed so that you have to follow a strict path to achieve your platform-native look. This means that obvious things you may have learned from Tk are just wrong now. For example:

Eg1: What font does this label have?

Tk: set font [$label cget -font] ; set size [font measure $font $text]

Ttk: error no such option '-font'...

or

Eg2: This widget's a bit cramped, let me give it some more space: $widget configure -borderwidth 4

Ttk: error no such option '-borderwidth'

So you have to recognise that your entire approach will have to be different to cope with Tile. It would have been pretty easy to code Tile deal with most standard options just like Tk does, but the developers appear to have made a conscious decision not to do anything like that. (Note that this page does not attempt to justify why the Tile developers rejected the idea of allowing configuration options to actually work and forced the programmer down the path of using styles for absolutely everything.)

Note: currently most of the answers here are empty. Tile's documentation wasn't too helpful, so I'm hoping that one of the Tile developers might step in with some answers.


Here are some common issues in migrating to Tile, together with their resolutions:

1) Tk's dialogs manually adjust buttons with, for example, '$button configure -relief sunken'. Tile has no '-relief' option. How can a dialog's code programmatically press a button with Tile?

Answer: JE Tk's dialogs do this to simulate a button press for keyboard accelerators. If that's what you're trying to do, then use: [event generate $button <<Invoke>>] That will toggle the 'pressed' state on, toggle it back off after a brief delay, and finally call the button's '-command'. All "activatable" tile widgets support <<Invoke>>, and the keynav package adds <<Invoke>> class bindings for many core widgets.

If you want to simulate a button press without actually invoking it, just toggle the 'pressed' state. This will update all of the element options needed to make the button looked pressed, regardless of the theme or widget style. (This is considerably simpler than in core Tk, where you need to save and restore a number of interrelated options.)

If you're trying to change the -relief for some other reason, then I don't know. It depends on what you're trying to do. (Note that in many themes, buttons don't even have a traditional Motif-style border.)

2) Labels, checkbuttons, etc. all have a variety of wrapping options so text can wrap across multiple lines. How can this effect be achieved with Tile? How can I create a Tile checkbutton widget that has wrapped text?

Answer: JE The 'ttk::label' widget supports most of the traditional Tk options (-wraplength, -anchor, -borderwidth, -relief, etc.). One approach is to configure a 'ttk::label' to act like a checkbutton (... details tbd...)

I assume those details are going to be half a page of code just to mimic an option that ought to be there already. Tk is supposed to be simple - that's why we use it. If I wanted something complex I'd code in a different language.

3) Tk's menubuttons have a '-indicatoron' option. How is this handled in Tile?

Answer: ...

4) I want a red label with a large font to warn a user about something important, but there isn't a -font or -foreground option. How is this done with Tile?

Answer: 'ttk::label' widgets support -font and -foreground; see (2).

4b) The answer to question 4 is a lot of work for just a big red warning label. Isn't there an easier way?

Answer: Use the standard Tk widgets.

APN Unless I misunderstand what you're looking for, I don't think you need to create a style for every theme. For example,

  package require tile
  style configure "WarningLabel.TLabel" -foreground red -font TkCaptionFont
  ttk::label .l -text "This is a warning" -style WarningLabel.TLabel
  pack .l

Now if the theme changes, the label will change with the theme except for the label font and color. Everything else will be inherited from TLabel which Tile will initialize based on the theme.

George Peter Staplin: That fails for me in NetBSD with Tile 0.7.2 (see below).

5) I want Tile widgets in Tk dialogs.

Answer: Rewrite the dialogs or use [insert name here]'s rewrite of the Tk dialogs.

6) I need to find out what font a widget is using so I can both display its name and calculate whether the widget will need several lines to fit a given textual string. How can I determine the widget's font?

Answer: JE By convention, Tile widgets use the symbolic font names defined in library/fonts.tcl. Most use TkDefaultFont; entry widgets use TkTextFont.

But I want to know the font of this widget not the font of some widget's default. My widget may have had various styles configured on it, or the user may have activated my special 'short-sightedness' plugin to temporarily increase font sizes. Surely I can find the font name associated with one specific widget.

JE: If you've changed the widget font and have forgotten what you changed it to, then [style lookup [$w cget -style] -font [$w state] ] might be what you're looking for; it depends on the widget class. Some widgets (notably ttk::treeview, plus the core text, canvas, and listbox widgets) can use more than one font, so the question as posed doesn't have a single answer. But most of the time when people are trying to figure this out, the right answer is still "just use TkDefaultFont."

7) My application is cross-platform. I'd like it to run if Tile is or is not available. How should I takes advantage of Tile when Tile is available, but works just fine when Tile isn't? Given the dramatically different design philosophy (e.g. of something as simple as the 'red label' above), it seems I'm just going to need to have a lot of different tile and non-tile branches in the code.

Answer: ... I think you need a lot of branches in your code and will have to write 2 versions of a lot of gui stuff. In one branch you configure the -style of tile widgets and in another branch you'll configure the various options of Tk's widgets. Of course you can factor some of this stuff into common procs, but you still need a lot of branches and a vast amount of work.

A good starting point is to move widget -option specifications into the option database, leaving just the subset that's supported by both Tile and core widgets in the main code. (YMMV, but for all the applications I've converted this ends up with a net reduction in code complexity.)

See recent releases of Coccinella for a real-world example of a large, heavily-customized Tk application that can switch between tile and core widgets.

8) I want a widget that's just the same as another one, but with a red foreground. How do I manage that?

Answer: Create a new style in every single theme which is the same as your old style but with a red foreground. You can't just configure the foreground colour of a single widget. Why would you want to do that when you have the option of creating half a dozen styles instead ;-)

APN: See my comment on (4) above. Now, if you really want to have widgets with many different colors then you are right in that you have to create a style for each of these setting the fg/bg to a different color in each style as in (4). But I would claim that for this case, you probably don't really want to use a theme-based engine for those widgets anyways and the Tk widgets are a better fit. For example, if you were writing a color-picker widget, you would not use the ttk::label. You would use Tk's label command or a canvas.

9) I have generic code that uses the configure -state to enable/disable a tree of widgets. Is there a way to make tile accept $widget configure -state?

Answer: JE That approach will continue to work with Tile; buttons, checkbuttons, entry widgets, etc., all support a '-state' option that admits (at least) '-state normal' and '-state disabled', as their Tk counterparts do. Couple caveats: the '-state' option should be considered "write-only" for Tile widgets, and beware that reenabling a widget with [$w configure -state normal] can unintentionally turn a readonly entry widget into an editable one (this goes for the core widgets too).

A more robust approach would be to try [catch {$w state disabled}] first (which will work for all Tile widgets), then [catch {$w configure -state disabled}] if that fails (which will work for most core widgets). If that fails, you can assume that the widget isn't disablable. Use [catch {$w state !disabled}] / [catch {$w configure -state $oldState}] to reenable the widgets.

10) I have code that uses tk_getoOpenFile and tk_getSaveFile. They don't use Tile. How can I fix that?

Answer: Try out the File selection dialog for Tile by Schelte Bron. It also has a message box dialog.


SRIV: I hope I'm wrong, but, due to lack of -options, I feel that tile widgets will be useless for building megawidgets. I do understand the goal of creating a native look and feel, which it does nicely.

APN: I think this would depend on the kind of megawidgets you are building. For example, Csaba Nemethi's tablelist package has a tile version which works very well for me. I've also written a couple of megawidgets that clone Windows Explorer - see http://downloads.magicsplat.com/xpthemesample1.png and http://downloads.magicsplat.com/xpthemesample2.png - which combine tile with text and canvas and change when the XP theme is changed. Certainly for some types of megawidgets which expose font, color, etc., tile may not be suitable.

George Peter Staplin: I feel the pain. I was excited about Tile for a while. I converted several applications to use it. Then I upgraded to tile07.kit and found that most of my applications broke. They were unusable.... So, I have removed Tile from all but 1 application -- the Whim window manager. Even there we now have what I consider unnecessary branches that are just tile-specific code. We no longer have the themed dialogs, because every dialog must now be rewritten. After the initial disappointment of Tile 07.x I talked with Joe English and unfortunately he isn't interested in changing things, and now with Tile going into the core it will probably go unused by all but the new apps, or those that pay to have applications converted.

Vince: I'm really struggling to update Alphatk to use the latest Tile. In fact I'm beginning to agree with what you write, George - Tile just isn't suited to updating complex applications. It demands such a different approach that it's only good if that approach is incorporated into the design from the beginning.

SRIV: If you use it such that the OS controls the theme, then you get native looking apps cross platform with little effort. But since you can't predict what the users set theme will look like, you can't really predict what your app will look like, especially when you make megawigets.

APN: To some extent, I feel the above discussion misses the point that Tile is not intended as a replacement for Tk, either now or in the future. If you want your widgets to look like the currently configured theme on the OS, use Tile. For the "client" areas (which are generally not theme-dependent) of the app, use Tk as that's generally more convenient. This is the same as what native apps do. Certainly, changing an entire app to use Tile is (IMHO) difficult, unnecessary and undesirable.

George Peter Staplin: APN, I think you miss the point. The GUI looks like a mismash of different widgets when that's done. Your example of the big red label also fails to work properly. (See below.)

Vince: APN, I also think you miss the point. If Tile is to be useful it has to be usable for an entire app, except for some special cases (e.g., colour picker labels). 99% of widgets in any application are likely to want to be themed (certainly in my applications). So it is desirable to change an entire app to use Tile. If Tile doesn't allow that with a reasonable effort level, then Tile is poorly designed, unless there are compelling reasons to the contrary. I certainly see nothing in TIP#248 to say that migrating an application to tile is supposed to be "difficult, unnecessary and undesirable."

style configure "WarningLabel.TLabel" -foreground red -font TkCaptionFont
ttk::label .l -text "This is a warning" -style WarningLabel.TLabel
pack .l

#
#That's ok, but I want a larger font.
#
style configure WarningLabel.TLabel -font {Helvetica 22}

#
# At this point nothing changes, so I wonder what's wrong?

JE A guess: you're probably using tile 0.7.3 or earlier. Earlier versions included some hacks to stop BWidgets from breaking when the namespace import trick was used. Unfortunately those hacks interfered with custom styles; they have since been removed, and the above works as expected with current (Feb 2006) CVS.

# I decide that tile is probably not updating the widget.
#
.l config -style WarningLabel.TLabel

# 
# Nothing changed, so at this point I decide to try *recreating* the widget (ugh!).
#
destroy .l
pack [ttk::label .l -text "This is a warning" -style WarningLabel.TLabel]

#
# Hmm it's not using my big font.  Oh well.  Let's see if the style is retained after a theme change.
#
tile::setTheme step

JE: This is still a problem: application-defined styles and user-settable themes still don't mix very well. Recent Coccinella releases implement a workable technique for managing this, but it's still more complicated than it should be. A better long-term solution is in the works.

#
# At this point the label loses its red color, and my earlier argument stands. 
#

APN: Wouldn't be the first time I missed a point :-). However, the example you gave above works for me (well kind of). The call to style configure to update the font does in fact result in the font being updated. This is on XP SP2 with Tcl 8.4.12, tile 0.7.3. So maybe this is a platform specific bug? On the other hand, setTheme generates a "package not found" error for me, probably because I hand installed tile and am missing some files.

George Peter Staplin: Ah, so it works in Windows? I guess it may be a bug in Tile, or it could be that you are missing the files that break it. Before I came to my somewhat angsty view of Tile I talked with Joe English about my concerns. Unfortunately based on my interpretation of his responses he wasn't interested, in changing anything. In fact at the time he told me that he thought it was a mistake that Tile is going into the core. Perhaps it's still in the Tcler's Chat logs. It was a public conversation.

I also once asked if we could have -background and -foreground in native Tile widgets, and was told that "it's not possible in Windows." I later found an article in C/C++ User's Journal that had example code for doing so in Windows with the native widgets. I was excited, so I told Joe English about it. He wasn't interested. I even found the code on the C/C++ User's Journal website for him. And KBK also said it was possible. Joe English wasn't interested. So, I'm disappointed now.

JE: More precisely, it's not possible in all themes. You can, with a lot of work, change the background color of Windows XP buttons. But you still can't do it in Aqua (at least, not to my knowledge), or in a pixmap theme. And if you do change the background color there are often a lot of other related colors that also need to be changed depending on the platform (active background, pressed background, border colors, foreground color in the various states...).

It wouldn't be hard to add a -background option, as long as you don't care whether or not it works.

I don't want to discount what Joe has done. He and the others have done something that's pretty good for native widgets, but it's not ideal for me, or the majority of existing applications. Rather than blaming tile or trying to convince the primary author of Tile, or the Tcl Core Team to change things I have decided to work on my own compatible version of themed widgets.

stevel: it works in AquaTk too

Vince: the above example doesn't work on Window XP with latest cvs head of Tile: the last call 'tile::setTheme step' results in a label which no longer has a large font nor red text - those style options seem to have vanished. The earlier stages of the example do work (i.e. the 'nothing changed' comments above don't apply in my testing).


If Tile has become so incompatible with Tk, then should it ship as an extension that is separate from Tk? If I am reading the above comments correctly, as well as comments on comp.lang.tcl, the TCT mailing list, etc. it sounds as if there is little practical use in trying to mix Tk and Tile - the look and feel would be so different as to make the application nearly universally disliked. And with there being less and less compatibility between the widgets, someone is going to have to somehow recreate useful Tk widgets such as dialogs in terms of Tile to get a unified look. So will it now be considered its own extension and shipped that way?

Vince: I would say that the question is "why has tile become to incompatible with Tk" and what can be done to improve the situation. The discussion on the TCLCORE mailing list suggests that (at least some people) believe Tile doesn't need to be so incompatible, and could happily support many standard options. The problem is the extreme design choice that the current Tile makes: "everything is a style." By recognising that Tk's problem was there are no styles, Tile has gone to the opposite extreme (which is equally bad). The middleground is the place to be: some things are options, some things are styles and some things are both.

SRIV: I originally felt the same way. As an early adopter of tile, I was estatic to find that I could make themes and styles that look and function IDENTICAL across platforms. But, as native look & feel became a tile priority, more focus was directed toward this goal, and it is an important goal. Native looking Tk apps have more appeal to serious developers than SAME looking apps across platforms. So now, I realize, that there are two separate needs that need to be addressed. The question is, can we leverage the tools that are the core of tile to do both, or should a separate extension be created for the "SAME look across platforms" theming engine?

Vince: actually my point isn't that I want things to look non-native at all. I have no interest in things looking the same across platforms. My point is that I want to be able to configure some aspects of widgets without having to write a new style everytime: it's simply about the level of effort the developer has to go to, and in particular (given the title of this wiki page) the level of effort you have to go to migrate existing code. There are plenty of options like padding, borderwidths, anchor, wraplength, etc which are, frankly, almost nothing to do with a native look and feel. Tile gets in the way of configuring such options because it insists you use a style to control them. I'm sure sometimes I will want to use a style to control most options (particularly in new code I write), but I'm equally sure I want to simply configure some options like I've always been able to do -- not to make something look non-native, just to tweak a layout or set a different fontsize, or whatever.

SRIV: Good points, I'd probably want the same capabilites too if I were developing native looking apps.


KaKaRoTo: Hi All, I'm KaKaRoTo, admin and developper of the aMSN project (http://amsn-project.net ) which is a Tcl/Tk application. We always had a lot of questions about the look and feel of Tk, and requests to use GTK, which is impossible for us to do, so I wanted to use Tile to make aMSN look better. Of course, I bumped into this problem of having to rewrite the whole application in order to get it to work with Tile, which is undoable. It turned out my project of a "simple plugin" that would load Tile became a project involving wrapping the whole Tile widgets to make them compatible with Tk widgets. This involved a lot of work, and it's not yet finished, but for many widgets, the work is done and the Chameleon plugin (the project I work on) seems to be stable enough for everyone to use. I was able to create a common interface to ease the wrapping of the widgets, and now I have the following widgets wrapped :

  • button
  • frame
  • labelframe
  • label
  • radiobutton
  • checkbutton
  • entry
  • menubutton
  • scrollbar (not tested).
  • combobox (wrapped from widget : )
  • notebook (wrapped from BWidget's NoteBook)

And the following widgets are still to be wrapped :

  • panedwindow
  • progressbar
  • dialog/message box
  • scale

It looks pretty good so far.

I understand why Tile wanted to remove the compatibility, only problem is that for a huge application like aMSN (more than 52 000 lines of Tcl only code + many megawidgets we wrote), we feel the need for such things as the compatibility options (example, the -background option on frames, the -relief option of buttons, etc...). Hopefully those options are available through a custom style, and I used that to keep the compatibility.

My plugin will wrap Tk widgets, will do the wrapping from Tk's options to tile's widget/style options, will also reimplement some of the commands of the widgets and use tile's capabilities for it (example, the flash or toggle command of checkbuttons, or options like unexisting -variable option on checkbuttons or radiobuttons), and will make any Tk application work with Tile, keep all the fancy fonts/colors/backgrounds you set on your widgets and requires no effort/rewrite whatsoever. It will also recursively set the background color of toplevel widgets to the same bg color of a tile's frame depending on the theme you use, so labels/frames will blend in correctly inside Tk's toplevels. You can see for yourself by viewing this forum (with links for screenshots) : http://amsn-project.net/forums/viewtopic.php?t=618

Once my plugin is finished, I will make it available, please tell me if you're interested in using it by writing me at : kakaroto AT kakaroto DOT homelinux DOT net

Thanks.

*Looks impressive, great job!!! Which license is it distributed under? Any chance it can be distributed under Tcl/BSD license? I would love this to be included with the core. How to do you get QT/GTK compatibility? Does Tile support that?

KaKaRoTo: Hi, thx for the comment, The license used is I guess GPL, not sure since I know nothing about licenses, in short, what I think is that you can use it freely (a reference to me in the credits of your app would always be nice but not mandatory). I don't think it will be included in the core, since it has nothing to do with the tcl core. Also, it's a pure tcl thing, so you don't need to patch Tk or compile anything, so you can distribute it with your application as if it were part of the app (only .tcl files). But you still need Tile for it to work, which I think will be included in tk 8.5 core, but I'm not too sure about that. About QT/GTK compatibility, it's not real QT, nor real GTK, only themes widgets which can have the same look and feel as QT or GTK. Indeed, Tile takes care of that. Contact me at the adress above if you want a copy of the code, you may also be the first one to test the package on a project other than aMSN (which might rise bugs that weren't visible through aMSN). Thanks and take care.

Lars H: The big problem with a GPL license for something like this, from the Tcl community perspective, is that it forces all code making use[1] of it to be GPLed as well, which for many is not an acceptable option. The issue is not whether to go Open Source or not, but about the freedom to choose other legal implementations of this than the GNU one. ([1] Yes, there are technicalities about dynamic linking and whatsnot that can weaken this a bit, but if distributing a program containing this package, then you're probably forced to GPL the whole thing.)

Concretely, a package of pure Tcl code for Tile backwards compatibility with Tk is a typical candidate for putting into tcllib, but this requires that you use the less restrictive Tcl (BSD-style) license. Note that as long as you're the sole copyright holder for a work, then you can at any time decide to offer a new license for it.

KaKaRoTo: Hi, Thanks Lars for clarifying things. As I said before, I'm not that much into licenses, I said GPL because aMSN uses GPL and I created it for aMSN. My main objective is to help people like me, so I guess a BSD license would be the way to go. I have contact with Pat Thoyts from tcllib, so I'll ask him what he thinks and propose as you suggested for it to be included in tcllib. For now, it is without any license, and you guys can try it out as much as you like.. you can get a copy of it from : http://kakaroto.homelinux.net/~kakaroto/chameleon.zip I have in there a version of the plugin that should work with a 'package require Chameleon', you can then change the theme using ::chameleon::ConfigurePlugin (iirc), and don't use ::tile::setTheme (or else, it won't change the background color of the toplevels and the theme won't blend in). The code should be generic and work for any Tcl application, but it was never tested on another application apart from aMSN, so it would be nice if I could get as much feedback as possible. Joe English reviewed the code a bit and says it's the way to go, and he's very interested in the plugin. I'll keep you informed, please post any bugs you encounter with it.

Thanks.

Kevin Walzer: I have tried this with the Mac version of aMSN--very impressive. If I understand the purpose of Chameleon, it's to provide a "bridge" between Tk and Tile widgets, so that it might make migrating a legacy application easier? So that I can take a pure Tk application, add the Chameleon package, and with minor tweaking, the Tk widgets will be mapped to Tile? If so that would be incredibly cool. One thing I did notice is that the version that is linked here for download is very tied to aMSN's coding conventions and specific packages: I tried to plug in Chameleon to a random Tk app I have on my machine (TkDiff) and TkDiff crashed with the error message "can't find package amsn_bwidgets". I assume a version of Chameleon prepared for general usage will have stuff like this refactored?

KaKaRoTo: Yeah, sorry about that, it slipped throught my code conversion.. if you rename the package require to BWidget instead of amsn_BWidget (which is Bwidget slightly modified to fix some bugs we encountered with BWidget), then you're done.. assuming you have BWidget.. I've updated the version on my website, so you can retry it if you want. Also, for Mac, you should disable the wrapping of label, frame, and labelframe (remove their reference in the variable wrapped_procs in chameleon.tcl), because those widgets in Mac have a special stripped background and won't fit in if you use Tile.. Anyways, I also did it now in the version on my server, so you should be ok..

Ben Dunbobbin: Dear all, What is the status of the the chameleon plugin? Are there any other attempts at providing compatibility between tile and tk widgets? If there isn't would it be worth making the chamelan code a core part of tile? Thanks, Ben.

KaKaRoTo: I'm back, and sorry for not giving news for so long.. Chameleon has been improved over the time, and I now have a 'package require-able' version, it will hopefully be maintained at the same time as the amsn version since it's a unique file being used for both, instead of being two separate versions. You can download it at http://kakaroto.homelinux.net/~kakaroto/chameleon.zip and you can try it by simply adding the following line in your scripts :

  package require Chameleon

once the script you launched it with is idle (using the event 'after idle' ) it will wrap the tk widgets into tile widgets (this should give you enough time to read your program's configuration and set chameleon's options like which widgets to wrap and which theme to use for example). If you want it to wrap the widgets right away (because you build your GUI in the initial script for example), you can simply call ::chameleon::rewrap. To configure Chameleon, you can use the helper proc

  ::chameleon::ConfigureChameleon

it will open a window with options. You can also configure it programatically by looking at the variable ::chameleon::config().

If you want to see the debug output (very little output) you can specify a command for this by calling ::chameleon::SetDebugProc $proc, so it can be

::chameleon::SetDebugProc puts

or

::chameleon::SetDebugProc [list .my_debug_window.text insert end]

Finally, if you want to translate some of the fields, like the 'theme' or 'widgets_to_wrap' labelframes of the configure window, you just need to implement a function named 'trans' that translates one of those keys into the string that you want...

To test what Kevin Walzer said, I just tried this new version on TkDiff, and it works fine, I just added these 3 lines in the begining of the tkdiff file, right after the package require Tk :

package require Chameleon
::chameleon::rewrap
::chameleon::ConfigureChameleon

and it worked right away.

If you want to follow up with the development, you can always get the latest SVN version of Chameleon from this URL : https://svn.sourceforge.net/svnroot/amsn/trunk/amsn-extras/plugins/chameleon

Note : This has not been tested and may not work with the tcl/tk 8.5 version that has tile included. Any patches are welcomed (as long as it doesn't break compatibility with tcl/tk 8.4).

Any comments are welcomed of course (you can contact me at kakaroto AT kakaroto.homelinux.net).


LV: So are you saying that, with Tile and Chameleon, you track GNOME themes relatively well? That seems like something that perhaps should be considered part of Tk, if it makes using Tile easier.

KaKaRoTo: Hi LV, I'm not saying that we can track GNOME themes easily, actually, Tile has a theme 'tile-qt' that makes it integrate fully with QT, but there is no theme 'tile-gtk' that would make it integrate with GTK (but I think that there is a way to tell QT itself to integrate with GTK, but I'm not sure). What Chameleon allows you to do is only to use Tile in your application without any code modifications, to see what it will enable your Tk app to do, you'll need to see what Tile allows you to do, Chameleon is mainly a bridge between Tile and Tk, nothing more.

George Petasis: As of august 2008, there is also a TileGTK theme [L1 ].