--- a/WindowGroup.st Mon Feb 06 01:38:04 1995 +0100
+++ b/WindowGroup.st Mon Feb 06 01:40:27 1995 +0100
@@ -11,7 +11,8 @@
"
Object subclass:#WindowGroup
- instanceVariableNames:'views topViews myProcess mySensor isModal previousGroup'
+ instanceVariableNames:'views topViews myProcess mySensor isModal previousGroup
+ focusView focusSequence'
classVariableNames:'ActiveGroup ScheduledWindowGroups LeaveSignal'
poolDictionaries:''
category:'Interface-Support'
@@ -21,7 +22,7 @@
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
-$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.16 1994-11-28 21:01:20 claus Exp $
+$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.17 1995-02-06 00:39:42 claus Exp $
'!
!WindowGroup class methodsFor:'documentation'!
@@ -42,7 +43,7 @@
version
"
-$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.16 1994-11-28 21:01:20 claus Exp $
+$Header: /cvs/stx/stx/libview/WindowGroup.st,v 1.17 1995-02-06 00:39:42 claus Exp $
"
!
@@ -190,7 +191,7 @@
mySensor := aSensor
! !
-!WindowGroup methodsFor:'enumeration'!
+!WindowGroup methodsFor:'enumerating'!
allViewsDo:aBlock
"evaluate aBlock for all views & topviews in this group"
@@ -265,13 +266,40 @@
"process a single event from either the damage- or user input queues.
Debugger abort brings us back here."
- |event|
+ |event ignore|
self processExposeEvents.
[mySensor hasEvents] whileTrue:[
event := mySensor nextEvent.
- (views isNil and:[topViews isNil]) ifFalse:[
- event sendEvent.
+ event notNil ifTrue:[
+ (views isNil and:[topViews isNil]) ifFalse:[
+
+ ignore := false.
+ event isKeyPressEvent ifTrue:[
+ event key == #FocusNext ifTrue:[
+ self focusNext.
+ ignore := true
+ ].
+ event key == #FocusPrevious ifTrue:[
+ self focusPrevious.
+ ignore := true
+ ].
+ ].
+ "
+ button events turn off explicit focus, and revert
+ to implicit focus control
+ "
+ (focusView notNil
+ and:[event isButtonEvent]) ifTrue:[
+ self focusView:nil
+ ].
+
+ ignore ifFalse:[
+ AbortSignal catch:[
+ event sendEventWithFocusOn:focusView.
+ ]
+ ]
+ ]
].
]
!
@@ -279,31 +307,43 @@
processExposeEvents
"process all expose events from the damage queue"
- |event view rect oldActive|
+ |event view rect oldActive x y w h|
oldActive := ActiveGroup.
- ActiveGroup := self.
- [mySensor notNil and:[mySensor hasDamage]] whileTrue:[
- event := mySensor nextDamage.
- event notNil ifTrue:[
- (views isNil and:[topViews isNil]) ifFalse:[
- event isDamage ifTrue:[
- view := event view.
- rect := event rectangle.
- view shown ifTrue:[
- view transformation notNil ifTrue:[
- view deviceExposeX:(rect left) y:(rect top) width:(rect width) height:(rect height)
- ] ifFalse:[
- view exposeX:(rect left) y:(rect top) width:(rect width) height:(rect height)
+ [
+ [mySensor notNil and:[mySensor hasDamage]] whileTrue:[
+ ActiveGroup := self.
+ event := mySensor nextDamage.
+ event notNil ifTrue:[
+ (views isNil and:[topViews isNil]) ifFalse:[
+ event isDamage ifTrue:[
+ view := event view.
+ rect := event rectangle.
+ view shown ifTrue:[
+ rect := event rectangle.
+ x := rect left.
+ y := rect top.
+ w := rect width.
+ h := rect height.
+ view transformation notNil ifTrue:[
+ view deviceExposeX:x y:y width:w height:h
+ ] ifFalse:[
+ view exposeX:x y:y width:w height:h
+ ]
]
+ ] ifFalse:[
+ "
+ mhmh - could we possibly arrive here ?
+ "
+ event sendEvent.
]
- ] ifFalse:[
- event sendEvent.
]
]
]
- ].
- ActiveGroup := oldActive
+ ] valueNowOrOnUnwindDo:[
+ ActiveGroup := oldActive.
+ oldActive := nil
+ ]
!
eventLoop
@@ -314,70 +354,80 @@
!
eventLoopWhile:aBlock
- "wait-for and process events while aBlock evaluates to true."
-
- |abortSignal|
+ "wait-for and process events.
+ Stay in this loop while there are still any views to dispatch for,
+ and aBlock evaluates to true."
- abortSignal := Object abortSignal.
- "/ ScheduledWindowGroups add:self.
+ |oldActive|
- (SignalSet with:LeaveSignal with:abortSignal)
- handle:[:ex |
- ex return
- ] do:[
- |p g oldActive mainGroup|
+ oldActive := ActiveGroup.
+"/ ScheduledWindowGroups add:self.
- isModal ifTrue:[
- mainGroup := self mainGroup.
- ].
+ [
+ (SignalSet with:LeaveSignal with:AbortSignal)
+ handle:[:ex |
+"/ ActiveGroup := oldActive.
+"/ oldActive := nil.
+ ex return
+ ] do:[
+ |p g mainGroup|
- aBlock whileTrue:[
- (views isNil and:[topViews isNil]) ifTrue:[
- "/ ScheduledWindowGroups remove:self ifAbsent:[].
- myProcess notNil ifTrue:[
- p := myProcess.
- myProcess := nil.
- p terminate.
- "not reached - there is no life after death"
- ].
- "
- this is the end of a modal loop
- (not having a private process ...)
- "
- ^ self
+ isModal ifTrue:[
+ mainGroup := self mainGroup.
].
- abortSignal handle:[:ex |
- ex return
- ] do:[
- "
- if modal, break out of the wait after some time
- to allow servicing update-events of the blocked
- windowgroup.
- "
- isModal ifTrue:[
- mySensor eventSemaphore waitWithTimeout:0.2.
- ] ifFalse:[
- Processor activeProcess setStateTo:#eventWait if:#active.
- mySensor eventSemaphore wait.
+
+ aBlock whileTrue:[
+ (views isNil and:[topViews isNil]) ifTrue:[
+"/ ScheduledWindowGroups remove:self ifAbsent:[].
+ myProcess notNil ifTrue:[
+ p := myProcess.
+ myProcess := nil.
+ p terminate.
+ "not reached - there is no life after death"
+ ].
+ "
+ this is the end of a modal loop
+ (not having a private process ...)
+ "
+ ^ self
].
- oldActive := ActiveGroup.
- ActiveGroup := self.
- self processEvent
- ].
- ActiveGroup := oldActive.
- oldActive := nil.
- "
- if modal, also check for redraw events in my maingroup
- (we arrive here after every event for myself or after the
- above timeout)
- "
- mainGroup notNil ifTrue:[
- mainGroup processExposeEvents.
+ AbortSignal handle:[:ex |
+"/ ActiveGroup := oldActive.
+"/ oldActive := nil.
+ ex return
+ ] do:[
+ "
+ if modal, break out of the wait after some time
+ to allow servicing update-events of the blocked
+ windowgroup.
+ "
+ Processor activeProcess setStateTo:#eventWait if:#active.
+ isModal ifTrue:[
+ mySensor eventSemaphore waitWithTimeout:0.2.
+ ] ifFalse:[
+ mySensor eventSemaphore wait.
+ ].
+ ActiveGroup := self.
+ self processEvent
+ ].
+"/ ActiveGroup := oldActive.
+
+ "
+ if modal, also check for redraw events in my maingroup
+ (we arrive here after every event for myself or after the
+ above timeout)
+ "
+ mainGroup notNil ifTrue:[
+ mainGroup processExposeEvents.
+ ]
]
- ]
+ ].
+ ] valueNowOrOnUnwindDo:[
+"/ ScheduledWindowGroups remove:self ifAbsent:[].
+ ActiveGroup := oldActive.
+ oldActive := nil.
].
- "/ ScheduledWindowGroups remove:self ifAbsent:[].
!
waitForExposeFor:aView
@@ -385,7 +435,9 @@
To be used after a scroll"
mySensor waitForExposeFor:aView.
- self processExposeEvents
+ AbortSignal catch:[
+ self processExposeEvents
+ ]
!
leaveEventLoop
@@ -419,7 +471,6 @@
previousGroup := nil.
myProcess isNil ifTrue:[
isModal := false.
- "/ ScheduledWindowGroups add:self.
myProcess := [
topViews notNil ifTrue:[
topViews do:[:aView |
@@ -498,7 +549,7 @@
].
views := nil.
topViews := nil.
- "/ ScheduledWindowGroups remove:self ifAbsent:[].
+"/ ScheduledWindowGroups remove:self ifAbsent:[].
!
shutdown
@@ -511,7 +562,7 @@
myProcess notNil ifTrue:[
p := myProcess.
myProcess := nil.
- "/ ScheduledWindowGroups remove:self ifAbsent:[].
+"/ ScheduledWindowGroups remove:self ifAbsent:[].
p terminate.
]
! !
@@ -544,12 +595,99 @@
isModal := false.
! !
+!WindowGroup methodsFor:'focus control'!
+
+focusSequence:aSequenceableCollection
+ "define the focus sequence for focusNext/focusPrevious.
+ Focus is stepped in the order in which subviews occur in
+ the sequence"
+
+ focusSequence := aSequenceableCollection
+!
+
+focusView
+ "return the view which has the focus"
+
+ ^ focusView
+!
+
+focusView:aViewOrNil
+ "give focus to aViewOrNil"
+
+ focusView notNil ifTrue:[
+ focusView focusOut.
+ ].
+ focusView := aViewOrNil.
+ focusView notNil ifTrue:[
+ focusView focusIn
+ ].
+
+ "
+ |top v1 v2|
+
+ top := StandardSystemView new.
+ v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top.
+ v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top.
+ top open.
+ top windowGroup focusView:v1.
+ "
+!
+
+focusNext
+ "give focus to next view in focusSequence"
+
+ |index|
+
+ focusSequence isNil ifTrue:[^ self].
+ focusView notNil ifTrue:[
+ index := (focusSequence indexOf:focusView) + 1.
+ index > focusSequence size ifTrue:[index := 1].
+ ] ifFalse:[
+ index := 1.
+ ].
+ self focusView:(focusSequence at:index)
+
+ "
+ |top v1 v2|
+
+ top := StandardSystemView new.
+ v1 := EditTextView origin:0.0@0.0 corner:1.0@0.5 in:top.
+ v2 := EditTextView origin:0.0@0.5 corner:1.0@1.0 in:top.
+ top open.
+ top windowGroup focusSequence:(Array with:v1 with:v2).
+ top windowGroup focusOn:v1.
+ (Delay forSeconds:10) wait.
+ top windowGroup focusNext.
+ "
+!
+
+focusPrevious
+ "give focus to previous view in focusSequence"
+
+ |index|
+
+ focusSequence isNil ifTrue:[^ self].
+ focusView notNil ifTrue:[
+ index := (focusSequence indexOf:focusView) - 1.
+ index < 1 ifTrue:[index := focusSequence size].
+ ] ifFalse:[
+ index := focusSequence size.
+ ].
+ self focusView:(focusSequence at:index)
+! !
+
!WindowGroup methodsFor:'printing'!
-printString
+printOn:aStream
"return a printed representation;
just for more user friendlyness, add name of process."
- myProcess isNil ifTrue:[^ super printString].
- ^ 'WindowGroup(' , myProcess nameOrId , ')'
+ myProcess isNil ifTrue:[
+ (previousGroup notNil and:[previousGroup process notNil]) ifTrue:[
+ aStream nextPutAll:('WindowGroup(modal in ' , previousGroup process nameOrId , ')').
+ ^ self.
+ ].
+ ^ super printOn:aStream
+ ].
+ aStream nextPutAll:('WindowGroup(' , myProcess nameOrId , ')')
! !