Hello,
Desiring a way to select windows directly from the keyboard, I whipped
the following up. When you press 'cmd-~', it pops up a list of all visible
SystemWindows. It also displays a thumbnail representation of the currently
selected window, and a translucent rectangle over the window (in case it is
partly or completely covered). These latter two behaviors can be independently
turned on or off (in case they slow down things too much).
I think this is kind of nifty, but it is also a bit slow. I understand that
creating thumbnails cannot be speeded up too much, but it seems to me that
the translucent rectangle is slower than it should be. I'm still getting the
hang of Morphic, so if anyone can see a glaring problem with my approach,
please let me know.
Hope it's useful,
Josh
Content-Type: TEXT/PLAIN; charset=US-ASCII; name="WindowSelection.30May1151pm.cs"
Content-ID: <Pine.LNX.3.96.990531000220.22228B(a)24.65.218.157.ab.wave.home.com>
Content-Description:
'From Squeak 2.4b of April 23, 1999 on 30 May 1999 at 11:51:49 pm'!
StringHolder subclass: #WindowListModel
instanceVariableNames: 'windowList stringList thumbnailList thumbnailHeight index defaultBackgroundColor '
classVariableNames: ''
poolDictionaries: ''
category: 'Josh-WindowSelection'!
MorphicModel subclass: #WindowListMorph
instanceVariableNames: 'thumbnail transform outline '
classVariableNames: 'OutlinesOn ThumbnailsOn '
poolDictionaries: ''
category: 'Josh-WindowSelection'!
!HandMorph methodsFor: 'event handling' stamp: 'jcg 5/14/1999 00:02'!
handleAsSpecialEvent: evt
"Tries to do something special with the event. If we can't find anything to do with it, we answer nil and let the regular event handling take over."
(evt anyButtonPressed and:
[evt controlKeyPressed and:
[lastEvent anyButtonPressed not]]) ifTrue:
[eventTransform _ MorphicTransform identity.
lastEvent _ evt.
^ self invokeMetaMenu: evt].
evt blueButtonPressed ifTrue:
[lastEvent blueButtonPressed
ifTrue: [^ self specialDrag: evt]
ifFalse: [eventTransform _ MorphicTransform identity.
lastEvent _ evt.
^ self specialGesture: evt]].
"check if the character '`' and the commandKey are pressed. If so, bring up a window menu"
((evt isKeystroke
and: [evt commandKeyPressed])
and: [evt keyValue = 96])
ifTrue: [^ WindowListModel popupPluggableList].
^ nil "event is not special after all."! !
!HandMorph methodsFor: 'event handling' stamp: 'jcg 5/3/1999 00:15'!
handleEvent: evt
| special |
eventSubscribers do: [:m | m handleEvent: evt].
"--"
"allows us to designate and handle certain events that will be handled here, and not passed on to a submorph"
special _ self handleAsSpecialEvent: evt.
special ifNotNil: [^ special].
"--"
lastEvent _ evt.
self position ~= evt cursorPoint
ifTrue: [self position: evt cursorPoint].
evt isMouse ifTrue: [
evt isMouseMove ifTrue: [^ self handleMouseMove: evt].
evt isMouseDown ifTrue: [ ^ self handleMouseDown: evt].
evt isMouseUp ifTrue: [^ self handleMouseUp: evt]].
evt isKeystroke ifTrue: [
keyboardFocus ifNotNil: [keyboardFocus keyStroke: evt].
^ self].
! !
Smalltalk renameClassNamed: #TestAltTab as: #WindowListModel!
!WindowListModel reorganize!
('window switching test')
('events' dealWithKeystroke:from: windowChosenFrom:)
('accessing' defaultBackgroundColor defaultBackgroundColor: index index: outline stringList thumbnail thumbnailHeight windowList)
('initialize' initialize)
!
!WindowListModel methodsFor: 'events' stamp: 'jcg 5/12/1999 00:36'!
dealWithKeystroke: aChar from: view
"If it is a return, do something. Otherwise, check if it is an arrow key"
(aChar = Character cr) ifTrue: [^ self windowChosenFrom: view ].
^ self arrowKey: aChar from: view.! !
!WindowListModel methodsFor: 'events' stamp: 'jcg 5/12/1999 15:01'!
windowChosenFrom: aView
"Activate the chosen window".
(windowList at: index) activate.
aView owner delete.
! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/12/1999 15:08'!
defaultBackgroundColor
^ defaultBackgroundColor! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/12/1999 15:08'!
defaultBackgroundColor: aColor
defaultBackgroundColor _ aColor.
! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/7/1999 00:59'!
index
^ index ! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/19/1999 01:39'!
index: anInteger
index _ anInteger.
self changed: #index.
! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/19/1999 01:05'!
outline
^ (windowList at: index) bounds
! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/7/1999 00:50'!
stringList
^ stringList ! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/14/1999 01:19'!
thumbnail
(thumbnailList at: index) ifNil:
[thumbnailList at: index put:
(MorphThumbnail new
height: thumbnailHeight;
width: 1200;
morphRepresented: (windowList at: index))].
^ thumbnailList at: index.
! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/14/1999 00:59'!
thumbnailHeight
^ thumbnailHeight.! !
!WindowListModel methodsFor: 'accessing' stamp: 'jcg 5/7/1999 00:49'!
windowList
^ windowList ! !
!WindowListModel methodsFor: 'initialize' stamp: 'jcg 5/19/1999 01:05'!
initialize
stringList _ self class getWindowsAsStrings.
windowList _ self class getWindows.
thumbnailList _ Array new: windowList size.
thumbnailHeight _ 90.
self index: 1.! !
!WindowListModel class reorganize!
('instance creation' new)
('choose windows' popupPluggableList)
('private' getWindows getWindowsAsStrings)
!
!WindowListModel class methodsFor: 'instance creation' stamp: 'jcg 5/12/1999 16:09'!
new
^ super new initialize.
! !
!WindowListModel class methodsFor: 'choose windows' stamp: 'jcg 5/14/1999 18:34'!
popupPluggableList
"pop up a PluggableList to choose the desired SystemWindow from."
| list model win |
model _ WindowListModel new.
"create a list"
list _ PluggableListMorph
on: model
list: #stringList
selected: #index
changeSelected: #index:
menu: nil
keystroke: #dealWithKeystroke:from:.
win _ WindowListMorph
newBounds: (Rectangle center: Sensor mousePoint extent: 300@400)
model: model
slotName: 'Window Chooser'
list: list.
win color: Color lightBlue.
"create a list"
" list _ PluggableListMorph
on: model
list: #stringList
selected: #index
changeSelected: #index:
menu: nil
keystroke: #dealWithKeystroke:from:.
list position: (win bounds topLeft + (10@10)).
list extent: (win extent - (20@110)).
win addMorph: list."
win openInWorld.
! !
!WindowListModel class methodsFor: 'private' stamp: 'jcg 5/6/1999 23:45'!
getWindows
"answers an Array of SystemWindow in world"
^ SystemWindow windowsIn: self currentWorld satisfying: [:dummy | true].! !
!WindowListModel class methodsFor: 'private' stamp: 'jcg 5/7/1999 00:23'!
getWindowsAsStrings
"answers an Array of string names of SystemWindows in world"
| prefix |
prefix _ 'a SystemWindow('.
^ self getWindows collect:
[:window | window asString
copyFrom: prefix size + 1
to: window asString size - 1].! !
!WindowListMorph methodsFor: 'updating' stamp: 'jcg 5/19/1999 01:32'!
update: aSymbol
"Refer to the comment in View|update:."
aSymbol == #index ifTrue:
[ThumbnailsOn ifTrue: [self thumbnail: model thumbnail].
OutlinesOn ifTrue: [self outline: model outline]].
"[ self outline: model outline]."
^ self.! !
!WindowListMorph methodsFor: 'private' stamp: 'jcg 5/19/1999 01:05'!
outline: aRectangle
outline bounds: aRectangle
! !
!WindowListMorph methodsFor: 'private' stamp: 'jcg 5/14/1999 19:15'!
positionList: aListMorph
aListMorph width: (self width - 20).
aListMorph height: (self height - 20 - model thumbnailHeight).
aListMorph position: (self topLeft + (10@10)).
! !
!WindowListMorph methodsFor: 'private' stamp: 'jcg 5/14/1999 18:43'!
positionThumbnail: aThumbnail
| x y |
x _ self left + (self width - thumbnail width / 2) rounded.
y _ self bottom - thumbnail height - 10.
thumbnail position: x@y.
! !
!WindowListMorph methodsFor: 'private' stamp: 'jcg 5/14/1999 19:11'!
thumbnail: aThumb
| x y |
thumbnail ifNotNil: [thumbnail delete].
thumbnail _ aThumb.
self addMorph: thumbnail.
" thumbnail ifNotNil: [thumbnail hide].
thumbnail _ aThumb show.
x _ self left + (self width - aThumb width / 2) rounded.
y _ self bottom - aThumb height - 10.
aThumb position: x@y.
self addMorph: aThumb.
transform addMorph: aThumb.
aThumb openInWorld."! !
!WindowListMorph methodsFor: 'initilization' stamp: 'jcg 5/19/1999 01:25'!
initialize
super initialize.
outline _ RectangleMorph new color: (Color blue alpha: 0.7).
outline extent: 0@0.
self addMorph: outline.
"transform _ TransformMorph new.
self addMorphCentered: transform."! !
!WindowListMorph methodsFor: 'change reporting' stamp: 'jcg 5/14/1999 19:02'!
layoutChanged
submorphs do: [:m | (m class = PluggableListMorph)
ifTrue: [ self positionList: m ]
ifFalse: [ (m class = MorphThumbnail)
ifTrue: [ self positionThumbnail: m ]]].
super layoutChanged.
! !
!WindowListMorph class reorganize!
('instance creation' newBounds:model:slotName: newBounds:model:slotName:list:)
('display properties' setOutlineDisplay: setThumbnailDisplay:)
!
!WindowListMorph class methodsFor: 'instance creation' stamp: 'jcg 5/14/1999 01:53'!
newBounds: aRectangle model: aModel slotName: aString
| newguy |
newguy _ super
newBounds: aRectangle
model: aModel
slotName: aString.
"hack. shouldn't be necessary if MorphicModel uses 'model:' instead of assignment"
self flag: #joshG.
aModel addDependent: newguy.
^ newguy! !
!WindowListMorph class methodsFor: 'instance creation' stamp: 'jcg 5/14/1999 18:38'!
newBounds: aRectangle model: aModel slotName: aString list: aListMorph
| newguy |
newguy _ super
newBounds: aRectangle
model: aModel
slotName: aString.
newguy addMorph: aListMorph.
"hack. shouldn't be necessary if MorphicModel uses 'model:' instead of assignment"
self flag: #joshG.
aModel addDependent: newguy.
^ newguy! !
!WindowListMorph class methodsFor: 'display properties' stamp: 'jcg 5/19/1999 01:31'!
setOutlineDisplay: aBool
OutlinesOn _ aBool.! !
!WindowListMorph class methodsFor: 'display properties' stamp: 'jcg 5/19/1999 01:30'!
setThumbnailDisplay: aBool
ThumbnailsOn _ aBool.! !
HandMorph removeSelector: #handleAsSpecialKeyboardEvent:!
HandMorph removeSelector: #handleSpecialEvent:!
WindowListModel removeSelector: #windowChosen!
WindowListModel removeSelector: #stringList:!
WindowListModel removeSelector: #windowList:!
WindowListModel removeSelector: #windowBounds!
WindowListModel removeSelector: #getWindows!
WindowListMorph removeSelector: #thumbnailHeight!
WindowListMorph removeSelector: #thumbnailHeight:!
WindowListMorph class removeSelector: #newBounds:model:slotName:thumbnailHeight:!
"Postscript:
By default, we want to enable both the outline and thumbnail display options."
WindowListMorph setOutlineDisplay: true.
WindowListMorph setThumbnailDisplay: true.
!