UIBuilder.st
author claus
Tue, 06 Jun 1995 06:10:38 +0200
changeset 80 e029e7deed8b
parent 75 a53337dc3e19
child 86 38cc61653cb2
permissions -rw-r--r--
.

'From Smalltalk/X, Version:2.10.5 on 11-apr-1995 at 9:42:52 am'!

WindowBuilder subclass:#UIBuilder 
	 instanceVariableNames:''
	 classVariableNames:'Verbose'
	 poolDictionaries:''
	 category:'Interface-Support-UI'
!

!UIBuilder class methodsFor:'documentation'!

documentation
"
    this class will (eventually) allow parsing windowSpecs as
    created by ST-80's UIPainter, and thereby allow to run applications
    built with this tool.
    It was created to allow execution of PD applications which were
    written using that tool (and more and more are appearing ...).

    The class is not completed yet and certainly not bug free.
    Also, it is not quaranteed that all winSpecs are understood.
"
! !

!UIBuilder class methodsFor:'initialization'!

initialize
    Verbose := false    "/ debugging flag
! !

!UIBuilder methodsFor:'operation'!

buildFromSpec:aSpec
    self readSpec:aSpec.
    ^ topView
! !

!UIBuilder methodsFor:'private spec component parsing'!

xLabelSpec:aSpec view:aView
    |l|

    l := Label in:aView.
    self fixFontFor:l.
    self doSpec:aSpec for:l 

!

xFullSpec:aSpec
    topView := StandardSystemView new.
    topView controller:(ApplicationController new).
    topView application:application.

    self doSpec:aSpec for:topView.
    ^ topView
!

xSpecCollection:aSpec view:aView
    self doSpec:aSpec for:aView

!

xWindowSpec:aSpec view:aView
    self doSpec:aSpec for:aView

!

xInputFieldSpec:aSpec view:aView
    |l|

    l := EditField in:aView.
    self fixFontFor:l.
    l aspect:#value; change:#value:.
    self doSpec:aSpec for:l 
!

xActionButtonSpec:aSpec view:aView
    |b|

    b := Button in:aView.
    self fixFontFor:b.
    self doSpec:aSpec for:b 
!

xSequenceViewSpec:aSpec view:aView
    |f s|

    f := ScrollableView for:SelectionInListView in:aView.
    s := f scrolledView.
    self doSpec:aSpec for:s frame:f.
!

xScrollerSpec:aSpec view:aView
    |s idx orientation|

    idx := aSpec indexOf:#orientation:.
    idx == 0 ifTrue:[
	orientation := #vertical
    ] ifFalse:[
	orientation := aSpec at:(idx + 1)
    ].
    orientation == #horizontal ifTrue:[
	s := HorizontalScroller in:aView
    ] ifFalse:[
	s := Scroller in:aView
    ].
    self doSpec:aSpec for:s 
!

xProgressIndicatorSpec:aSpec view:aView
    |s|

    s := ProgressIndicator in:aView.
    self doSpec:aSpec for:s 
!

xSliderSpec:aSpec view:aView
    |s idx orientation|

    idx := aSpec indexOf:#orientation:.
    idx == 0 ifTrue:[
	orientation := #vertical
    ] ifFalse:[
	orientation := aSpec at:(idx + 1)
    ].
    orientation == #horizontal ifTrue:[
	s := HorizontalSlider in:aView
    ] ifFalse:[
	s := Slider in:aView
    ].
    self doSpec:aSpec for:s 
!

xCompositeSpecCollection:aSpec view:aView
    |v|

"/ 'compositeSpecCollection ignoed' printNL.
"/ ^ self.
    v := View in:aView.
    self doSpec:aSpec for:v 

!

xArbitraryComponentSpec:aSpec view:aView
    |v|

"/    v := View in:aView.
    v := Label label:'ArbitraryView' in:aView.
    v level:-1.
    self doSpec:aSpec for:v 
!

xCheckBoxSpec:aSpec view:aView
    |b|

    b := CheckBox in:aView.
    self fixFontFor:b.
    self doSpec:aSpec for:b 

