Hi, there! :-)
TL;DR: Here is a SAR file that cleans up the code of all widget classes such as lists and buttons in your image and adds support for UI theming as well as a bunch of UI themes (choose Themes via "Extras > Themes & Colors"): squeak_trunk_uitheme_v12.sar http://forum.world.st/file/n4908439/squeak_trunk_uitheme_v12.sar
Here is a preview: http://i.giphy.com/l46CcX46yRE9H6yQ0.gif
*Try it out. Report bugs. Report performance issues!!* We will commit the changes to trunk this Saturday.
Btw: The SAR installer is compatible with Eliot's current working image. ;o) And there are numerous open windows and projects in that image...^^
========================================== 0. The Long History of Squeak & UI Theming ==========================================
... http://forum.world.st/Dark-theme-td4869082.html http://forum.world.st/Themes-for-Squeak-5-1-td4882848.html http://forum.world.st/Skylark-Theme-and-Squeak-3-9-td54720.html http://forum.world.st/Non-SmallLand-colour-theme-lying-around-td4697438.html... ...
======================== 1. User Interface Themes ========================
Chris, Karl, and I designed a very lightweight abstraction to support UI themes in Squeak. You can find the whole implementation in the class UserInterfaceTheme and a bunch of tests in UserInterfaceThemeTests.
An object that wants to support theming SHOULD (!) implement three methods:
MyFancyClass class >> #themeProperties MyFancyClass >> #applyUserInterfaceTheme MyFancyClass >> #canApplyUserInterfaceTheme
It also MUST (!) access the current UI theme when setting visual state. And here comes the nice part:
... self color: (self userInterfaceTheme color ifNil: [Color white]). ...
Remember, usually you would write something like this:
... self color: Color white. ...
How can this work? It works by using #doesNotUnderstand: and trigger a dynamic lookup in a dictionary inside the current theme:
Object >> #userInterfaceTheme ^ UserInterfaceTheme current pushScope: self; yourself
UserInterfaceTheme >> #doesNotUnderstand: aMessage ... ^ [self get: scope top class -> aMessage selector] ensure: [scope pop]
Isn't this slow? No, not at all. If you have any doubts, try benching it on your machine:
UserInterfaceThemeTestObject benchLookup.
On my machine, this is even fast enough to support theme lookups in frequently called messages such as Morph >> #drawOn:. However, applications are advised to cache. That's why we have the explicit #applyUserInterfaceTheme callbacks as described above.
Note that amazing effects can be achieved by adjusting #color, #borderColor, #borderWidth, #fillStyle, and fonts. :-) The existing themes do exactly that.
To get a feeling of the impact of having themes in Squeak, try browsing senders and implementors of #applyUserInterfaceTheme, #themeProperties, #userInterfaceTheme, and maybe #canApplyUserInterfaceTheme. I think we can still reduce the number of sends to #userInterfaceTheme a little more.
================================== 2. Code clean-up in widget classes ==================================
We made Shout look up the current theme to build its internal cache of text attributes to quickly style code as you type it.
We removed window color specifications and replaced them by simply implementing Model >> #defaultWindowColor. There is also still the #uniformWindowColor if you do not like colorful windows. This makes it also much easier for new applications to have their own window color.
We unified the implementation of MenuMorph and DockingBarMorph and fixed several bugs there.
Dialogs! *phew* ... *arrrrgss* ... Dialogs. :-) We managed to introduce a general DialogWindow class. FillInTheBlankMorph and UserDialogBoxMorph are now mere subclasses with a custom interface. There is also support for ToolBuilder, see ListChooser for an example. *yay*
Buttons feel more like buttons now. It's a good thing, right?
For lists and trees and text boxes, we greatly reduced the amount of code that just accessed global state. LazyListMorph, NewParagraph, TextMorph, IndentingListItemMorph, ... they all now get configured by their "hosts", which are PluggableListMorph, PluggableTextMorph, and SimpleHierarchicalListMorph. Having this, we improved the modular structure of our whole Squeak widget library. That modular structure made applying themes much easier. :-)
======================== 3. Theme all the widgets ========================
There is a nice existing pattern with the message #setDefaultParameters, which is usually called from #initialize. Go, see for yourself. Browse implementors of #setDefaultParameters. We used that pattern and cleaned up many implementations of that message in the image.
Note that rounded corners, gradients, colorful windows, and shadows are still preferences outside of UI themes. You can toggle them in any UI theme.
Note that the background color/image is also not subject to be themed. Just drop your favorite picture or pattern in the image. It's really easy.
Now, take a look at the class SqueakTheme. There, you will find source code for creating the default Squeak theme to be shared via SqueakSource and reset during the release building process. :-)
Besides get/set/clear -- which might be expected from the theme structure because it is basically a dictionary with some properties -- There, you will notice a "merge" or "link" or "derive". When creating themes programmatically, you can: - derive properties from other properties - link themes to extend property look-up - merge one theme into another theme
How does property look-up work? Well, see UserInterfaceTheme >> #get: 1. Look up the key, which is usually "Class -> symbol". 2. Try the superclass chain. 3. Try the same lookup in the linked theme if any.
Theoretically, you could actually implement messages in subclasses of UserInterfaceTheme and bypass that DNU-triggered lookup. We do not do this right now.
As you can see, Squeak/Smalltalk offers a great deal of flexibility. It is remains subject to discussion of how to employ the language and its semantics. Think of the current implementation of user interface themes as one way that represents a trade-off between a concise programming interface (i.e. ... self userInterfaceTheme color ifNil ...), a fair amount of comprehensive patterns (i.e. #setDefaultParameters, #applyUserInterfaceTheme, ...), and some other existing constraints (i.e. old code, Monticello/Squeaksource, existing tools such as senders/implementors, ...).
Happy Squeaking!
Marcel, Chris, Karl
-- View this message in context: http://forum.world.st/ANN-Widget-Refactorings-UI-Themes-for-Squeak-tp4908439... Sent from the Squeak - Dev mailing list archive at Nabble.com.