HPanelV.st
author claus
Mon, 21 Nov 1994 17:46:30 +0100
changeset 65 b33e4f3a264e
parent 62 7cc1e330da47
child 77 565b052f5277
permissions -rw-r--r--
*** empty log message ***

"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

PanelView subclass:#HorizontalPanelView
       instanceVariableNames:''
       classVariableNames:''
       poolDictionaries:''
       category:'Views-Layout'
!

HorizontalPanelView comment:'
COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

$Header: /cvs/stx/stx/libwidg/Attic/HPanelV.st,v 1.7 1994-11-21 16:45:24 claus Exp $
'!

!HorizontalPanelView class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

version
"
$Header: /cvs/stx/stx/libwidg/Attic/HPanelV.st,v 1.7 1994-11-21 16:45:24 claus Exp $
"
!

documentation
"
    a View which arranges its child-views in a horizontal row.
    All real work is done in PanelView - only the layout computation is
    redefined here.

    The layout is controlled by two instance variables. 
    The horizontal layout can be any of:

	#left           arrange elements at the left
	#leftSpace      arrange elements at the left, start with spacing
	#right          arrange elements at the right
	#rightSpace     arrange elements at the right, start with spacing
	#center         arrange elements in the center
	#spread         spread elements evenly
	#fit            like spread, but resize elements for tight packing

    the vertical layout can be:

	#top            place element at the top
	#topSpace       place element at the top, offset by verticalSpace
	#center         place it horizontally centered
	#bottom         place it at the bottom
	#bottomSpace    place it at the bottom, offset by verticalSpace
	#fit            resize elements vertically to fit this panel

    The defaults is #centered for both directions.
    The layout is changed by the messages #verticalLayout: and #horizontalLayout:.
    For backward compatibility (to times, where only hLayout existed), the simple
    #layout: does the same as #horizontalLayout:. Do not use this old method.
"
!

examples
"
    example: default layout (centered)

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open


    example: left-layout

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#left.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open


    example: right-layout

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#right.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open


    example: spread-layout

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#spread.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open

    example: fit - top

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#fit.
	p verticalLayout:#top.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open

    example: fit - top without spacing

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#fit.
	p verticalLayout:#top.
	p horizontalSpace:0.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open

    example: fit - bottom with spacing and bottomSpace

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#fit.
	p verticalLayout:#bottomSpace.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open

    example: fit no horizontal space - bottom with spacing and bottomSpace

	|v p b1 b2 b3|

	v := StandardSystemView new.
	p := HorizontalPanelView in:v.
	p horizontalLayout:#fit.
	p verticalLayout:#bottomSpace.
	p horizontalSpace:0.
	p origin:(0.0 @ 0.0) corner:(1.0 @ 1.0).
	b1 := Button label:'button1' in:p.
	b2 := Button label:'button2' in:p.
	b3 := Button label:'button3' in:p.
	v extent:300 @ 100.
	v open
"
! !

!HorizontalPanelView methodsFor:'accessing'!

horizontalLayout
    "return the horizontal layout as symbol.
     the returned value is one of
	#left 
	#leftSpace 
	#center
	#spread
	#fit
	#right 
	#rightSpace 
      the default is #centered
    "

    ^ hLayout
!

verticalLayout
    "return the vertical layout as a symbol.
     the returned value is one of
	#top
	#topSpace
	#center
	#bottom
	#bottomSpace
	#fit 
      the default is #centered
    "

    ^ vLayout
!

horizontalLayout:aSymbol
    "change the horizontal layout as symbol.
     The argument, aSymbol must be one of:
	#left 
	#leftSpace 
	#center
	#spread
	#fit
	#right 
	#rightSpace 
      the default (if never changed) is #centered
    "

    (hLayout ~~ aSymbol) ifTrue:[
	hLayout := aSymbol.
	self layoutChanged
    ]
!

verticalLayout:aSymbol
    "change the vertical layout as a symbol.
     The argument, aSymbol must be one of:
	#top
	#topSpace
	#center
	#bottom
	#bottomSpace
	#fit 
      the default (if never changed) is #centered
    "

    (vLayout ~~ aSymbol) ifTrue:[
	vLayout := aSymbol.
	self layoutChanged
    ]
!

layout
    "leftover for historic reasons - do not use any more"

    self horizontalLayout
!

layout:aSymbol
    "leftover for historic reasons - do not use any more"

    self horizontalLayout:aSymbol
! !


!HorizontalPanelView methodsFor:'queries'!