!

xTableViewSpec:aSpec view:aView
    |l|

    'tableView ignored' printNL.
    l := Label label:'TableView' in:aView.
    l level:-1.
    self doSpec:aSpec for:l 
!

xGroupBoxSpec:aSpec view:aView
    |l|

    l := FramedBox in:aView.
    self doSpec:aSpec for:l 
!

xDividerSpec:aSpec view:aView
    |l|

    l := View in:aView.
    self doSpec:aSpec for:l 
! !

!UIBuilder methodsFor:'private spec attribute parsing'!

yMultipleSelections:args view:aView
    aView multipleSelectOk:args
!

yBounds:args view:aView frame:frameView
    |value r|

    value := self getArg:args.
    (value at:1) == #rectangle ifTrue:[
	r := value at:2.
	aView origin:r origin corner:r corner.
	^ self
    ].
    self halt:'unimplemented'.
!

yCollection:args view:aView frame:frameView
    args do:[:aSpec |
	self readSpec:aSpec view:aView frame:frameView.
    ].
!

yComponent:args view:aView frame:frameView
    |v|

    args isSymbol ifTrue:[
	v := application perform:args.
	aView addSubView:v
    ] ifFalse:[
	v := View origin:0.0@0.0 corner:1.0@1.0 in:aView.
	self readSpec:args view:v frame:frameView.
    ]
!

yColors:args view:aView frame:frameView
    |value|

    value := self getArg:args.
    self halt:'unimplemented'.
!

yCompositeSpec:args view:aView frame:frameView
    |value r|

    self doSpec:args for:aView.
"
    value := self getArg:args.
    (value at:1) == #rectangle ifTrue:[
	r := value at:2.
	aView origin:r origin corner:r corner.
	^ self
    ].

self halt.
"
!

yDefaultable:args view:aView frame:frameView
    'defaultable ignored' printNL
!

yLabel:args view:aView frame:frameView
    aView label:args.

!

yLayout:args view:aView frame:frameView
    |value r org corn orgInset cornInset what|

    value := self getArg:args.

    what := value at:1.
    what == #point ifTrue:[
	Verbose ifTrue:[frameView print. ' ' print. 'origin: ' print. (value at:2) printNL].
	frameView origin:(value at:2).
	^ self
    ].
    what == #rectangle ifTrue:[
	r := value at:2.
	Verbose ifTrue:[
	    frameView print. ' ' print. 'origin: ' print. r origin print.
			     ' corner: ' print. r corner printNL.
	].
	frameView origin:r origin corner:r corner.
	^ self
    ].
    what == #layoutOrigin ifTrue:[
	"/ #layoutOrigin relOrg orgInset
	org := value at:2.       "/ relative origin
	org := org x asFloat @ org y asFloat.
	orgInset := self fixExtentFor:(value at:3).
	Verbose ifTrue:[
	    frameView print. ' ' print. 'origin: ' print. org printNL
	].
	frameView origin:org.
	frameView 
	      leftInset:orgInset x;
	      topInset:orgInset y.
	^ self
    ].
    what == #layoutFrame ifTrue:[
	"/ #layoutFrame orgInset cornInset relOrg relCorner

	org := value at:4.       "/ relative origin
	orgInset := self fixExtentFor:(value at:2).

	org := org x asFloat @ org y asFloat.
"/        org = (0@0) ifTrue:[
"/            org := value at:2    "/ absolute origin
"/        ].

	corn := value at:5.      "/ relative corner
	cornInset := self fixExtentFor:(value at:3).
	corn := corn x asFloat @ corn y asFloat.
