Philip Quaife 20 Jan 05
This review is of the developer release 0.5. As such the documentation is meant as an overview rather than a definitive guide.
I also do not know what the final form this package will take so some of the findings may not be relevant when actually released.
Hopefully after reading this you will have a better understanding on what to expect from the tile package.
As always, all care , no responsibility.
This is a binary extension that compiles for most sane platforms. Under Linux (and other Unix platforms) there is the usual configure ; make all install.
I tried to run the demo without installing the tile package. Unfortunately the function tclFindLibrary does not look at ., auto_path , tcl_pkgPath, or tcl_libPath, so the demo could not find the library files without being installed.
This is caused by bug #695441, which has finally been fixed in 8.5, and should work in 8.4.8 as well.
How it works
The documentation is somewhat sparse so what I write here is my interpretation of the workings.
The Themed Widgets have been split into two parts in what can be broadly described as the decoration and actual widget. How the decorations are drawn is no longer fixed by the widget.
Instead of the widget drawing everything from the border, background, background image, and then the contents, they now just create an element that is the core function of the widget.
The widget now concentrates on managing the data and function rather than how it appears on the screen.
For example, an entry widget is functionally a text box with an ibeam cursor when it has the focus. The entry widget does not know about borders, backgrounds, labels, or images that may appear on the screen with the entry text.
So these widgets themselves and a number of generic display units which are called elements are what appears on the screen.
By way of example , a scrollbar widget could be made up of the elements:
border, trough, thumb, arrows, text, and even images.
In fact there is no limit to the type and number of elements that are used to make the visual representation of a widget. If you wanted to have a slider that has six left arrows, two thumbs, and four images than there is nothing to stop you, other then good taste and sensibilities.
While there is separation between function and form, it is not as great as paradigms such as Morphs or MVC. The implication of this is that further down the track we will see that changes to the implementation will be required to implement new visual effects.
The separate parts
1. The Widget itself.
A ttk::button widget looks much like a button widget when it comes to progamming within tcl. It however takes a much smaller list of options. All options to do with stylistic features have been removed.
These are specified much like options in the option database in another part of the style system.
Visual properties such as colour, padding, alignment, and size can be specified as defaults for each Widget class and also Heirarchies of Classes much like the option database.
This creates a more consistent look between widgets and it now takes more effort to alter the appearance of a single widget. Hopefully this will encourage programmers to structure their displays so that they are more amenable to customisation by the end user.
3. The layout.
Each widget has a layout that can be changed by the theme. This describes which elements are used to draw the widget. The arrangement is loosely modelled on the pack manager. Using a subset of the pack options, you can state that there should be a leftarrow element on the left of the text element, a rightarrow element at the far right, and underneath this a happyface element.
4. The Elements.
The elements are invariably coded in C and are currenly part of the tile package. While the elements are not bounded to any particular widget, we find that they are declared in the code that is most likely to use them.
We also find that each theme declares the same element but has a different visual representation of this element. This means while all scrollbars have a thumb element, the way it appears on the screen is determined by more than just the style settings at the script level.
This allows for differences such as buttons with rounded or square corners. It allows, for example, round buttons or even ones with arbitary regions.
The principle reason for having multiple renderings seems to be to support native look and feel. Having not run the code under Windows or OSX I cannot say how the native themes are implemented. This could be a source of inconsistant behaviour between platforms particularly with event bindings.
Maps allow dynamic changes to the visual appearance of the widgets or widget classes. The forementioned state flags can be associated with any widget property (eg -forecolor, -image, -text) and a change of state flags will cause the map to be searched for the corresponding value and the widget property is updated on the screen.
In essence a theme represents a collection of the above layouts, maps and stylistic (property) settings for each class of widget. There is only one theme in effect at any one time.
Unlike the present widgets under Tk, when you switch themes, the widgets are redrawn automatically with their new look.
Themes can be based on other themes in what OO would call a single inheritance methodology. Any property that cannot be located in the current theme will be searched for in its parent. This will continue to the root theme which has the standard defaults for all widgets.
Dynamic style changes through state changes
A new concept is that a widget can have more than one state active at any instance. This is known by the unfortunate name of a state bitmap. A less confusing name could be a bitmap of flags or a flag map as it has nothing to do with TK bitmaps.
Ed. Note: The official term is actually "state map". Suggestions for a better name welcome.
These flags can be set and reset individually. They are used to implement dynamic style changes such as changing the background image on Mouse entry and exit, or when becoming disabled.
Another new feature is the style map function. This allows any attribute such as foreground colour, background image, border mode to be changed when the state flags are changed.
The map command takes an attribute and a list of flag and value pairs (like a dictionary). Each flag can be either a single flag, the negation of a flag or the boolean conjunction of a number of flags.
Rather than go into complex examples, trust that the combinations of flag bits make it possible to animate a widget based on any likely combination of conditions.
Key and mouse bindings
Event bindings are as always bound to a widget. Within the binding the script can query the widget to see what element the mouse was over when the event was generated and select different actions for different parts of the widget.
Can you do funky things with the widgets
Yes. However it will take some experimentation with the layouts to get the desired look.
I attempted to create a collapsable frame class with an arrow element along with a label for the frame without success.
No amount of reordering or packing with children could generate the desired effect.
I even managed to get the children of the frame to be drawn outside of the frame border at one point!
The good thing was that I could add a -text attribute to this frame class and have it appear on the screen in the label element even if not in the right position. Even though the frame element was not expecting a -text option, somehow magic happened. I hope this is an intended feature.
The normal cases of attaching images and extra buttons to a widget's appearance will however be less of an ordeal I expect.
You may even be able to create widgets with embedded scrollbars if you wanted for special cases. I don't think that this would be an intended use of styles but someone will come up with a neat use of such a feature, so it is good not to have limits where none are required.
What about gradients and transparant images
I was suprised not to see a gradient background element among the list of elements created thus far.
While an image can be tiled or stretched (I assume the basis for the package) to create gradients for buttions and such, there is no background element that will do this. There appears no impediment to do this, other than the current code does have a propensity to automatically clear the widget's bbox to the background colour in the default case rather than use a background element that the user can choose to include or exclude from the layout.
While transparant images are supported, in the current implementation they insist on drawing a background. This would preclude a layout from having two or more transparant overlapping images as a background.
You will have to wait for tile/2 or tile3D before you see alpha blending.
Does this mean I can put a background image on a text widget or frame
Yes for a frame. It may not be possible for a text widget (and others). Specifying a null background attribute in a style means search the parent for the value of this attribute. Any widgets packed over the top of a background image will always clear their bbox to their background colour so the look will not be as good as one would hope.
Hopefully this behaviour will not be present in the released version.
What is missing
You cannot delete styles and layouts so developing a new layout or style is a pain. This will be a needed feature in the release version.
[Vince inserts that at least one Tile developer has concluded that 'quit and restart' is a suitable resolution of the above pain, and therefore there is no problem! See [1 ]. I also agree this is a needed feature, but apparently it is not so obvious to those working on Tile.]
[Is this a suggestion that to change styles, one would need to quit and restart the application? I surely hope that was not a serious suggestion.]
It is assumed that all the standard widgets will be available as themed versions in the release version (tk 8.5). Visually it is worse to see unthemed windows pop up over themed ones that it is to have all widgets looking ugly but uniformly so.
While a widget can have multiple instances of an element, the widget binding cannot determine which instance generated the event. This means that each element must perform the same function.
JE The main rationale for this is scrollbars: for example, if you have an OSX-style scrollbar with two uparrow elements, they should both perform the same function, so scrollbar identify doesn't distinguish them. However, if you want to create a layout with two identical elements that perform different functions, you can use style element create from to duplicate an element definition under a new name.
The fact that they are new widgets rather than modifications of the originals means more code rewrites. From past experience the TCT will be unlikely to release a compatibility library with the new widgets so that existing code will look and act the same and to get the new themes you will have to rewrite your code.
More importantly it means that any extension to Tk that has created their own widget (like tkhtml, tkZinc) will have to be rewritten to use the new theme system.
JE Not necessarily (although the theme engine does tend to make things a lot easier in my experience). Complex "owner-draw" widgets like tkZinc, or the text and canvas widgets, really don't benefit much from themability, so there's no reason to rewrite them.
I could not test the Win* themes as they are not compiled into the Linux version (for obvious reasons). It is inevitable that applications will be released with the first line of code requesting a nonexistant os-dependent theme causing an application error. Themes like font requests should not generate errors; rather they should just select the best available theme or do nothing.
As of Tk 8.5, Tile is a part of the Tk core under the ttk namespace.