Hello guys,
thinking, how to easily define styles, based on simple selection rules, i sketched the class, MorphStyle. The principle how it works is simple: - you creating a style, add adding actions to it - you then applying style to morph or group of morphs. Example: | style | style := MorphStyle new submorphs model: #Browser; color: Color red. style applyTo: World. Let me describe in detail, what it does, when you applying it: style applyTo: World. Style initializing its current selection to be a collection with single element - { World }. Next thing, which it does is applying any actions , which we specified during building the style, namely: 'submorphs' - replacing the current selection by gathering all submorphs of it, i.e. selection before: #( World ) selection after: #( World's submorphs ) 'model: #Browser' - filter the current selection and leave only those entries, which respond to #model and model class name is #Browser selection before: #( world's submorphs ) selection after: { Browser SystemWindow#1. Browser SystemWindow#2. Browser SystemWindow#3.Browser SystemWindow#4. } 'color: Color red'. - since there's no such method in MorphStyle, it is trapped by DNU handler and converted to a #sendMessage: action. A #sendMessage: action sends a specified message to current selection, i.e.: { Browser SystemWindow#1. .... Browser SystemWindow#N. } do: [:morph | message sendTo: morph ]. So, as result, if you doIt : | style | style := MorphStyle new submorphs model: #Browser; color: Color red. style applyTo: World. all browser windows color will be changed to red color. Some words about potential uses of this stuff. - theming, (through defining own style sheets). In contrast to existing implementation, we're free to define anything, which morph understands , not just colors, border or fillstyle, but also, layout, fonts, position etc etc. - defining styles in various ways: following snippet sets the 'browse' button color to red for all browser windows and illustrating how one style could reuse another one. | browseButton buttonStyle browsers | buttonStyle := MorphStyle new color: Color blue. browseButton := MorphStyle new allSubmorphs; has: #label equalTo: 'browse'. browsers := MorphStyle new model: #Browser. browseButton style: buttonStyle. "browseButton reusing buttonStyle" browsers style: browseButton. "browser style reusing browseButton style" browsers applyTo: World submorphs. It can be easily integrated with Morphic when using some global theme, all we need is: - add Morph>>applyThemeStyles ^ World currentTheme applyStylesTo: self - send #applyStyles to morph, when its added to World. Also, we could integrate it with toolbuilder which will allow us to define morph layouts, fonts, colors & initial properties more flexibly than currently are . Non-morphic builders could just ignore the #setStyles: message. Comments, suggestions , as always welcome. -- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list [hidden email] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project MorphStyle.st (5K) Download Attachment |
+1 The builders and themes don't play nicely at present. There are 35 senders like: window := (SystemWindow labelled: labelString) model: self. So #labelled: creates a SystemWindow and asks the current UITheme to theme it, before it has any information to do so (model is still nil). So having more dynamic styles like this sounds a good way to sort this; I suspect it would also allow some theme related nasties to be removed. ...Stan |
2010/1/16 Stan Shepherd <[hidden email]>:
> > > Igor Stasenko wrote: >> >> Hello guys, >> >> thinking, how to easily define styles, based on simple selection rules, >> i sketched the class, MorphStyle. >> >> The principle how it works is simple: >> >> - you creating a style, add adding actions to it >> - you then applying style to morph or group of morphs. >> >> Example: >> >> | style | >> style := MorphStyle new >> submorphs >> model: #Browser; >> color: Color red. >> style applyTo: World. >> >> Let me describe in detail, what it does, when you applying it: >> >> style applyTo: World. >> >> Style initializing its current selection to be a collection with >> single element - { World }. >> Next thing, which it does is applying any actions , which we specified >> during building the style, >> namely: >> >> 'submorphs' - replacing the current selection by gathering all >> submorphs of it, i.e. >> >> selection before: >> #( World ) >> selection after: >> #( World's submorphs ) >> >> 'model: #Browser' - filter the current selection and leave only those >> entries, which respond to #model and model class name is #Browser >> >> selection before: >> #( world's submorphs ) >> selection after: >> { Browser SystemWindow#1. Browser SystemWindow#2. Browser >> SystemWindow#3.Browser SystemWindow#4. } >> >> >> 'color: Color red'. - since there's no such method in MorphStyle, it >> is trapped by DNU handler and >> converted to a #sendMessage: action. >> A #sendMessage: action sends a specified message to current selection, >> i.e.: >> >> { Browser SystemWindow#1. .... Browser SystemWindow#N. } >> do: [:morph | message sendTo: morph ]. >> >> So, as result, if you doIt : >> | style | >> style := MorphStyle new >> submorphs >> model: #Browser; >> color: Color red. >> style applyTo: World. >> >> all browser windows color will be changed to red color. >> >> Some words about potential uses of this stuff. >> >> - theming, (through defining own style sheets). In contrast to >> existing implementation, we're free to define anything, which morph >> understands , >> not just colors, border or fillstyle, but also, layout, fonts, >> position etc etc. >> >> - defining styles in various ways: >> following snippet sets the 'browse' button color to red for all >> browser windows and illustrating how one style could reuse another >> one. >> >> | browseButton buttonStyle browsers | >> >> buttonStyle := MorphStyle new color: Color blue. >> browseButton := MorphStyle new allSubmorphs; has: #label equalTo: >> 'browse'. >> browsers := MorphStyle new model: #Browser. >> >> browseButton style: buttonStyle. "browseButton reusing buttonStyle" >> browsers style: browseButton. "browser style reusing browseButton style" >> >> browsers applyTo: World submorphs. >> >> >> It can be easily integrated with Morphic when using some global theme, >> all we need is: >> - add Morph>>applyThemeStyles >> ^ World currentTheme applyStylesTo: self >> >> - send #applyStyles to morph, when its added to World. >> >> Also, we could integrate it with toolbuilder which will allow us to define >> morph layouts, fonts, colors & initial properties more flexibly than >> currently are . Non-morphic builders could just ignore the #setStyles: >> message. >> >> Comments, suggestions , as always welcome. >> >> -- >> Best regards, >> Igor Stasenko AKA sig. >> >> > > +1 > > The builders and themes don't play nicely at present. > > There are 35 senders like: > > window := (SystemWindow labelled: labelString) model: self. > > So #labelled: creates a SystemWindow and asks the current UITheme to theme > it, before it has any information to do so (model is still nil). > > So having more dynamic styles like this sounds a good way to sort this; I > suspect it would also allow some theme related nasties to be removed. > In my other experiment, i introduced the modes stack for morphs. Initially, a morph has default mode, but once its interacting with user, its mode stack is changing, and this immediately reflects on morph's appearance. A morph's mode stack explained for a simple button: default default -> mouseover "mouse entering the button" default -> mouseover -> mousedown "user clicking a button" default "mouse leaved the button" now same but for disabled button: default -> disabled default -> disabled -> mouseover default -> disabled -> mouseover -> mousedown Now all we need is to define a style for each mode. The code, which draws the morph then asks a topmost style for some property. drawNormal: aCanvas | padding | " self debugDisplay: bounds corner printString." (mode styleAt: #hasDropShadow) ifTrue: [ self drawShadowOn: aCanvas. ]. aCanvas frameAndFillRectangle: (bounds origin extent: labelExtent) fillColor: (mode styleAt: #backgroundColor) borderWidth: (mode styleAt: #borderWidth ) borderColor: (mode styleAt: #borderColor). padding := mode styleAt: #labelPadding. aCanvas drawString: node label at: (bounds origin translateBy: padding) font: self font color: (mode styleAt: #labelColor). The property lookup semantics is simple: first it looks for property defined for topmost mode in stack, if not found, then it asks mode which lies down the stack, and so on, until it finds it in the default mode style. But that's not all, you can also control a method, which will draw the morph, depending on its current mode. The trick is simple: drawOn: aCanvas "Draw a morph by using method, supplied by current mode" | method | method := mode styleAt: #drawMethod. ^ self perform: method with: aCanvas So, depending on mode & its style it may issue #drawNormal, or #drawDisabled , or anything. A different drawing methods is useful, when you want to change the way how morph is drawn, i.e. draw ellipse instead of rectangle, or draw image instead of text etc. So, with given trick, you can control not only how you drawing the morph, but also what you drawing. I found that mode stack is most flexible way to control the morph's appearance. There is a tons of properties , held by morph, such as #hasShadow which is set by some controller. But the thing is, that this is wrong way to do that , because of the explosion of number of combinations: when you have 10 flags - you have 2^10 combinations. While with mode stack you simply pushing the #dropShadow mode into stack, and with corresponding style you can define new or override existing properties which control the morph's appearance. For example, your code using a #backgroundColor style property: MorphStyles at: #default put: ( SlimCascadingStyle new at: #fillColor put: (Color r: 235/255 g: 227/255 b: 103/255 ); at: #highlightColor put: (Color r: 251/255 g: 242/255 b: 110/255); at: #backgroundColor inherit: #fillColor ) But you want to use different background, when mouse hoveing over the morph: MorphStyles at: #mouseOver put: ( SlimCascadingStyle new " replace background color with highlight color" at: #backgroundColor inherit: #highlightColor; yourself). That's all :) Then code, which drawing the morph always looks clean , because you don't need to put messy things like: self isFoo ifTrue: [ self drawThis ] ifFalse: [ self drawThat]. self isBar ifTrue: [ self drawThis ] ifFalse: [ self drawThat]. ... It would be interesting to combine the 'Styles for Morphic' with 'Styles for mode stack' :) > ...Stan > > -- > View this message in context: http://n2.nabble.com/Styles-for-Morphic-tp4402731p4404007.html > Sent from the Pharo Smalltalk mailing list archive at Nabble.com. > > _______________________________________________ > Pharo-project mailing list > [hidden email] > http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project > -- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list [hidden email] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project |
Free forum by Nabble | Edit this page |