"/        corn = (0@0) ifTrue:[
"/            corn := value at:3   "/ absolute corner
"/        ].
	Verbose ifTrue:[
	    frameView print. ' ' print. 'origin: ' print. org print.
			     ' corner: ' print. corn printNL.
	].
	frameView origin:org corner:corn.
	frameView leftInset:orgInset x;
	      topInset:orgInset y;
	      rightInset:cornInset x negated;
	      bottomInset:cornInset y negated.
	frameView sizeFixed:true.
	^ self
    ].
    what == #alignmentOrigin ifTrue:[
	org := value at:3.       "/ relative origin
	org = (0@0) ifTrue:[
	    org := value at:2    "/ absolute origin
	].
	Verbose ifTrue:[frameView print. ' ' print. 'origin: ' print. org printNL].
	frameView origin:org.
	^ self
    ].

    self halt:'unimplemented'.
!

yFlags:args view:aView frame:frameView
    'flags ignored' printNL
!

yIsDefault:args view:aView frame:frameView
    aView isReturnButton:args
!

yMin:args view:aView frame:frameView
    |value|

    value := self getArg:args.
    (value at:1) == #point ifTrue:[
	aView minExtent:(value at:2).
	^ self
    ].
    self halt:'unimplemented'.
!

yModel:args view:aView frame:frameView
    |model|

    (aspects notNil and:[aspects includesKey:args]) ifTrue:[
	model := aspects at:args
    ] ifFalse:[
	model := application perform:args
    ].
    aView model:model.
!

yIsOpaque:args view:aView frame:frameView
    'isOpaque ignored' printNL.
!

yIsReadOnly:args view:aView frame:frameView
    args ifTrue:[
	aView readOnly
    ]
!

yMax:args view:aView frame:frameView
    |value|

    value := self getArg:args.
    (value at:1) == #point ifTrue:[
	aView maxExtent:(value at:2).
	^ self
    ].
    self halt:'unimplemented'.
!

yMenu:args view:aView frame:frameView
    'menu ignored' printNL
!

yName:args view:aView frame:frameView
    bindings isNil ifTrue:[
	bindings := IdentityDictionary new.
    ].
    bindings at:args put:aView
!

yOrientation:args view:aView frame:frameView
    'orientation ignored' printNL.
!

ySelectionStyle:args view:aView frame:frameView
    'selectionStyle ignored' printNL.

!

yTabable:args view:aView frame:frameView
    args == true ifTrue:[
	focusSequence isNil ifTrue:[
	    focusSequence := OrderedCollection new.
	].
	focusSequence add:aView.
	'tabable element added' printNL.
    ]
!

yStart:args view:aView frame:frameView
    'start ignored' printNL.

!

yStep:args view:aView frame:frameView
    'step ignored' printNL.

!

yWindow:args view:aView frame:frameView
    self readSpec:args view:aView frame:frameView.
!

yStop:args view:aView frame:frameView
    'stop ignored' printNL.

!

yStyle:args view:aView frame:frameView
    'name ignored' printNL.

!

yType:args view:aView frame:frameView
    'type ignored' printNL.
! !

!UIBuilder methodsFor:'private arg parsing'!

getArg:spec
    "take something like #(Point 50 100) and return the value"

    |what|

    what := spec at:1.
    ^ self perform:('get' , what , ':') asSymbol with:spec
!

getPoint:spec
    "called for #(Point x y)"

    ^ Array with:#point 
	    with:((spec at:2) @ (spec at:3))
!

getLayoutFrame:spec
    "called for #(LayoutFrame absOrgX relOrgX absOrgY relOrgY absCornX relCornX absCornY relCornY)"
    "             1           2       3       4        5      6        7        8        9"
    ^ Array with:#layoutFrame
	    with:((spec at:2) @ (spec at:4))     "/ org inset
	    with:((spec at:6) @ (spec at:8))     "/ corner inset
	    with:((spec at:3) @ (spec at:5))     "/ rel org
	    with:((spec at:7) @ (spec at:9))     "/ rel corn 

!

getRectangle:spec
    "called for #(Rectangle x y)"

    ^ Array with:#rectangle
	    with:(((spec at:2) @ (spec at:3)) corner:((spec at:4) @ (spec at:5)))
!

