from preamble:
"Change Set: TicTacToe Date: 27 April 2003 Author: Ingo Hohmann
Just a little Morphic project - to learn Squeak, Morphic and so ...
It implements a two player TicTacToe game.
And of course, I hope to get this thing right. "!
ingo@2b1.de writes: You asked: How can I make it resizable?
I am a newbie myself, but this is what I'd do:
You need to draw your TicTacToe fields with respect to the owning Morph (the TicTacToe). Therefore the TicTacToe field needs to know its row and column and thus needs 2 more instance variables:
BorderedMorph subclass: #TicTacToeField instanceVariableNames: 'mark row col ' classVariableNames: '' poolDictionaries: '' category: 'IHO-Learning'
You then initialize them by passing row and column. And you can forget about all other geometry stuff during initialisation because the TicTacToeField will take care of that:
TicTacToe>>initialize | temp | super initialize. self extent: 300 @ 300. turn _ 0. winner _ nil. 1 to: 3 do: [:x | 1 to: 3 do: [:y | temp _ TicTacToeField new row: y; col: x. self addMorph: temp]]
Next thing is to compute the real geometry of TicTacToe field. Lets put this into an extra method:
computeLayout | height width posx posy | height _ (owner height / 3) asInteger. width _ (owner width / 3) asInteger. self extent: width @ height. posx _ self col - 1 * width. posy _ self row - 1 * height. self position: owner position + (posx @ posy)
This has to be called before we draw the field, so:
drawOn: canvas | markBounds | self computeLayout. super drawOn: canvas. mark ifNotNil: [markBounds _ self bounds scaleBy: 0.75. ... etc.
HTH
On Sunday 27 April 2003 04:39 pm, Martin Drautzburg wrote:
ingo@2b1.de writes: You asked: How can I make it resizable?
Using the ProportionalLayout is probably the easiest way.
For instance, try this in a Workspace:
field _ RectangleMorph new extent: 300@300; openInWorld. field layoutPolicy: ProportionalLayout new. 1 to: 3 do: [ :row | 1 to: 3 do: [ :col | field addMorph: (RectangleMorph new color: Color red) fullFrame: (LayoutFrame fractions: (((row - 1)/3.0 @ ((col - 1)/3.0)) extent: 0.333@0.333)) ] ]
On Sunday, April 27, 2003, at 06:11 PM, ingo@2b1.de wrote:
from preamble:
"Change Set: TicTacToe Date: 27 April 2003 Author: Ingo Hohmann
Just a little Morphic project - to learn Squeak, Morphic and so ...
It implements a two player TicTacToe game.
And of course, I hope to get this thing right. "!
Ingo,
I have tried your game and for anybody else that's also still getting to grips with Morphic I've posted my comments here...they are related to your comments in the Transcript window after installing the code.
DRAWING A CROSS: I've modified your drawing code to draw the red mark as a cross instead of a circle...
drawOn: canvas | markBounds | super drawOn: canvas. mark ifNotNil: [markBounds _ self bounds scaleBy: 0.75. markBounds _ markBounds translateBy: self center - markBounds center. "In my working Version of Squeak (3.5+something) there is a Rectangle center: but in the clean 3.5 it seems to be missing, why?" mark = 0 ifTrue: ["canvas fillOval: markBounds color: Color red" canvas line: markBounds topLeft to: markBounds bottomRight width: 5 color: Color red. canvas line: markBounds topRight to: markBounds bottomLeft width: 5 color: Color red] ifFalse: [canvas fillOval: markBounds color: Color green]]
MAKING IT RESIZABLE: You are close! The way you draw the TicTacToe field morph means it will scale. You can try this by using the resize halo to stretch it and you will see what I mean. That's good. However, to make it truly resizable you need to change the TicTacToe class to use a table layout. I won't give that away here, I'll leave it as an exercise to the reader. It ain't that hard! Study the ChessMorph>>addButtonRow, or look for 'references' to AlignmentMorph (195 in my image, plenty to choose from! ) and you will soon get the hang of it! The sheer beauty of Squeak/Morphic is you can twiddle all of it on live objects to see what happens. If you still can't figure it out, mail me off-list.
WINNING CONDITION CHECKING: Welcome to game programming. Messy sometimes. Given the way that you have implemented the game, this is as good a way as any for testing for a completed line. Me being a bit-basher would have probably have maintained two 16-bit numbers, one for each player with bit0 for submorph at:1 etc and then used bit-masks to test three bits at once, the bit patterns having a 1 set for the presence of a mark at that position. Assumption: only one mark occupies the same square! Any hard-core AI types care to offer a solution?
DISPLAYING A WINNING MESSAGE: A cheap and cheery solution would be to replace the bottom of TicTacToe>>setMark with this:
ifTrue: [winner _ (turn \ 2) asString. Transcript show: 'Player ' , winner , ' wins'; cr. self showBalloon: 'A WINNER Player' , winner , ' has won' hand: nil]
It get's the message over and it takes care of removing itself as well!
Sean Charles.
Thanks Sean Charles and all others,
I am answering especially to this one, because ...
Bibbers wrote:
"Change Set: TicTacToe Date: 27 April 2003 Author: Ingo Hohmann
<..>
DRAWING A CROSS: I've modified your drawing code to draw the red mark as a cross instead of a circle...
<..>
canvas line: markBounds topLeft to: markBounds bottomRight width: 5 color: Color red. canvas line: markBounds topRight to: markBounds bottomLeft width: 5 color: Color red]
... now you can kick me ... I was so engulfed in Rectangles and Ovals, I didn't even think about using a Line!
About the winning checks, I first tried to use solely and: and or:, but then decided to write equalTo:and: at least it looked a little less messy (and worked ;-). Given the data structures I used, would there have been a better way?
Kind regards,
Ingo
PS: Do you think a version with all those changes from the list would be worth publishing as a newbie project for others to learn?
On Monday, April 28, 2003, at 02:34 PM, Ingo Hohmann wrote:
... now you can kick me ... I was so engulfed in Rectangles and Ovals, I didn't even think about using a Line!
Fog happens. I could tell you about the time a mate and me spent forty minutes wondering why the 'new' hard disk wouldn't boot...the answer...it was a CD-ROM. Long story, too painful to recount!
About the winning checks, I first tried to use solely and: and or:, but then decided to write equalTo:and: at least it looked a little less messy (and worked ;-). Given the data structures I used, would there have been a better way?
What is 'better' grasshopper? Your way works and is readable and understandable. Works for me.
PS: Do you think a version with all those changes from the list would be worth publishing as a newbie project for others to learn?
Yup. At the risk of trumpet blowing, if you visit http://www.bumpybibbers. com and then follow the SPLASHWORD link on the left hand side, you'll see a taster for a full multi-media game I've written using Squeak. Finished it last year. It plays pretty good. It's not there for download as the only way I can package it is on CD because I used morphs glued together and saved i.e. I've strayed from the path of declarativeness! I only have a crappy modem link and the total upload size is about 25MB so it won't be there this week! The entire site is a work-in-progress as there is never enough time...
Sean Charles.
Hi Sean,
Sean Charles wrote:
On Monday, April 28, 2003, at 02:34 PM, Ingo Hohmann wrote:
<..>
About the winning checks, I first tried to use solely and: and or:, but then decided to write equalTo:and: at least it looked a little less messy (and worked ;-). Given the data structures I used, would there have been a better way?
What is 'better' grasshopper? Your way works and is readable and understandable. Works for me.
I just thought there might be something like, e.g. ifAll: [ "do something"] that may be sent to a block, and evaluates the "do sth" block, if all expressions in the receiving block return true, or something like that which I don't know of
Yup. At the risk of trumpet blowing, if you visit http://www.bumpybibbers. com and then follow the SPLASHWORD link on the left hand side, you'll see a taster for a full multi-media game I've written using Squeak. Finished it last year. It plays pretty good. It's not there for download as the only way I can package it is on CD because I used morphs glued together and saved i.e. I've strayed from the path of declarativeness! I only have a crappy modem link and the total upload size is about 25MB so it won't be there this week! The entire site is a work-in-progress as there is never enough time...
Just send it to me by email, and I'll upload it for you. ;-)
About the resizing code in ChessMorph>>addButtonRow, I still haven't figured out _why_ it works. Well, tomorrows another day.
Regards,
Ingo
By pictures, I mean images loaded from jpg, gif, and png type files so I can get them again.
I'm trying to put together a sar file for a goodie I'm doing and am wondering what is the best way to include a couple background patterns.
I thought I might load them and stash them in some class owned Dictionary via:
SomeClass at: #sometexture putInfiniteForm: (InfiniteForm with: (self zip fileInMemberNamed: 'sometexture.gif'))
but then I started wondering if there was a common facility for storing this kind of thing.
-Todd Blanchard
I'm starting to find out where the code hooks into Morphic are. I found #fullDrawOn:, which looks like the place to put my drawing code for a pane. But I have a few simple questions.
(1) Is this the only drawing hook? What's #drawOn: for?
(2) The canvas argument my pane is passed does not seem to be clipped to the pane. This surprised me. Is this the right behaviour? Am I supposed to do my own clipping using something like #clipBy:during: ?
(3) I noticed that when my window is first creatd and displayed, #fullDrawOn: is called three times. This seems excessive. :) I'm used to battling the Windows API to stop unnecessary extra WM_PAINT messages. Am I up against the same kind of thing in Squeak?
(4) Squeak seems to have problems coping with errors during the execution of #fullDrawOn: - I get a stack dump to the screen instead of a debugger, and the image usually dies. This makes code here hard to debug. Is there a general approach to debugging drawing code to work around this?
Thanks for any help anyone can give. :)
Cheers, Paul
On Monday 28 April 2003 08:53 am, Paul Chapman wrote:
I'm starting to find out where the code hooks into Morphic are. I found #fullDrawOn:, which looks like the place to put my drawing code for a pane. But I have a few simple questions.
(1) Is this the only drawing hook? What's #drawOn: for?
You probably want to override #drawOn: instead. #fullDrawOn: also takes structure into account; unless you don't need or want to draw your submorphs you shouldn't have to override it.
(2) The canvas argument my pane is passed does not seem to be clipped to the pane. This surprised me. Is this the right behaviour? Am I supposed to do my own clipping using something like #clipBy:during: ?
Do you have clipping turned on in your Morph? And in your Morph's parents? You talk about a "pane"; does this mean that your Morph's parent is a SystemWindow? Have you tried turning on clipping on the SystemWindow? Usually the canvases that we render to have clipping turned on.
(3) I noticed that when my window is first creatd and displayed, #fullDrawOn: is called three times. This seems excessive. :) I'm used to battling the Windows API to stop unnecessary extra WM_PAINT messages. Am I up against the same kind of thing in Squeak?
Are you doing something like creating your Morph, then setting the extent, then moving it? Each change to the bounds or position can result in a repaint.
(4) Squeak seems to have problems coping with errors during the execution of #fullDrawOn: - I get a stack dump to the screen instead of a debugger, and the image usually dies. This makes code here hard to debug. Is there a general approach to debugging drawing code to work around this?
You can often type "exit" or "revert" at the emergency debugger and have the right thing happen. Though there are some places in the code that should be wrapped in exception handlers and aren't.
As I said some time ago:
So I'd probably try replacing the call to displayWorld in SystemWindow>>passivate with displayWorldSafely, which *does* have proper error handling.
and:
It looks to me like #displayWorldSafely should be called from most of the places that #displayWorld is, but I haven't really analyzed it.
Ack! :)
Why am I having so much trouble making a subpane "paneB" of a pane "paneA" of a SystemWindow fill its LayoutFrame?
I've done:
paneA setProperty: #autoFitContents toValue: true
and
paneB hResizing: #spaceFill; vResizing: #spaceFill
What am I missing? Help!
Cheers, Paul
A post yesterday to comp.lang.misc contains a link to http://www.idiom.com/free-compilers. There appears to be no entry for Squeak. Should someone from SqC rectify this?
Cheers, Paul
Are there any plans to build versions of the various list morphs which draw their rows directly instead of using a submorph for every row? For large lists the current implementation is very slow!
Cheers, Paul
On Sun, May 04, 2003 at 01:58:20PM +0100, Paul Chapman wrote:
Are there any plans to build versions of the various list morphs which draw their rows directly instead of using a submorph for every row? For large lists the current implementation is very slow!
There are some LargeList enhancements floating around. Check the list archives and the swiki. My apologies for not having the references handy.
Cheers, Paul
While we're on the subject of ListMorphs, all of the list morphs seem to expect the submorphs to be string/text morphs, and seem to provide the submorphs with (effectively) infinite width. I want to display a list of more complicated morphs where each submorph is a window with 3 (or more) panes. I want the submorphs to be laid out proportionally in the horizontal direction, but to be fixed size and scrolled in the vertical direction. (For anyone who has used Quicken, think of how the list of transactions in an account is displayed.)
I just got such a morph working yesterday, but I had to make changes all over the place :(. Now that I've proved to myself I can do it :), I can ask the list: is there an obvious, easy way to do this? One that doesn't involve a dozen new classes and changes to many old classes?
Also, what should this morph be called? I've called it the "PluggableMorphListMorh" in the sense of pluggable(MorphList)morph, not because I like that name (I don't) but because I couldn't think of anything better. Suggestions anyone?
If anyone's interested, I'll post it once I get rid all the cruft and dead end code from the things I tried that didn't work. Right at the moment I don't think my pride could handle someone else looking at it :).
Regards,
On Sun, May 04, 2003 at 01:02:21PM -0700, Tom Rushworth wrote:
On Sun, May 04, 2003 at 01:58:20PM +0100, Paul Chapman wrote:
Are there any plans to build versions of the various list morphs which draw their rows directly instead of using a submorph for every row? For large lists the current implementation is very slow!
There are some LargeList enhancements floating around. Check the list archives and the swiki. My apologies for not having the references handy.
http://map2.squeakfoundation.org/sm/package/ee1e9026-1d3f-4092-971b-bd42b3d1... Large Lists Summary: A replacement PluggableListMorph and friends that performs well with very large lists Author: Lex Spoon
I agree, Large Lists by Lex Spoon is your best bet for a simple fix.
One thing I'll point out is that Squeak isn't going to be the environment of the next thousand years or whatever if it can't handle displaying list items, by default, in a scalable way. This question has come up several times and each time we point the innocent off to some patch needed to make lists run as well as they should by default. Morphic has been around for a while now, and there isn't much excuse for such a serious kink to exist despite several available patches and extensive discussion in the past. If Morphic is only a temporary solution to be replaced "soon" by the next big thing, thats fine, but I don't know that this is the case.
We need to either make LargeLists part of the standard distribution or commission a group to implement a universally palatable solution that will be adopted as standard.
Here are the causes of the slowdown as I understand (LargeLists mostly addresses these, I believe) 1) Lists are slow to create and populate because the StringMorphs are created all at once. This can be alleviated by creating them lazily (which is a bit tricky afaik). LargeLists does this. This is the more minor problem imo, but still annoying if, for example, you want to open a list of 5000 email messages. 2) Lists are slow to scroll because: a) ScrollPanes draw every submorph, not just the visible ones. Yes, StringMorph has an early out, but the performance remains O( total items) instead of O ( viewable items). I haven't figured out a better way for general morph layouts, but for lists, its very easy to draw only the visible ones. Maybe ScrollPane should have more than one policy for drawing submorphs (general, slow policy, and fast specialized policies) b) ScrollPane is asked to find the bounds of all its submorphs for every scroll update. This is very easy to cache. (5-liner, adds an instance var.)
Given of List of n items, where k are viewable at one time, the scrolling performance can be as good as O(k), but the current version is O(n), leading to poor scalability on a big enough list. If I want a list of a billion items, with a window big enough for 10 of them, it should be just as fast as if there were 20 items total.
I hope that doesn't sound too harsh, but I think people tend not to take Morphic seriously if we don't.
I remember some people being mad that Java's Swing was slow with more than 20,000 menu items.. I'm not that picky! But 20,000 list items is a real possibility.
Sincerely, Eddie
Macus Said:
http://map2.squeakfoundation.org/sm/package/ee1e9026-1d3f-4092-971b-bd42b3d1 4670 Large Lists Summary: A replacement PluggableListMorph and friends that performs well with very large lists Author: Lex Spoon
-- Marcus Denker marcus@ira.uka.de -- Squeak! http://squeak.de
Thanks to all who replied.
Eddie Cottongim:
[liberally snipped]
... Morphic has been around for a while now, and there isn't much excuse for such a serious kink to exist despite several available patches and extensive discussion in the past.
I have some sympathy with a design which says that (almost) everything is a Morph, and CPU be damned. When it comes to the UI, I really don't mind if opening a window takes 0.1s rather than 0.01s. But when it takes >5s (on my ancient 400MHz PC) to view the class Morph in the WhiskerBrowser, I'm losing time and my train of thought!
a) ScrollPanes draw every submorph, not just the visible ones. Yes,
StringMorph has an early out, but the performance remains O( total items) instead of O ( viewable items).
When I found that not much intelligent use is made of the clipping rectangle (here and elsewhere) I was a little perplexed.
Given of List of n items, where k are viewable at one time, the scrolling performance can be as good as O(k), ...
... and the constant can be very small if BitBlt is used in line-at-a-time scrolling. This was something else which surprised and disappointed me - the (apparent) lack of hard-scrolling support for Morphs in general.
I remember some people being mad that Java's Swing was slow with more than 20,000 menu items.. I'm not that picky! But 20,000 list items is a real possibility.
Well, I would hope that I wouldn't hand a user a list of 20,000 items without some very powerful shortcuts to get to all of them, starting with initial-letter keystrokes.
I am perfectly comfortable with writing classes which provide speed-ups, or even withrewriting kernel code where necessary.
If I dared to criticise the wonderful work which has been done to get Squeak to where it is now, I would say that the development seems to have been following the slogan, "Never mind the quality, feel the width!" I don't really need voice synthesis for my current app. :) What I do need are fundamental tools which are small, fast and easy to drive.
A couple of things surprised me about Squeak as I started to explore it:
(1) Most methods do not have a comment. (Class comments are new to me, but many classes seem to be missing comments too.) I'm used to almost every method (except maybe new, intialize and instvar accessors) containing a comment which starts "Answer a [classname] which ..." or "Answer the receiver. [Does something]" or similar. It seems to me that we need an "MCP" - Method Commenting Project". ;)
(2) Many naming conventions of Smalltalk (as I understand them) are not followed. I was shocked to see "evt" used instead of "event" or "anEvent". I thought the Smalltalk way was to write complete words. I also thought that parameter names (and parameter names only) traditionally start with "a" or "an".
Now of course my concerns mean I should never be a Harvester, because I'd reject any contribution which did not conform rigorously to these standards and others. Too many people like me in the past would have meant today's Squeak would provide classes and methods for little more than adding and subtracting SmallIntegers. :)
Cheers, Paul
[make LargeLists standard] sounds good to me!
Here are the causes of the slowdown as I understand (LargeLists mostly addresses these, I believe)
- Lists are slow to create and populate because the StringMorphs are
created all at once. This can be alleviated by creating them lazily (which is a bit tricky afaik). LargeLists does this. This is the more minor problem imo, but still annoying if, for example, you want to open a list of 5000 email messages.
LargeLists doesn't even use StringMorph's, actually. It has a "LazyListMorph" which knows how to display a long list of strings, taking into account the clipping rectangle.
Also, there's another cost that LargeLists takes care of: it can take a long time to compute the strings from the domain items. For example, in Celeste, if you are viewing a list of 10000 email messages, then in a regular list morph that's 10000 summary lines that have to be computed up front. If only 10 of those will be displayed at a time, this is a big waste. To take advantage of this second possibility, you have to use an extended interface to the list morph,however; the standard interface requests all items at once through the #getListSelector.
As for scrolling speed, note that it is hard for ScrollPane to do better. The root problem is that the submorphs ivar is a simple Array; a fancier data structure is necessary. Also, it may be best to stick it all the way up in Morph; it's not ScrollPane only that deals with clipping panes. Furthermore, note that the better data structure is useful for forwarding mouse events to the correct submorph, as well.
Lex
Lex,
As for scrolling speed, note that it is hard for ScrollPane to do better. The root problem is that the submorphs ivar is a simple Array; a fancier data structure is necessary.
Measuring it a little I found a very specific hot-spot there. Turns out that scroll panes spend ages in computing the local submorph bounds of the transform which can be trivially cached. Try it!
Cheers, - Andreas
'From TeaSqueak3.2 of 19 September 2002 [latest update: #393] on 12 May 2003 at 11:55:08 pm'! Morph subclass: #TransformMorph instanceVariableNames: 'transform smoothing localBounds ' classVariableNames: '' poolDictionaries: '' category: 'Morphic-Basic'!
!TransformMorph methodsFor: 'geometry' stamp: 'ar 5/12/2003 23:15'! layoutChanged localBounds := nil. ^super layoutChanged! !
!TransformMorph methodsFor: 'geometry' stamp: 'ar 5/12/2003 23:15'! localSubmorphBounds "Answer, in my coordinate system, the bounds of all my submorphs (or nil if no submorphs)" | subBounds | localBounds ifNotNil:[^localBounds]. subBounds _ nil. self submorphsDo: [:m | subBounds ifNil: [subBounds _ m fullBounds] ifNotNil: [subBounds _ subBounds quickMerge: m fullBounds]]. ^localBounds := subBounds! !
"Andreas Raab" andreas.raab@gmx.de wrote:
Lex,
As for scrolling speed, note that it is hard for ScrollPane to do better. The root problem is that the submorphs ivar is a simple Array; a fancier data structure is necessary.
Measuring it a little I found a very specific hot-spot there. Turns out that scroll panes spend ages in computing the local submorph bounds of the transform which can be trivially cached. Try it!
Oh, well neat! This still doesn't help much with the initial display after a list changes, does it? I seem to remember profiling and finding that the bottleneck there was all the StringMorph's resizing themselves.
Anyway, for Celeste a definite slow part is just calculating all the strings, and you still need a tweaked PLM to avoid this.
Lex
Lex,
Oh, well neat! This still doesn't help much with the initial display after a list changes, does it?
It doesn't. But the trick here is that the little tweak affects any PLM (no matter how large) which might be useful for 'medium length lists' (such as the class list in a browser) on low-end machines.
Cheers, - Andreas
Oh, well neat! This still doesn't help much with the initial display after a list changes, does it?
It doesn't. But the trick here is that the little tweak affects any PLM (no matter how large) which might be useful for 'medium length lists' (such as the class list in a browser) on low-end machines.
Yes, very helpful. The LargeLists patch has always helped with lists of all sizes, too, by the way, including the pause when a list's contents change. Thus LargeLists has more code, but does strictly more.
Lex
tbr@mannynkapy.net (Tom Rushworth) wrote:
On Sun, May 04, 2003 at 01:58:20PM +0100, Paul Chapman wrote:
Are there any plans to build versions of the various list morphs which draw their rows directly instead of using a submorph for every row? For large lists the current implementation is very slow!
There are some LargeList enhancements floating around. Check the list archives and the swiki. My apologies for not having the references handy.
Cheers, Paul
While we're on the subject of ListMorphs, all of the list morphs seem to expect the submorphs to be string/text morphs, and seem to provide the submorphs with (effectively) infinite width. I want to display a list of more complicated morphs where each submorph is a window with 3 (or more) panes. I want the submorphs to be laid out proportionally in the horizontal direction, but to be fixed size and scrolled in the vertical direction. (For anyone who has used Quicken, think of how the list of transactions in an account is displayed.)
I just got such a morph working yesterday, but I had to make changes all over the place :(. Now that I've proved to myself I can do it :), I can ask the list: is there an obvious, easy way to do this? One that doesn't involve a dozen new classes and changes to many old classes?
How about ScrollPane plus a table layout that is 1 column wide? Maybe that would work.
-Lex
On Tue, May 06, 2003 at 05:26:14PM +0300, Lex Spoon wrote:
tbr@mannynkapy.net (Tom Rushworth) wrote:
[snip]
While we're on the subject of ListMorphs, all of the list morphs seem to expect the submorphs to be string/text morphs, and seem to provide the submorphs with (effectively) infinite width. I want to display a list of more complicated morphs where each submorph is a window with 3 (or more) panes. I want the submorphs to be laid out proportionally in the horizontal direction, but to be fixed size and scrolled in the vertical direction. (For anyone who has used Quicken, think of how the list of transactions in an account is displayed.)
I just got such a morph working yesterday, but I had to make changes all over the place :(. Now that I've proved to myself I can do it :), I can ask the list: is there an obvious, easy way to do this? One that doesn't involve a dozen new classes and changes to many old classes?
How about ScrollPane plus a table layout that is 1 column wide? Maybe that would work.
A table layout is something I didn't think of trying. I'll give it a try as soon as I can get back to Squeak.
I suspect there will be problems though, because what I first tried was a ScrollPane with a custom layout. The ScrollPane's scroller is normally a TransformMorph, and seems to intercept any layout stuff before it gets to the morphs to be transformed. I ended up replacing the TransformMorph with a subclass of ComponentLikeModel that I called VerticalOffsetMorph, which contains just enough of the TransformMorph to track a vertical offset, and draw its submorphs accordingly. The custom layout I called a HorizontalProportionalLayout, and it's a fairly obvious subclass of ProportionalLayout. I was hoping I wouldn't need either one of them, but...
-Lex
I need to get it cleaned up and posted, so people can criticize properly :).
On Tuesday, May 6, 2003, at 06:41 PM, Tom Rushworth wrote:
How about ScrollPane plus a table layout that is 1 column wide? Maybe that would work.
A table layout is something I didn't think of trying. I'll give it a try as soon as I can get back to Squeak.
You might also try stealing some code from Bricks.
Take a look at ToolbarBrick - its more general than just toolbars - you can make a menu or list out of it pretty easily as it just lays out its parts in a row (or column - your choice) and there's a highlight painter to handle selections that you can attach.
tbr@mannynkapy.net (Tom Rushworth) wrote:
I suspect there will be problems though, because what I first tried was a ScrollPane with a custom layout. The ScrollPane's scroller is normally a TransformMorph, and seems to intercept any layout stuff before it gets to the morphs to be transformed.
I don't know whether you can make it work directly. If you cannot, however, you can surely add a level of indirection and use a plain Morph to hold all your items and then add that morph as the only element of the TransformMorph. Then the morph can have whatever layout you wish. You can make the morph transparent if need be.
Lex
squeak-dev@lists.squeakfoundation.org