Oh thanks, that explains the problem I observed and why I did not spot the bug 
in all the time I spent staring at it in the debugger: the values were there in 
the rectangle, only swapped between origin and corner!

Maybe receiving a rectangle as the second argument of #fractions:offsets: 
should cause a warning to be printed on the Transcript. It is such an easy 
mistake with such a tricky behaviour…

Anyway, the improved FrameLayout documentation will already help a lot.

> On 10 Jan 2016, at 23:16, Thierry Goubier <[email protected]> wrote:
> 
> Hi David,
> 
> this is the bug with LayoutFrame>>#fractions:offsets: we were talking
> about relative to that class comment.
> 
> In Pharo, Rectangles are constrained to have the smallest vertical value
> as the top, smallest horizontal value as the left, largest vertical
> value as bottom and largest horizontal value as right. So, your
> rectangle 'offsets' was in fact:
>       -3 @ -3 corner: 3 @ 3
> which is exactly the reverse of what you intended ;)
> 
> Using the elementary distance accessors is the correct approach.
> 
> Regards,
> 
> Thierry
> 
> Le 10/01/2016 23:05, David Allouche a écrit :
>> I guess that is a class comment for LayoutFrame. I think this is
>> great improvement.
>> 
>> By I the way, I noticed something really strange when I was using it
>> in my learning project of a TicTacToe game. I started initializing a
>> LayoutFrame using #fractions:offsets:, but I had strange incorrect
>> results. I have fixed them by using the elementary distance
>> accessors.
>> 
>> Here is the relevant method in my code.
>> 
>> drawCircleOn: aCanvas "Draw a circle cell" | layout oval | "That
>> should worlk, but does not!" "offsets := (1@1 corner: (-1)@(-1))
>> scaleBy: lineWidth*3." "layout := LayoutFrame fractions: (0@0 corner:
>> 1@1) offsets: offsets." layout := (0@0 corner: 1@1) asLayoutFrame.
>> layout topOffset: lineWidth*3; leftOffset: lineWidth*3; bottomOffset:
>> lineWidth*(-3); rightOffset: lineWidth*(-3). oval := layout
>> transform: self bounds. aCanvas frameOval: oval width: lineWidth
>> color: color.
>> 
>> I could not find an online syntax highlighter that supports
>> Smalltalk, so here it comes unstyled.
>> 
>> Should I write a test case for that, or did I try to do something
>> obviously incorrect?
>> 
>>> On 9 Jan 2016, at 10:22, stepharo <[email protected]> wrote:
>>> 
>>> I define a transformation frame relative to some rectangle. I'm
>>> basic data structure used for graphics. I represent two groups of
>>> distances: - The fractional distance (between 0 and 1) to place the
>>> morph in its owner's bounds - Fixed pixel offset to apply after
>>> fractional positioning (e.g., "10 pixel right of the center of the
>>> owner")
>>> 
>>> !! API usage It is important to understand that it is better to use
>>> the fine grained API using elementary distances (bottomFraction:,
>>> bottomOffset:, leftFraction: ....) than the ones (historical) using
>>> points and rectangles (fractions:offsets:)
>>> 
>>> The reason is that the old API (fractions:offsets:) is only
>>> interesting if you already have a rectangle and point at hand. If
>>> you need to create new ones, then they are created for nothing
>>> because they will be destructured to extract their information to
>>> be feed into the layoutFrame. So please do not blindly copy and
>>> paste code!
>>> 
>>> Example: Favor
>>> 
>>> (LayoutFrame identity leftFraction: 0; yourself);
>>> 
>>> (LayoutFrame identity leftFraction: 0.5; rightFraction: 0.95;
>>> 
>>> (LayoutFrame identity topOffset: topHeight; bottomFraction: 0;
>>> bottomOffset: self buttonsBarHeight; leftOffset: -1; rightOffset:
>>> 1) over
>>> 
>>> (LayoutFrame fractions: (0 @ 0 corner: 1 @ 1))
>>> 
>>> For this one in particular it is better to use LayoutFrame
>>> identity
>>> 
>>> It is faster and more readable
>>> 
>>> because you are creating for nothing a new rectangle and some
>>> points.
>>> 
>>> !! Final point: Do not use Rectangles for specifying layoutFrames
>>> 
>>> If you happen to need to create a rectangle and use the
>>> fractions:offsets: class methods, refrain from creating a
>>> rectangle. The reason is that a rectangle is not 4 numbers, it
>>> represents a space area and when you use a rectangle to represent
>>> random numbers you end up creating rectangles with negative extents
>>> and this is not good. In this case use Margin, Margin is a nice
>>> class holding either one number (the same "margin" on the four
>>> sides of a rectangle), or two number (top/bottom, left/right
>>> margins) or 4 numbers.
>>> 
>>> !! Implementation
>>> 
>>> Instance variables: The fractional distance (between 0 and 1) to
>>> place the morph in its owner's bounds is represented by the
>>> following instance variables: leftFraction topFraction
>>> rightFraction bottomFraction     <Float>
>>> 
>>> 
>>> Fixed pixel offset to apply after fractional positioning (e.g., "10
>>> pixel right of the center of the owner")  is represented by the
>>> following instance variables: leftOffset topOffset rightOffset
>>> bottomOffset     <Integer>
>>> 
>> 
>> 
>> 
> 
> 


Reply via email to