getLayoutOrigin:spec
    "called for #(LayoutOrigin xInset relX yInset relY)"

    ^ Array with:#layoutOrigin
	    with:((spec at:3) @ (spec at:5))     "/ rels
	    with:((spec at:2) @ (spec at:4))     "/ insets
!

getCompositeSpec:spec
    "called for #(CompositeSpec layout: #(orgx orgy cornx corny)"

    |layout|

    (spec at:2) == #layout: ifTrue:[
	layout := spec at:3.
	(layout at:1) == #Rectangle ifTrue:[
	    ^ Rectangle
		    origin:(layout at:2) @ (layout at:3)
		    corner:(layout at:4) @ (layout at:5)
	].
    ].
    self halt:'unimplemented'.
!

getAlignmentOrigin:spec
    "called for #(AlignmentOrigin ?x ?relX ?x ?y ?relY ?y)"

    ^ Array with:#alignmentOrigin
	    with:((spec at:2) @ (spec at:5))     "/ ?
	    with:((spec at:3) @ (spec at:6))     "/ rels ?
	    with:((spec at:4) @ (spec at:7))     "/ insets ?


!

getLookPreferences:spec
    "called for #(LookPreferences setForegroundColor: (...) setBackgroundColor: (...) ...)"

    |coll|

    coll := OrderedCollection new.
    2 to:spec size by:2 do:[:index |
	coll add: 
	    (Array with:(spec at:index)
		  with:(self getArg:(spec at:index+1)))
    ].
    ^ coll.
!

getColorValue:spec
    "called for #(ColorValue #sym)
	     or #(ColorValue red green blue)"

    |clr arg|

    (arg := spec at:2) isSymbol ifTrue:[
	(Color respondsTo:arg) ifTrue:[
	    ^ Color perform:arg
	].
	^ Color name:arg asString ifIllegal:[Color black]
    ].
    arg isInteger ifTrue:[
	^ ColorValue scaledRed:arg
		     scaledGreen:(spec at:3)
		     scaledBlue:(spec at:4)
    ].
    ^ ColorValue red:arg
		 green:(spec at:3)
		 blue:(spec at:4)


! !

!UIBuilder methodsFor:'private spec parsing'!

doSpec:aSpec for:aView
    ^ self doSpec:aSpec for:aView frame:aView
!

add:aSpec
    self readSpec:aSpec
!

readSpec:aSpec
    |what|

    what := aSpec first.
    ^ self perform:('x' , what , ':') asSymbol with:aSpec
!

doSpec:aSpec for:aView frame:frame 
    |state selector args argsToRead|

    argsToRead := 0.
    args := #().
    aSpec from:2 to:(aSpec size) do:[:element |
	argsToRead > 1 ifTrue:[
	    self halt.
	] ifFalse:[
	    argsToRead == 1 ifTrue:[
		args := element.
		argsToRead := argsToRead - 1
	    ] ifFalse:[
		selector := element.
		argsToRead := selector numArgs.
	    ].
	].
	argsToRead == 0 ifTrue:[
	    self doSingleSpec:selector args:args for:aView frame:frame
	]
    ]
!

readSpec:aSpec view:aView frame:frameView
    |what|

    what := aSpec first.
    self perform:('x' , what , ':view:') asSymbol with:aSpec with:aView
!

doSingleSpec:selector args:args for:aView frame:frame
    Verbose ifTrue:[
	'doSingle (' print. aView print. ' -> ' print. selector print.
	' ' print. args printString printNL.
    ].

    self perform:('y' , selector asString asUppercaseFirst , 'view:frame:') asSymbol 
	    with:args
	    with:aView
	    with:frame.

! !

!UIBuilder methodsFor:'private special kludges'!

fixFontFor:aComponent
    "since ST-80 seems to use a smaller default font,
     and component sizes are often given in pixels in winSpecs,
     make the font smaller for less ugly looking elements."

"/   aComponent font:(aComponent font size:8)
!

fixExtentFor:aPoint
    ^ aPoint "/ (aPoint * (1 @ 1.5)) truncated
! !

UIBuilder  initialize!