From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 1:12:50 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>FlyByHelpSystem</name> <environment>UI</environment> <super>Core.Subsystem</super> <private>false</private> none flyByHelpWasEnabled <imports></imports> <category>Tools-FlyByHelp</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> </class> <comment> UI.FlyByHelpSystem
This subsystem manages the Fly By Help. This doesn't require much management, but we want to turn it off when we're saving the image, because if the images comes up headless, having fly by help running can cause bad things to happen. Instance Variables: flyByHelpWasEnabled <Boolean> Was fly by help on before we saved the image.
</comment> <class> <name>FlyByHelpWindowSensor</name> <environment>UI</environment> <super>UI.EventSensor</super> <private>false</private> none <imports></imports> <category>OS-Window System</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> </class> <comment> UI.FlyByHelpWindowSensor
This specialized sensor for FlyByHelpWindows notifies the window of mouse move events. The help window then delivers those events to the help tracker for consideration.
</comment> <class> <name>NullFlyByHelpTracker</name> <environment>UI</environment> <super>Core.Object</super> <private>false</private> none <imports></imports> <category>Interface-Events-Trackers</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> </class> <comment> UI.NullFlyByHelpTracker
This is a stub class for Fly-By Help. If the help facility isn't loaded, or is de-activated, then an instance of NullFlyByHelpTracker will be the default instance for FlyByHelpTracker. This responds to a minimal set of messages that are sent by windowing system code to notify the fly by help system, and ignores them.
</comment> <class> <name>FlyByHelpWindow</name> <environment>UI</environment> <super>UI.TransientWindow</super> <private>false</private> none tracker <imports></imports> <category>OS-Window System</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> </class> <comment> UI.FlyByHelpWindow
I am the popup window that displays help text. There is normally a singleton instance of the help tracker that holds onto an instance of myself and uses it over and over again to display help messages by remapping. A tracker may, however, at some point discard one help window and start using another. I also use a special window sensor that notifies me of all mouse move events so I can in turn notify the tracker about them. The thing is, some mouse move events may come to me yet it is the tracker that is interested in these events because it might decide to close the help window when the mouse moves too far. Instance Variables: tracker <FlyByHelpTracker> The tracker that created me; I need it to get the help text to display. Class Variables: DefaultBackgroundPaint <ColorValue> The color to use for the background of the popup window. DefaultForegroundPaint <ColorValue> The color to use for the foreground of the popup window.
</comment> <class> <name>FlyByHelpTracker</name> <environment>UI</environment> <super>Core.Object</super> <private>false</private> none entryAction exitAction interrupt mutex targetController helpPopup skipEntry skipExit <imports></imports> <category>Interface-Events-Trackers</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> </class> <comment> UI.FlyByHelpTracker
A singleton instance of this class is responsible for keeping track of the state of the user interaction with respect to the fly-by help. It is essentially a state machine, with four states listed below and three events that can occur in each state: mouse entry, mouse exit, and interrupt. States are represented as triplets of methods, one method for each possible event. Controllers notify the tracker of mouse entry and exit events, and the tracker routes control to an appropriate method. Interrupts methods are invoked by a background processes. All event processing code runs within critical sections on the mutex maintained by the tracker, to prevent the UI and interrupt processes from trampling over each other. The picture is somewhat complicated by the fact that popping up a help window causes the original controller to receive an exit event. Similarly, closing a help window after it expires generates a bogus entry event on the original controller. To avoid these, the tracker maintains two flags: 'skipEntry' and 'skipExit'. Setting either to true causes the tracker to ignore the next incoming event of that type and then revert it to false. The picture is further complicated by the fact that this does not happen on X11. States: Cold - An instance starts out in this state. No interrupts are scheduled. Events: entry - switch to the armed state; exit - unexpected, ignore. Armed - The tracker is ready to pop up the help window after an initial delay. An interrupt is scheduled to open the window after a timeout. Events: entry - unexpected, ignored; exit - the mouse has left the view, kill the scheduled interrupt and switch to the cold state; interrupt - pop up the help window and switch to the reaper state. Reaper - A help window is currently open. An interrupt is scheduled to close it after a timeout. Events: entry - unexpected, ignore; exit - close the popup, unschedule the interrupt, switch to the warm state; interrupt - close the popup, switch to the cold state. Warm - A help window has just been closed because the mouse has left the view. An interrupt is scheduled to switch the machine to cold state after a short timeout. However, the mouse pointer enters another view that can provide help while the machine is still warm, it opens the help window immediately after entering. Events: entry - immediately open the help window and switch to the reaper state; exit - unexpected, ignore; interrupt - switch to the cold state. One additional state is Idle. An idle tracker ignores any mouse events and has no interrupts scheduled. The singleton tracker can be switched to the idle state by sending #disable to the class. #enable sent to the class reactivates the tracker (puts it into the cold state). To ease the debugging, all relevant methods are instrumented with #log: messages sent to self. If the reporting code in the #log message is enabled, state switches and events are reported to the Transcript as they occur. It is wise to keep that instrumentation as this is the easiest if not the only way to debug state transitions. Instance Variables: entryAction <Symbol> Selector of the message to send to self on mouse entry event. exitAction <Symbol> Selector of the message to send to self on mouse exit event. interrupt <Process|nil> If not nil, a process scheduled to wake up after a while and perform one of the interrupt methods of the receiver. mutex <Semaphore> A mutual exclusion semaphore. Execution of all event response and interrupt methods is protected by it to ensure flawless state switching. targetController <Controller> Controller for view help opens for. helpPopup <FlyByHelpWindow> Window displaying help for tracker. skipEntry <Boolean> Entry transition marker (private). skipExit <Boolean> Exit transition marker (private). Class Variables: Default <FlyByHelpTracker> The singleton instance of this class. OpenDelay <SmallInteger> The default number of milliseconds to delay once the tracker is armed before opening up the window. CloseDelay <SmallInteger> The default number of milliseconds to display the help window.
</comment> <name>DefaultForegroundPaint</name> <environment>UI.FlyByHelpWindow</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer>ColorValue black</initializer> <attributes> <package>Tools-FlyByHelp</package> </attributes> <name>DefaultBackgroundPaint</name> <environment>UI.FlyByHelpWindow</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer>ColorValue red: 1.0 green: 1.0 blue: 0.749969</initializer> <attributes> <package>Tools-FlyByHelp</package> </attributes> <name>Default</name> <environment>UI.FlyByHelpTracker</environment> <private>true</private> <constant>false</constant> <category>singleton</category> <attributes> <package>Tools-FlyByHelp</package> </attributes> <name>CloseDelay</name> <environment>UI.FlyByHelpTracker</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer>5000</initializer> <attributes> <package>Tools-FlyByHelp</package> </attributes> <name>OpenDelay</name> <environment>UI.FlyByHelpTracker</environment> <private>false</private> <constant>false</constant> <category>defaults</category> <initializer>500</initializer> <attributes> <package>Tools-FlyByHelp</package> </attributes> <methods> UI.FlyByHelpSystem <category>actions</category>
pauseAction "Remember if fly by help was active, and shut it down while we save the image." super pauseAction. flyByHelpWasEnabled := FlyByHelpTracker isEnabled. FlyByHelpTracker disable.
resumeAction "If fly by help was on before we saved, turn it back on when we continue running." super resumeAction. flyByHelpWasEnabled ifTrue: [FlyByHelpTracker enable].
setUp "If fly by help was active when this image was saved, turn it back on. This will only happen if the windowing system is active. Note that the variable may be nil if this is initial setup after this was loaded. The default for the FlyByHelp system is 'enabled'." super setUp. flyByHelpWasEnabled ifNil: [ FlyByHelpTracker enable ] ifNotNil: [ flyByHelpWasEnabled ifTrue: [ FlyByHelpTracker enable ] ].
</methods> <methods> UI.FlyByHelpSystem <category>prerequisites</category>
prerequisiteSystems ^Array with: WindowingSystem.
</methods> <methods> UI.FlyByHelpWindowSensor <category>event processing</category>
eventButtonPress: event "Mac requires this event to be explicitly redirected to the main window. On other platforms mouse clicks are redirected by the VM but doing it explicitly does no harm." | targetSensor | targetSensor := window targetWindowSensor. targetSensor notNil ifTrue: [targetSensor eventButtonPress: event]
eventKeyPress: event "All keyboard events should go to the window I am serving so the user typing while the help popup is open is not lost." | targetSensor | targetSensor := window targetWindowSensor. targetSensor notNil ifTrue: [targetSensor eventKeyPress: event]
eventKeyRelease: event "All keyboard events should go to the window I am serving so the user typing while the help popup is open is not lost." | targetSensor | targetSensor := window targetWindowSensor. targetSensor notNil ifTrue: [targetSensor eventKeyRelease: event]
eventMouseMoved: event "The mouse has changed position. Pass the event on to the window" ^self window mouseMoved: self state mousePoint
</methods> <methods> UI.NullFlyByHelpTracker <category>events</category>
noticeEntryInto: aController
noticeExitFrom: aController
noticeRedButtonPress
</methods> <methods> UI.NullFlyByHelpTracker <category>testing</category>
deactivate
isActive ^false
</methods> <methods> UI.FlyByHelpWindow <category>private</category>
preferredDisplayBox "Preferentially align the left edge of the help window with the current mouse location and the top edge with the bottom of the mouse pointer box. Make sure the result fits the screen!" | mouse extent origin | mouse := self sensor state mousePoint. extent := component preferredBounds extent + (6 @ 0). origin := mouse + (0 @ 18). origin y > Screen default bounds bottom ifTrue: [origin := mouse - (0 @ (2 + extent y))]. ^Screen default makeRectangleVisible: (origin extent: extent)
refresh: aText "Change the text I display and update my size and position on the screen, as well as the position of my component (the help text)." self component: (self wrap: aText); displayBox: self preferredDisplayBox. component bounds: self bounds
sensorClass ^FlyByHelpWindowSensor
wrap: aStringOrText | text wrapper textWrapper foregroundPaint | text := ComposedText withText: aStringOrText style: self widgetPolicy lookPolicyClass systemTextStyle. foregroundPaint := self defaultForegroundPaint. textWrapper := (GraphicsAttributesWrapper on: text) attributes: (GraphicsAttributes new paint: foregroundPaint). wrapper := BorderedWrapper on: (TranslatingWrapper on: textWrapper at: 2@0). wrapper borderColor: foregroundPaint. ^wrapper
</methods> <methods> UI.FlyByHelpWindow <category>testing</category>
canProcessEvent ^false
isInvalid ^component isNil or: [handle isNil]
</methods> <methods> UI.FlyByHelpWindow <category>properties</category>
defaultBackgroundPaint ^self class defaultBackgroundPaint
defaultForegroundPaint ^self class defaultForegroundPaint
edgeDecorationPolicy ^LookPreferences edgeDecorationPolicy
</methods> <methods> UI.FlyByHelpWindow <category>initialize-release</category>
initializeTracker: aTracker tracker := aTracker
remap "If the tracker can supply a meaningful help text, update self to include it and display at the current mouse location." | text | (text := tracker helpText) ifNil: [^self]. self refresh: text; scheduleWindow; map.
</methods> <methods> UI.FlyByHelpWindow <category>events</category>
mouseMoved: aPoint tracker helpWindowMouseMoved: aPoint
windowEventDispatcher ^self
</methods> <methods> UI.FlyByHelpWindow <category>accessing</category>
label ^(#FlyByHelp << #dialogs >> 'FlyByHelp')
targetController "Answer the controller of the widget I am serving, or nil if it cannot be determined." ^tracker isNil ifTrue: [nil] ifFalse: [tracker targetController]
targetWindowSensor "Answer the sensor of the window whose widget I am serving, or nil if it cannot be determined." | target | target := self targetController. ^target isNil ifTrue: [nil] ifFalse: [target sensor windowSensor]
</methods> <methods> UI.FlyByHelpWindow class <category>accessing</category>
defaultBackgroundPaint ^DefaultBackgroundPaint
defaultBackgroundPaint: colorValue DefaultBackgroundPaint := colorValue
defaultForegroundPaint ^DefaultForegroundPaint
defaultForegroundPaint: colorValue DefaultForegroundPaint := colorValue
</methods> <methods> UI.FlyByHelpWindow class <category>opening</category>
for: aTracker ^(self newIn: (0@0 extent: 1@1) withType: #popUp) initializeTracker: aTracker; isEventDriven: true; yourself
</methods> <methods> UI.FlyByHelpTracker <category>accessing</category>
activate self cautiously: [mutex critical: [self enterColdState]]
deactivate self cautiously: [mutex critical: [self enterIdleState]]
helpWindowMouseMoved: aPoint "The help window is the only expected sender of this. It is currently active and tracking the mouse. This means we are in the reaper state. The window notifies us that the mouse pointer has just changed position. This may lead to the widget losing the pointer, which is equivalent to a #reaperExitFrom: event." mutex critical: [self cautiously: [targetController notNil ifTrue: [targetController viewContainsCursor ifFalse: [self log: 'mm'; reaperExitFrom: targetController]]]]
isActive ^entryAction ~~ #ignore:
noticeEntryInto: aController "The argument controller notifies us that the mouse has just entered its bounds. Be VERY careful editing this method. Control passes through it very often on a locked semaphore. Any snag it hits may freeze the image. Normally, the #cautiously: method logic takes care of switching the system to a brand new tracker if something goes wrong, thus avoiding the UI deadlock on a tracker suspended inside a critical section." mutex critical: [self cautiously: [skipEntry ifTrue: [skipEntry := false. self log: 'e-'] ifFalse: [self perform: entryAction with: aController]]]
noticeExitFrom: aController "The argument controller notifies us that the mouse has just left its bounds. Be VERY careful editing this method. Control passes through it very often on a locked semaphore. Any snag it hits may freeze the image. Normally, the #cautiously: method logic takes care of switching the system to a brand new tracker if something goes wrong, thus avoiding the UI deadlock on a tracker suspended inside a critical section." mutex critical: [self cautiously: [skipExit ifTrue: [skipExit := false. self log: 'x-'] ifFalse: [self perform: exitAction with: aController]]]
noticeRedButtonPress "If the mouse is pressed, go immediately into cold state as this indicates the user knows what to do. What's even more important, popping up a window in this case would take control away from the widget's controller." self inIdleState ifTrue: [^self]. mutex critical: [self cautiously: [self inReaperState ifTrue: [self closePopup]. self enterColdState]]
targetController "When there is activity -- the popup window is open or is scheduled to be open -- this reports the controller of the widget the tracker is serving. Otherwise this returns nil." ^targetController
</methods> <methods> UI.FlyByHelpTracker <category>events</category>
armedEntryInto: aController "While normally a mouse enters a controller when the tracker is in cold or warm state, this may happen in other states as well, since entries and exits may not be reported correctly as the mouse moves over a window partially occluded by other windows. When this happens, the best we can do is kill the scheduled interrupt (since another controller is in charge now and nobody needs help for the old one) and do everything we normally do on a mouse entry in cold state." self log: 'ae'. self unscheduleInterrupt. self coldEntryInto: aController
armedExitFrom: aController "The mouse pointer has left the controller's view before the interrupt to open a help window had a chance to fire. Kill it and switch back to the cold (expecting entry) state." self log: 'ax'; unscheduleInterrupt; enterColdState
armedInterrupt "Invoked by the interrupt process scheduled upon entering the armed state. Supposed to pop up the help window. Must ensure that the original controller still has the cursor, as the cursor may leave the view without triggering the exit event--for example, by switching to another window. If that happens, do nothing and switch to the cold state, expecting another controller to work with. Any execution of this method should be protected by the mutex." self log: 'ai'. targetController viewHasCursor ifFalse: [targetController := nil. self log: 'LOST'. self enterColdState] ifTrue: [self openPopup. self enterReaperState]
coldEntryInto: aController "The mouse pointer has entered the controller's view. We are in the cold state--there has been a while since the previous help window was visible. If the controller can provide help text, schedule an interrupt to pop up a help window after a delay. Remember the controller because we will have to make sure it is still active before actually popping up the help window. If the controller cannot provide help text, don't bother doing anything." self log: 'ce'. (self hasHelp: aController) ifTrue: [targetController := aController. self enterArmedState]
coldExitFrom: aController "The mouse pointer has left the controller's view. In the cold state there is nothing to clean up." self log: 'cx'
ignore: aController "Do nothing; used by the Idle state."
reaperEntryInto: aController "This event is not normally expected in this state, but it is spuriously delivered as the popup window goes up. For this reason, there is no other choice but to ignore it." self log: 're'
reaperExitFrom: aController "The mouse pointer has left the controller's view. As we are in the reaper state, there is a scheduled window closing interrupt that has never had a chance to fire. Close the current window." self log: 'rx'; unscheduleInterrupt; closePopup; enterWarmState
reaperInterrupt "Invoked by the interrupt process scheduled upon entering the reaper state. Supposed to shut down the help window and switch the tracker to the cold state. Any execution of this method should be protected by the mutex." self log: 'ri'. self closePopup. self enterColdState
warmEntryInto: aController "The mouse pointer has entered the controller's view. As this is the warm state, the previous help window has been closed very recently. There is a cooldown interrupt pending. Kill it and open a help window for the current widget immediately. If the current widget cannot provide help, remain in the warm state." self log: 'we'. self unscheduleInterrupt. (self hasHelp: aController) ifTrue: [targetController := aController. self openPopup. self enterReaperState] ifFalse: [self scheduleCooldownInterrupt]
warmExitFrom: aController "This event is not normally expected in this state, but it can occur in a partially occluded window. There is nothing to do." self log: 'wx'
warmInterrupt "Invoked by the interrupt process scheduled upon entering the warm state. Supposed to switch the tracker to the cool state. Any execution of this method should be protected by the mutex." self log: 'wi'. self enterColdState
</methods> <methods> UI.FlyByHelpTracker <category>state switching</category>
enterArmedState "See description of states in the class comment." self log: 'armed'. entryAction := #armedEntryInto:. exitAction := #armedExitFrom:. self schedulePopupInterrupt
enterColdState "See description of states in the class comment." self log: 'cold'. entryAction := #coldEntryInto:. exitAction := #coldExitFrom:. targetController := nil. self unscheduleInterrupt
enterIdleState "See description of states in the class comment." self log: 'idle'. entryAction := #ignore:. exitAction := #ignore:. self unscheduleInterrupt; closePopup. targetController := nil
enterReaperState "See description of states in the class comment." self log: 'reaper'. entryAction := #reaperEntryInto:. exitAction := #reaperExitFrom:. self scheduleReaperInterrupt
enterWarmState "See description of states in the class comment." self log: 'warm'. entryAction := #warmEntryInto:. exitAction := #warmExitFrom:. self scheduleCooldownInterrupt
</methods> <methods> UI.FlyByHelpTracker <category>privileged</category>
helpText "Answer the text to display in the fly-by help popup. Answer nil if no help text is available." | helpText | helpText := [targetController view helpText] on: Error do: [:ex | ex return: nil]. ^helpText isNil ifTrue: [nil] ifFalse: [helpText asText]
</methods> <methods> UI.FlyByHelpTracker <category>initialize-release</category>
initialize "FlyByHelpTracker flush" interrupt := nil. mutex := Semaphore forMutualExclusion. skipEntry := false. skipExit := false. self recreatePopup; enterColdState
</methods> <methods> UI.FlyByHelpTracker <category>parameters</category>
closeDelay "The delay after the help window opens and before it is closed." ^Delay forMilliseconds: self class closeDelay
cooldownDelay "The delay it takes for a warm tracker to become cold. (See the explanation of tracker states in the class comment)." ^Delay forMilliseconds: 300
openDelay "The delay after the mouse enters a widget and before the help window opens." ^Delay forMilliseconds: self class openDelay
</methods> <methods> UI.FlyByHelpTracker <category>help window</category>
closePopup "Closing the popup will generate a bogus entry event but that's OK because the event response code can deal with that. Unmapping may alse cause an error if this request comes before the window was ever open during the current image session." self log: 'CLOSE'. [helpPopup unmap. helpPopup unscheduleWindow. targetController sensor window becomeActive] on: Error do: [:ex | ex return]
openPopup "The first time within a new image session, mapping the popup window may fail. If this happens, simply recreate it and try again." | triedOnce | self log: 'OPEN'. triedOnce := false. [helpPopup remap] on: Error do: [:ex | triedOnce ifTrue: [ex pass] ifFalse: [triedOnce := true. self recreatePopup. ex retry]]
recreatePopup helpPopup := FlyByHelpWindow for: self
</methods> <methods> UI.FlyByHelpTracker <category>private</category>
cautiously: aBlock "Evaluate aBlock. In case of an error, flush the class to make it use a new singleton tracker instead of the current one, then pass the exception to make the debugger come up. Without this precaution, the current singleton tracker with a locked semaphore would still be the one to receive entry/exit notifications from controllers, and would almost immediately lock the UI process. Just to be extra paranoid, switch the fresh tracker to the idle state so that there is no chance the problem that caused the exception is triggered again." ^aBlock on: Error do: [:ex | self class flush. self class disable. ex pass]
hasHelp: aController "Determine if the controller is worth attention. Those that cannot provide help text are ignored." | helpText | helpText := [aController view helpText] on: Error do: [:ex | ex return: nil]. ^helpText notNil and: [helpText asText isEmpty not and: [aController viewContainsCursor]]
inIdleState ^#ignore: == entryAction
inReaperState ^#reaperEntryInto: == entryAction
log: aString "A handy little tool to debug state switches. All the key state transition methods throughout the class are instrumented to print an event log. Because that log is the easiest - if not the only - way to debug tracker states, if you don't need it, it is wiser to make this method a no-op rather than remove the instrumentation. Writing to the Transcript can fail at early stages of image startup, so the method has to protect against that." "[Transcript space; show: aString] on: Error do: [:ex | ex return]"
scheduleCooldownInterrupt self unscheduleInterrupt. self log: 'intc+'. interrupt := [self cooldownDelay wait. mutex critical: [self cautiously: [self warmInterrupt]]] forkAt: Processor userInterruptPriority
schedulePopupInterrupt self unscheduleInterrupt. self log: 'intp+'. interrupt := [self openDelay wait. mutex critical: [self cautiously: [self armedInterrupt]]] forkAt: Processor userInterruptPriority
scheduleReaperInterrupt self unscheduleInterrupt. self log: 'intr+'. interrupt := [self closeDelay wait. mutex critical: [self cautiously: [self reaperInterrupt]]] forkAt: Processor userInterruptPriority.
unscheduleInterrupt "Assuming execution of this is protected by the mutex. Do not terminate the interrupt process if we are indeed that very process. This is OK, since by design of this class it means the interrupt process is about to terminate very soon by running to normal completion." self log: 'int-'. interrupt notNil ifTrue: [(interrupt suspendedContext notNil and: [interrupt ~~ Processor activeProcess]) ifTrue: [interrupt terminate. self log: '-']. interrupt := nil]
</methods> <methods> UI.FlyByHelpTracker <category>obsolete</category>
skipNextEntry "Does not seem to be needed anymore with MultiProcUI. Verified not to be on Windoze. If other platforms are fine as well, both the two #skip... methods and related variables and other code using it can be ripped out, and good riddance!" #unix == OSHandle currentOS ifFalse: [skipEntry := true]
skipNextExit "Does not seem to be needed anymore with MultiProcUI. Verified not to be on Windoze. If other platforms are fine as well, both the two #skip... methods and related variables and other code using it can be ripped out, and good riddance!" #unix == OSHandle currentOS ifFalse: [skipExit := true]
</methods> <methods> UI.FlyByHelpTracker class <category>accessing-preferences</category>
closeDelay ^CloseDelay
closeDelay: milliseconds CloseDelay := milliseconds
defaultBackgroundPaint ^FlyByHelpWindow defaultBackgroundPaint
defaultBackgroundPaint: aColorValue FlyByHelpWindow defaultBackgroundPaint: aColorValue. self updatePopupWindow
defaultForegroundPaint ^FlyByHelpWindow defaultForegroundPaint
defaultForegroundPaint: aColorValue FlyByHelpWindow defaultForegroundPaint: aColorValue. self updatePopupWindow
isEnabled ^Default notNil and: [Default isActive]
isEnabled: aBoolean aBoolean ifTrue: [self enable] ifFalse: [self disable]
openDelay ^OpenDelay
openDelay: milliseconds OpenDelay := milliseconds
</methods> <methods> UI.FlyByHelpTracker class <category>class initialization</category>
initialize "self initialize" Default := self new
</methods> <methods> UI.FlyByHelpTracker class <category>instance creation</category>
new ^super new initialize
</methods> <methods> UI.FlyByHelpTracker class <category>accessing</category>
default "Answer the singleton instance of the class." Default isNil ifTrue: [Default := NullFlyByHelpTracker new]. ^Default
disable "Make the default tracker ignore the events from now on by replacing it with a null one." self default deactivate. Default := NullFlyByHelpTracker new
enable "Make the default tracker process events as usual again." Default := self new
flush "Dispose of the default instance. The default tracker recreated upon next request for a default instance will be a null one." "self flush" Default := nil
updatePopupWindow self default isActive ifTrue: [self default recreatePopup]
</methods> <methods> UI.ProgressWidgetView <category>initialize-release</category>
helpText: aStringOrText "This is the old API." helpText := aStringOrText.
</methods> <methods> UI.SequenceView <category>accessing</category>
helpText: aStringOrText "This is the old API." helpText := aStringOrText.
</methods> <methods> UI.SliderView <category>accessing</category>
helpText: aStringOrText "This is the old API." helpText := aStringOrText.
</methods> <methods> UI.TextEditorView <category>accessing</category>
helpText: aStringOrText "This is the old API." helpText := aStringOrText.
</methods> <methods> UI.LabeledButtonView <category>accessing</category>
helpText: aStringOrText "This is the old API." helpText := aStringOrText.
</methods> <methods> UI.Controller <category>events</category>
noticeFlyByHelpEnter FlyByHelpTracker default noticeEntryInto: self.
noticeFlyByHelpExit FlyByHelpTracker default noticeExitFrom: self.
</methods> <methods> Tools.VisualWorksSettings class <category>settings-fly by help</category>
flyByHelp1Enabled <setting: #(flyByHelp flyByHelpEnabled)> ^(BooleanSetting on: FlyByHelpTracker aspect: #isEnabled) default: true; label: #FlyByHelpEnabled << #labels >> 'Enabled'; helpText: #FlyByHelpEnabledHelpText << #dialogs >> 'When the fly-by help is enabled, a small help window explaining the purpose of the current widget pops up whenever the mouse pointer pauses over the widget (if the explanation is available). The help window closes when the mouse pointer leaves the widget or after a timeout.'
flyByHelp2OpenDelay <setting: #(flyByHelp flyByHelpOpenDelay)> ^((IntegerSetting min: 100 max: 100000) on: FlyByHelpTracker aspect: #openDelay) default: 500; label: #PopupDelayMS << #labels >> 'Popup delay (ms)'; helpText: #PopupDelayHelpText << #dialogs >> 'The duration the mouse pointer has to be within a widget before the help window opens.'
flyByHelp3CloseDelay <setting: #(flyByHelp flyByHelpCloseDelay)> ^((IntegerSetting min: 100 max: 100000) on: FlyByHelpTracker aspect: #closeDelay) default: 5000; label: #CloseDelayMS << #labels >> 'Close delay (ms)'; helpText: #CloseDelayHelpText << #dialogs >> 'The delay after which the help window is closed.'
flyByHelp4ForegroundColor <setting: #(flyByHelp foregroundColor)> ^(ColorValueSetting on: FlyByHelpTracker aspect: #defaultForegroundPaint) label: #FlyByHelpForeground << #labels >> 'Foreground color'; helpText: #FlyByHelpForegrondHelp << #dialogs >> 'The foreground color of the fly-by help window.'
flyByHelp5BackgroundColor <setting: #(flyByHelp backgroundColor)> ^(ColorValueSetting on: FlyByHelpTracker aspect: #defaultBackgroundPaint) label: #FlyByHelpBackground << #labels >> 'Background color'; helpText: #FlyByHelpBackgroundHelpText << #dialogs >> 'Background color of the help window.'
</methods> <methods> Tools.VisualWorksSettings class <category>pages</category>
flyByHelpPage <settingsPage: #(system flyByHelp)> ^ModularSettingsPage new label: #FlyByHelp << #labels >> 'Fly-by Help'; icon: (ListIconLibrary visualFor: #flyByHelp); settings: (self settingsWithPrefix: #(flyByHelp))
</methods> <initialize> UI.FlyByHelpTracker </initialize> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Object</name> <environment>Core</environment> <super></super> <private>false</private> none <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>TransientWindow</name> <environment>UI</environment> <super>Graphics.Window</super> <private>false</private> none component paintPreferences isEventDriven controller <imports></imports> <category>Interface-Framework</category> <attributes> <package>Interface-Framework</package> </attributes> </class> <class> <name>LabeledButtonView</name> <environment>UI</environment> <super>UI.BasicButtonView</super> <private>false</private> none label textStyle helpText <imports></imports> <category>UIBasics-Components</category> <attributes> <package>UIBasics-Components</package> </attributes> </class> <class> <name>TextEditorView</name> <environment>UI</environment> <super>UI.ComposedTextView</super> <private>false</private> none state helpText <imports></imports> <category>UIBasics-Components</category> <attributes> <package>UIBasics-Components</package> </attributes> </class> <class> <name>Subsystem</name> <environment>Core</environment> <super>Core.Object</super> <private>false</private> none state canActivate prerequisites current <imports></imports> <category>System-Subsystems</category> <attributes> <package>System-Subsystems</package> </attributes> </class> <class> <name>ProgressWidgetView</name> <environment>UI</environment> <super>UI.View</super> <private>false</private> none axis lastValue position reverse area helpText <imports></imports> <category>UIBasics-Components</category> <attributes> <package>UIBasics-Components</package> </attributes> </class> <class> <name>EventSensor</name> <environment>UI</environment> <super>UI.ApplicationWindowSensor</super> <private>false</private> none collapseEvents queueLocked <imports></imports> <category>Interface-Events-Support</category> <attributes> <package>Interface-Events-Support</package> </attributes> </class> <class> <name>Controller</name> <environment>UI</environment> <super>Core.Object</super> <private>false</private> none model view sensor <imports></imports> <category>Interface-Framework</category> <attributes> <package>Interface-Framework</package> </attributes> </class> <class> <name>SequenceView</name> <environment>UI</environment> <super>UI.SelectionView</super> <private>false</private> none visualBlock selectedVisualBlock measureWidth cachedWidth helpText <imports></imports> <category>UIBasics-Components</category> <attributes> <package>UIBasics-Components</package> </attributes> </class> <class> <name>SliderView</name> <environment>UI</environment> <super>UI.SimpleView</super> <private>false</private> none axis markerBlock markerLength marker color1 color2 markerBorder rangeMap helpText <imports></imports> <category>UIBasics-Components</category> <attributes> <package>UIBasics-Components</package> </attributes> </class>