ActiveHelp.st
author claus
Wed, 30 Aug 1995 01:43:11 +0200
changeset 98 ab8ed9e213d0
parent 97 72fbe8f7130f
child 100 0300e64bb883
permissions -rw-r--r--
.

"
 COPYRIGHT (c) 1995 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.
"


'From Smalltalk/X, Version:2.10.5 on 26-mar-1995 at 10:19:20 am'!

EventListener subclass:#ActiveHelp
	 instanceVariableNames:'currentView currentHelpView currentFrame showProcess closeProcess'
	 classVariableNames:'DelayTime ShowTime TheOneAndOnlyHelpListener'
	 poolDictionaries:''
	 category:'Interface-Help'
!

!ActiveHelp class methodsFor:'documentation'!

version
"
$Header: /cvs/stx/stx/libview2/ActiveHelp.st,v 1.4 1995-08-29 23:42:57 claus Exp $
"
!

documentation
"
    The active help listener.
    The one and only instance of myself intercepts incoming mouse & keyboard 
    events for the display device, being especially interested in view-enter/
    leave ebents. When such an event arrives, it asks the corresponding view
    or its model for a help message and display it via an ActiveHelpView.
    All I need for automatic help is some model/view/applicationModel along
    the superview chain of the entered component, which responds to the
    #helpTextFor: message with a non-nil (string-) answer.
    I close down the help view after a while, if a key is pressed or the mouse
    moved to another view.
"
!

copyright
"
 COPYRIGHT (c) 1995 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.
"

! !

!ActiveHelp class methodsFor:'initialization'!

initialize
    ShowTime := 15.
    DelayTime := 1.

    "
     ActiveHelp initialize
    "
! !

!ActiveHelp class methodsFor:'startup'!

start
    TheOneAndOnlyHelpListener isNil ifTrue:[
	TheOneAndOnlyHelpListener := self new.
    ].
    TheOneAndOnlyHelpListener listen

    "
     ActiveHelp start
    "
!

stop
    TheOneAndOnlyHelpListener notNil ifTrue:[
	TheOneAndOnlyHelpListener unlisten.
    ].
    TheOneAndOnlyHelpListener := nil

    "
     ActiveHelp stop
    "
!

isActive 
    ^ TheOneAndOnlyHelpListener notNil
! !

!ActiveHelp methodsFor:'private'!

helpTextFor:aView atX:x y:y
    |model text view org found v sv|

    view := aView.

    (model := aView model) notNil ifTrue:[
"/ model printNL.
	(model respondsTo:#helpTextFor:at:) ifTrue:[
	    text := model helpTextFor:aView at:x@y.
	    text notNil ifTrue:[^ text].
	].
	(model respondsTo:#helpTextFor:) ifTrue:[
	    text := model helpTextFor:aView.
	    text notNil ifTrue:[^ text].
	]
    ].

    (aView respondsTo:#helpText) ifTrue:[
	text := aView helpText.
	text notNil ifTrue:[^ text].
    ].

    "walk up the chain - maybe someone knows about its subview ..."
    v := aView.

    [(sv := v superView) notNil] whileTrue:[
	(model := sv model) notNil ifTrue:[
	    (model respondsTo:#helpTextFor:at:) ifTrue:[
		text := model helpTextFor:aView at:x@y.
		text notNil ifTrue:[^ text].
	    ].
	    (model respondsTo:#helpTextFor:) ifTrue:[
		text := model helpTextFor:aView.
		text notNil ifTrue:[^ text].
	    ]
	].

	(sv respondsTo:#helpTextFor:) ifTrue:[
	    text := sv helpTextFor:aView.
	    text notNil ifTrue:[^ text].
	    text := sv helpTextFor:v.
	    text notNil ifTrue:[^ text].
	 ].
	 v := sv.
    ].

    (view class respondsTo:#helpText) ifTrue:[
	text := view class helpText.
	text notNil ifTrue:[^ text].
    ].

    ^ nil
!

hideIfPointerLeft:aView
    |whereOnScreen p|

    showProcess notNil ifTrue:[
	p := showProcess. showProcess := nil.
	p terminate.
    ].

    whereOnScreen := aView device pointerPosition.

    (currentFrame notNil
    and:[(currentFrame insetBy:1@1) containsPoint:whereOnScreen]) ifFalse:[
	self hideHelp.
	currentView := nil
    ].
! !

!ActiveHelp methodsFor:'listening'!

buttonPress:state x:x y:y view:view
    self hideHelp.
    ^ false
!

pointerEnter:state x:x y:y view:aView
    |text p|

    showProcess notNil ifTrue:[
	p := showProcess. showProcess := nil.
	p terminate.
    ].
    self hideIfPointerLeft:aView.
    aView topView == currentHelpView ifTrue:[
	^ true
    ].

    text := self helpTextFor:aView atX:x y:y.

    text notNil ifTrue:[
	DelayTime > 0 ifTrue:[
	    showProcess notNil ifTrue:[
		p := showProcess. showProcess := nil.
		p terminate.
	    ].
	    showProcess := [
		    (Delay forSeconds:DelayTime) wait.
		    showProcess := nil.
		    self showHelp:text for:aView
	    ] forkAt:(Processor userSchedulingPriority + 1).
	] ifFalse:[
	    self showHelp:text for:aView
	]
    ].

    ^ false
!

pointerLeave:state view:view
    self hideIfPointerLeft:view.
    ^ false
!

keyPress:state x:x y:y view:view
    self hideHelp.
    ^ false
!

buttonMotion:state x:x y:y view:view
    self hideIfPointerLeft:view.
    ^ false
! !

!ActiveHelp methodsFor:'show / hide help'!

hideHelp
    |p|

    showProcess notNil ifTrue:[
	p := showProcess. showProcess := nil.
	p terminate.
    ].
    currentHelpView notNil ifTrue:[
	[
	    currentHelpView destroy.
	    currentHelpView := nil.
	    currentView := nil.
	] valueUninterruptably
    ].
    currentFrame := nil.
    closeProcess notNil ifTrue:[
	p := closeProcess. closeProcess := nil.
	p terminate.
    ]
!

showHelp:aHelpText for:view
    |org p|

    view == currentView ifTrue:[^ self].

    closeProcess notNil ifTrue:[
	p := closeProcess. closeProcess := nil.
	p terminate.
    ].
    currentHelpView notNil ifTrue:[
	self hideHelp
    ].

    org := view originRelativeTo:nil.
    currentFrame := org extent:view extent.
    org :=org + (view extent // 2).

    currentHelpView := ActiveHelpView for:aHelpText withCRs.

    org := view device pointerPosition.
    org := org + (20@20).
    (org x + currentHelpView width) > view device width ifTrue:[
	org := (org x - currentHelpView width) @ org y
    ].
    (org y + currentHelpView height) > view device height ifTrue:[
	org := org x @ (org y - currentHelpView height).
    ].

    currentHelpView origin:org.
"/    currentHelpView open.
    currentHelpView realize.
    currentHelpView enableButtonMotionEvents.
    currentHelpView enableMotionEvents.

    currentView := view.
    closeProcess := [
	Process terminateSignal handle:[:ex |
	    closeProcess := nil.
	] do:[
	    (Delay forSeconds:ShowTime) wait.
	    [
		currentHelpView notNil ifTrue:[
		    currentHelpView destroy.
		    currentHelpView := nil.
		]
	    ] valueUninterruptably
	].
    ] forkAt:(Processor userSchedulingPriority + 1).
! !

ActiveHelp initialize!