preferedExtent
    "return a good extent, one that makes subviews fit"

    |sumOfWidths maxHeight maxWidth|

    subViews isNil ifTrue:[^ horizontalSpace @ verticalSpace].

    "compute net height needed"

    sumOfWidths := 0.
    maxHeight := 0.
    maxWidth := 0.

    subViews do:[:child |
	|childsPreference|

	childsPreference := child preferedExtent.
	sumOfWidths := sumOfWidths + childsPreference x.
	maxHeight := maxHeight max:childsPreference y.
	maxWidth := maxWidth max:childsPreference x.

"/        sumOfWidths := sumOfWidths + child widthIncludingBorder.
"/        maxHeight := maxHeight max:(child heightIncludingBorder).
"/        maxWidth := maxWidth max:(child widthIncludingBorder).
    ].
    borderWidth ~~ 0 ifTrue:[
	sumOfWidths := sumOfWidths + (horizontalSpace * 2).
	maxHeight := maxHeight + (verticalSpace * 2).
    ].
    hLayout == #fit ifTrue:[
	sumOfWidths := maxWidth * subViews size.
	borderWidth ~~ 0 ifTrue:[
	    sumOfWidths := sumOfWidths + (verticalSpace * 2).
	]
    ] ifFalse:[
	sumOfWidths := sumOfWidths + ((subViews size - 1) * horizontalSpace).
    ].

    ((vLayout == #topSpace) or:[vLayout == #bottomSpace]) ifTrue:[
	maxHeight := maxHeight + verticalSpace
    ] ifFalse:[
	((vLayout == #fit)  or:[vLayout == #center]) ifTrue:[
	    maxHeight := maxHeight + (verticalSpace * 2)
	]        
    ].

    ^ sumOfWidths @ maxHeight
! !

!HorizontalPanelView methodsFor:'layout'!

setChildPositions
    "(re)compute position of every child whenever childs are added or
     my size has changed"

    |xpos space sumOfWidths numChilds l wEach|

    subViews isNil ifTrue:[^ self].

    space := horizontalSpace.
    numChilds := subViews size.

    hLayout == #fit ifTrue:[
	"
	 adjust childs extents and set origins.
	 Be careful to avoid accumulation of rounding errors
	"
	wEach := (width - (margin * 2) - (numChilds + 1 * space) + borderWidth) / numChilds.
	xpos := space + margin - borderWidth.
    ] ifFalse:[

	"
	 compute net width needed
	"
	sumOfWidths := subViews inject:0 into:[:sumSoFar :child | sumSoFar + child widthIncludingBorder].

	l := hLayout.
	((l == #center) and:[numChilds == 1]) ifTrue:[
	    l := #spread
	].

	"
	 compute position of leftmost subview and space between them;
	 if they do hardly fit, leave no space between them 
	"
	(sumOfWidths >= (width - (margin * 2))) ifTrue:[
	    xpos := 0.
	    space := 0
	] ifFalse: [
	    ((l == #right) or:[l == #rightSpace]) ifTrue:[
		xpos := width - (space * numChilds) - sumOfWidths.
    "
		borderWidth == 0 ifTrue:[
		    xpos := xpos + space 
		].
    "
		l == #rightSpace ifTrue:[
		    xpos > space ifTrue:[
			xpos := xpos - space
		    ]
		].

		xpos < 0 ifTrue:[
		    space := space min:(width - sumOfWidths) // (numChilds + 1).
		    xpos := width - (space * numChilds) - sumOfWidths.
		]
	    ] ifFalse:[
		(l == #spread) ifTrue:[
		    space := (width - sumOfWidths) // (numChilds + 1).
		    xpos := space.
		    (space == 0) ifTrue:[
			xpos := (width - sumOfWidths) // 2
		    ]
		] ifFalse:[
		    ((l == #left) or:[l == #leftSpace]) ifTrue:[
			space := space min:(width - sumOfWidths) // (numChilds + 1).
			l == #leftSpace ifTrue:[
			    xpos := space.
			] ifFalse:[
			    xpos := 0
			]
    "
			borderWidth == 0 ifTrue:[
			    xpos := 0 
			].
    "
		    ] ifFalse:[
			xpos := (width - (sumOfWidths
					  + ((numChilds - 1) * space))) // 2.
			xpos < 0 ifTrue:[
			    space := (width - sumOfWidths) // (numChilds + 1).
			    xpos := (width - (sumOfWidths
					   + ((numChilds - 1) * space))) // 2.
			]
		    ]
		]
	    ]
	].
    ].

    "now set positions"

    subViews do:[:child |
	|ypos|

	vLayout == #top ifTrue:[
	    ypos := 0
	] ifFalse:[
	    hLayout == #topSpace ifTrue:[
		ypos := verticalSpace
	    ] ifFalse:[
		vLayout == #bottom ifTrue:[
		    ypos := height - child heightIncludingBorder
		] ifFalse:[
		    vLayout == #bottomSpace ifTrue:[
			ypos := height - verticalSpace - child heightIncludingBorder.
		    ] ifFalse:[
			vLayout == #fit ifTrue:[
			    ypos := verticalSpace.
			    child height:(height - (verticalSpace + child borderWidth * 2))
			] ifFalse:[
			    "centered"
			    ypos := (height - child heightIncludingBorder) // 2.
			]
		    ]
		]
	    ]
	].
	(ypos < 0) ifTrue:[ypos := 0].

	hLayout == #fit ifTrue:[
	    child origin:(xpos rounded @ ypos)
		  corner:(xpos + wEach - (child borderWidth)) rounded
			 @ (ypos + child height).
	    xpos := xpos + wEach + space
	] ifFalse:[
	    child origin:(xpos @ ypos).
	    xpos := xpos + (child widthIncludingBorder) + space
	]
    ]
! !