ProvideAnswerNotification and UIManager

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

ProvideAnswerNotification and UIManager

Patrick R.
Hi everyone,

recently I noticed that the method BlockClosure>>valueSupplyingAnswer: (and related ones) do
not work on all method of UIManager. When I looked into the issue I noticed that the signaling of
ProvideAnswerNotification is not done in the UIManagers but in the classes implementing the
actual user interfaces for the corresponding queries (e.g. MenuMorph and PopUpMenu). This
scattered the ProvideAnswerNotification logic throughout different packages and classes and
might have lead to the oversights.

The attached changeset is a refactoring of this mechanism which moves the corresponding
logic into the UIManagers. Unfortunately, this required some code duplication but at least it is
contained with the UIManager. On the plus side the code is contained in the UIManagers and
all methods should be covered now.

As I am not very familiar with the original intend and responsibilities of the UIManagers I wanted
to ask whether anyone has any thoughts on that change.

Thanks and bests
Patrick

P.S.: There are other minor changes related to the refactoring in the changeset such as extending
the BlockClosureTests to test all UIManager subclasses


ProvideAnswerNotification.1.cs (44K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: ProvideAnswerNotification and UIManager

David T. Lewis
I have not reviewed in detail, but this seems like a good set of changes.

Has anyone else had a chance to take a look at this? If no objections I
would say that it is a good thing to add to trunk, but maybe not right now.

Just based on the number of methods being touched, it might be safer to
wait until immediately after the 5.2 release to apply this.

Dave

On Tue, Jul 10, 2018 at 09:28:14AM +0000, Rein, Patrick wrote:

> Hi everyone,
>
> recently I noticed that the method BlockClosure>>valueSupplyingAnswer: (and related ones) do
> not work on all method of UIManager. When I looked into the issue I noticed that the signaling of
> ProvideAnswerNotification is not done in the UIManagers but in the classes implementing the
> actual user interfaces for the corresponding queries (e.g. MenuMorph and PopUpMenu). This
> scattered the ProvideAnswerNotification logic throughout different packages and classes and
> might have lead to the oversights.
>
> The attached changeset is a refactoring of this mechanism which moves the corresponding
> logic into the UIManagers. Unfortunately, this required some code duplication but at least it is
> contained with the UIManager. On the plus side the code is contained in the UIManagers and
> all methods should be covered now.
>
> As I am not very familiar with the original intend and responsibilities of the UIManagers I wanted
> to ask whether anyone has any thoughts on that change.
>
> Thanks and bests
> Patrick
>
> P.S.: There are other minor changes related to the refactoring in the changeset such as extending
> the BlockClosureTests to test all UIManager subclasses
Content-Description: ProvideAnswerNotification.1.cs
> 'From Squeak5.2alpha of 9 July 2018 [latest update: #18142] on 10 July 2018 at 11:13:26 am'! !BlockClosureTest methodsFor: 'tests' stamp: 'pre 7/10/2018 09:07'! testSupplyAnswerUsingOnlySubstringOfQuestion UIManager subclassesDo: [:managerClass | self should: [false = ([managerClass new confirm: 'You like Smalltalk?'] valueSupplyingAnswer: #('like' false))]]! ! !BlockClosureTest methodsFor: 'tests' stamp: 'pre 7/10/2018 09:08'! testSupplyAnswerUsingRegexMatchOfQuestion (String includesSelector: #matchesRegex:) ifFalse: [^ self]. UIManager subclassesDo: [:managerClass | self should: [true = ([managerClass new confirm: 'You like Smalltalk?'] valueSupplyingAnswer: #('.*Smalltalk\?' true))]]! ! !BlockClosureTest methodsFor: 'tests' stamp: 'pre 7/10/2018 09:08'! testSupplySpecificAnswerToQuestion UIManager subclassesDo: [:managerClass | self should: [false = ([managerClass new confirm: 'You like Smalltalk?'] valueSupplyingAnswer: #('You like Smalltalk?' false))]]! ! !BlockClosureTest methodsFor: 'tests' stamp: 'pre 7/10/2018 09:14'! testSuppressInform UIManager subclassesDo: [:managerClass | | manager | manager := managerClass new. self should: [[manager inform: 'Should not see this message or this test failed!!'] valueSuppressingAllMessages]]! ! !BlockClosureTest methodsFor: 'tests' stamp: 'pre 7/10/2018 10:56'! testSuppressInformUsingStringMatchOptions UIManager subclassesDo: [:managerClass | | manager | manager := managerClass new. #("message" "pattern" 'Should not see this message or this test failed!!' 'Should not see this message or this test failed!!' 'Should not see this message or this test failed!!' 'not see this message' 'Should not see this message or this test failed!!' '*message*failed#') pairsDo: [:message :pattern | self assert: ([manager inform: message] valueSuppressingMessages: {pattern})]]! ! !BlockClosureTest methodsFor: 'testing' stamp: 'pre 7/10/2018 09:05'! testSupplyAnswerOfFillInTheBlank UIManager subclassesDo: [:managerClass | self should: ['blue' = ([managerClass new request: 'Your favorite color?'] valueSupplyingAnswer: #('Your favorite color?' 'blue'))]]! ! !BlockClosureTest methodsFor: 'testing' stamp: 'pre 7/10/2018 09:05'! testSupplyAnswerOfFillInTheBlankUsingDefaultAnswer UIManager subclassesDo: [:managerClass | self should: ['red' = ([managerClass new request: 'Your favorite color?' initialAnswer: 'red'] valueSupplyingAnswer: #('Your favorite color?' #default))]]! ! !DialogWindow methodsFor: 'running' stamp: 'pre 7/9/2018 16:46'! getUserResponse | hand world | self message ifEmpty: [messageMorph delete]. "Do not waste space." self paneMorph submorphs ifEmpty: [self paneMorph delete]. "Do not waste space." hand := self currentHand. world := self currentWorld. self fullBounds. self moveToPreferredPosition. self openInWorld: world. hand showTemporaryCursor: nil. "Since we are out of context, reset the cursor." hand keyboardFocus in: [:priorKeyboardFocus | hand mouseFocus in: [:priorMouseFocus | self exclusive ifTrue: [hand newMouseFocus: self]. hand newKeyboardFocus: self. [self isInWorld] whileTrue:[world doOneSubCycle]. hand newKeyboardFocus: priorKeyboardFocus. hand newMouseFocus: priorMouseFocus]]. ^ result! ! !MenuMorph class methodsFor: 'utilities' stamp: 'pre 7/10/2018 11:11'! chooseFrom: aList lines: linesArray title: queryString "Choose an item from the given list. Answer the index of the selected item." | menu aBlock result | aBlock := [:v| result := v]. menu := self new. menu addTitle: queryString. 1 to: aList size do:[:i| menu add: (aList at: i) asString target: aBlock selector: #value: argument: i. (linesArray includes: i) ifTrue:[menu addLine]]. MenuIcons decorateMenu: menu. result := 0. menu invokeAt: ActiveHand position in: ActiveWorld allowKeyboard: true. ^result! ! !MenuMorph class methodsFor: 'utilities' stamp: 'pre 7/10/2018 11:12'! chooseFrom: aList values: valueList lines: linesArray title: queryString "Choose an item from the given list. Answer the index of the selected item." | index | index := self chooseFrom: aList lines: linesArray title: queryString. ^ valueList at: index ifAbsent: [nil]! ! !MenuMorph class methodsFor: 'utilities' stamp: 'pre 7/10/2018 08:57'! confirm: queryString trueChoice: trueChoice falseChoice: falseChoice "Put up a yes/no menu with caption queryString. The actual wording for the two choices will be as provided in the trueChoice and falseChoice parameters. Answer true if the response is the true-choice,  false if it's the false-choice. This is a modal question -- the user must respond one way or the other." "MenuMorph confirm: 'Are you hungry?'   trueChoice: 'yes, I''m famished'   falseChoice: 'no, I just ate'" | menu aBlock result | aBlock := [:v| result := v]. menu := self new. menu addTitle: queryString icon: MenuIcons confirmIcon. menu add: trueChoice target: aBlock selector: #value: argument: true. menu add: falseChoice target: aBlock selector: #value: argument: false. MenuIcons decorateMenu: menu. [menu invokeAt: ActiveHand position in: ActiveWorld allowKeyboard: true. result == nil] whileTrue. ^result! ! !MenuMorph class methodsFor: 'utilities' stamp: 'pre 7/10/2018 08:57'! inform: queryString "MenuMorph inform: 'I like Squeak'" | menu | menu := self new. menu addTitle: queryString icon: MenuIcons confirmIcon. menu add: 'OK' target: self selector: #yourself. MenuIcons decorateMenu: menu. menu invokeAt: ActiveHand position in: ActiveWorld allowKeyboard: true.! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:41'! chooseDirectory "Let the user choose a directory. Returns a proper directory." ^self chooseDirectoryFrom: FileDirectory default! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:41'! chooseDirectory: label "Let the user choose a directory. Returns a proper directory." ^self chooseDirectory: label from: FileDirectory default! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:41'! chooseDirectory: label from: dir "Let the user choose a directory. Returns a proper directory." "UIManager default chooseDirectory: 'Choose one' from: FileDirectory default" ^self subclassResponsibility! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:41'! chooseDirectoryFrom: dir "Let the user choose a directory. Returns a proper directory." ^self chooseDirectory: nil from: dir! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:40'! chooseFileMatching: patterns "Let the user choose a file matching the given patterns. Returns a file name." ^self chooseFileMatching: patterns label: nil! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:39'! chooseFileMatching: patterns label: labelString "Let the user choose a file matching the given patterns. Returns a file name." ^self subclassResponsibility! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:40'! chooseFileMatchingSuffixes: suffixList "Let the user choose a file matching the given suffixes. Returns a file name." ^self chooseFileMatchingSuffixes: suffixList label: nil! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:40'! chooseFileMatchingSuffixes: suffixList label: labelString "Let the user choose a file matching the given suffixes. Returns a file name." ^self subclassResponsibility! ! !UIManager methodsFor: 'ui requests - files' stamp: 'pre 7/10/2018 08:40'! saveFilenameRequest: queryString initialAnswer: defaultAnswer "Open a FileSaverDialog to ask for a place and filename to use for saving a file. The initial suggestion for the filename is defaultAnswer but the user may choose any existing file or type in a new name entirely. Returns a file name." ^self subclassResponsibility! ! !UIManager methodsFor: 'utilities' stamp: 'pre 7/9/2018 15:09'! askForProvidedAnswerTo: queryString ifSupplied: supplyBlock ^ (ProvideAnswerNotification signal: queryString asString) ifNotNil: supplyBlock! ! !DummyUIManager methodsFor: '*52Deprecated' stamp: 'pre 7/9/2018 16:40'! openPluggableFileListLabel: aString in: aWorld "PluggableFileList is being deprecated and this can go away soon" "This method is not used anymore in 5.2 by any system classes and seems to have been renamed to openPluggableFileList:label:in:" ^nil! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:41'! chooseDirectory: label from: dir self askForProvidedAnswerTo: label ifSupplied: [:answer | ^ answer]. ^ nil! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:50'! chooseFrom: aList lines: linesArray title: aString self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ 0]. ^ aList indexOf: answer]. ^ 1! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:51'! chooseFrom: labelList values: valueList lines: linesArray title: aString self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ nil]. ^ valueList at: (valueList indexOf: answer)]. ^ valueList first! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:42'! confirm: queryString self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. self error: 'No user response possible'! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:42'! confirm: aString orCancel: cancelBlock self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ (answer = #cancel or: [answer isNil]) ifTrue: [cancelBlock value] ifFalse: [answer]]. self error: 'No user response possible'! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 09:16'! inform: aString "Nothing to be done here" self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer].! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:44'! request: queryString initialAnswer: defaultAnswer self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. self error: 'No user response possible'! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:44'! requestPassword: queryString ^ self request: queryString initialAnswer: ''! ! !DummyUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:45'! saveFilenameRequest: queryString initialAnswer: defaultAnswer "Open a FileSaverDialog to ask for a place and filename to use for saving a file. The initial suggestion for the filename is defaultAnswer but the user may choose any existing file or type in a new name entirely" self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. self error: 'No user response possible'! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:43'! chooseFileMatching: patterns label: labelString "Let the user choose a file matching the given patterns. Returns a file name." ^self notYetImplemented! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:42'! chooseFileMatchingSuffixes: suffixList label: aString "Let the user choose a file matching the given suffixes. Returns a file name." ^self notYetImplemented! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:31'! chooseFont: aPrompt for: aTarget setSelector: setSelector getSelector: getSelector "MVC Only!! prompt for a font and if one is provided, send it to aTarget using a message with selector aSelector." | aMenu aChoice aStyle namesAndSizes aFont | self askForProvidedAnswerTo: aPrompt ifSupplied: [:answer | ^ answer]. aMenu := CustomMenu new. TextStyle actualTextStyles keysSortedSafely do: [:styleName | aMenu add: styleName action: styleName]. aChoice := aMenu startUpWithCaption: aPrompt. aChoice ifNil: [^ self]. aMenu := CustomMenu new. aStyle := TextStyle named: aChoice. (namesAndSizes := aStyle fontNamesWithPointSizes) do: [:aString | aMenu add: aString action: aString]. aChoice := aMenu startUpWithCaption: nil. aChoice ifNil: [^ self]. aFont := aStyle fontAt: (namesAndSizes indexOf: aChoice). aTarget perform: setSelector with: aFont! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:49'! chooseFrom: aList lines: linesArray title: aString "Choose an item from the given list. Answer the index of the selected item." | menu | self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ 0]. ^ aList indexOf: answer]. menu := PopUpMenu labelArray: aList lines: linesArray. ^ aString isEmpty ifTrue:[menu startUp] ifFalse:[menu startUpWithCaption: aString]! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:51'! chooseFrom: labelList values: valueList lines: linesArray title: aString "Choose an item from the given list. Answer the selected item." | menu | self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ nil]. ^ valueList at: (valueList indexOf: answer)]. menu := SelectionMenu labels: labelList lines: linesArray selections: valueList. ^ aString ifEmpty: [menu startUp] ifNotEmpty: [menu startUpWithCaption: aString]! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:33'! confirm: queryString "Put up a yes/no menu with caption queryString. Answer true if the response is yes, false if no. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ PopUpMenu confirm: queryString! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:34'! confirm: aString orCancel: cancelBlock "Put up a yes/no/cancel menu with caption aString. Answer true if   the response is yes, false if no. If cancel is chosen, evaluate   cancelBlock. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ (answer = #cancel or: [answer isNil]) ifTrue: [cancelBlock value] ifFalse: [answer]]. ^ PopUpMenu confirm: aString orCancel: cancelBlock! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:34'! confirm: aString orCancel: cancelBlock title: titleString "Put up a yes/no/cancel menu with caption aString, and titleString to label the dialog. Answer true if  the response is yes, false if no. If cancel is chosen, evaluate cancelBlock. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ (answer = #cancel or: [answer isNil]) ifTrue: [cancelBlock value] ifFalse: [answer]]. ^ PopUpMenu confirm: (self dialogStringFromQuery: aString withTitle: titleString) orCancel: cancelBlock! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:34'! confirm: queryString title: titleString "Put up a yes/no menu with caption queryString, and titleString to label the dialog. Answer true if the response is yes, false if no. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ PopUpMenu confirm: (self dialogStringFromQuery: queryString withTitle: titleString) ! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:55'! confirm: queryString title: titleString trueChoice: trueChoice falseChoice: falseChoice "Put up a yes/no menu with caption queryString, and titleString to label the dialog. The actual wording for the two choices will be as provided in the trueChoice and falseChoice parameters. Answer true if the response is the true-choice, false if it is the false-choice. This is a modal question -- the user must respond one way or the other." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer isBoolean ifTrue: [answer] ifFalse: [trueChoice = answer]]. ^ PopUpMenu confirm: (self dialogStringFromQuery: queryString withTitle: titleString) trueChoice: trueChoice falseChoice: falseChoice! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:35'! confirm: queryString trueChoice: trueChoice falseChoice: falseChoice "Put up a yes/no menu with caption queryString. The actual wording for the two choices will be as provided in the trueChoice and falseChoice parameters. Answer true if the response is the true-choice, false if it's the false-choice. This is a modal question -- the user must respond one way or the other." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ PopUpMenu confirm: queryString trueChoice: trueChoice falseChoice: falseChoice! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:35'! inform: aString "Display a message for the user to read and then dismiss" self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ PopUpMenu inform: aString! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:36'! multiLineRequest: queryString centerAt: aPoint initialAnswer: defaultAnswer answerHeight: answerHeight "Create a multi-line instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts.  Answer nil if the user cancels.  An empty string returned means that the ussr cleared the editing area and then hit 'accept'.  Because multiple lines are invited, we ask that the user use the ENTER key, or (in morphic anyway) hit the 'accept' button, to submit; that way, the return key can be typed to move to the next line." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^ FillInTheBlank multiLineRequest: queryString centerAt: aPoint initialAnswer: defaultAnswer answerHeight: answerHeight! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:36'! request: queryString initialAnswer: defaultAnswer centerAt: aPoint "Create an instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^ FillInTheBlank request: queryString initialAnswer: defaultAnswer centerAt: aPoint ! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:36'! requestPassword: queryString "Create an instance of me whose question is queryString. Invoke it centered at the cursor, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ FillInTheBlank requestPassword: queryString! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:37'! request: queryString initialAnswer: defaultAnswer "Create an instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^FillInTheBlank request: queryString initialAnswer: defaultAnswer ! ! !MVCUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:37'! saveFilenameRequest: queryString initialAnswer: defaultAnswer "Open a FileSaverDialog to ask for a place and filename to use for saving a file. The initial suggestion for the filename is defaultAnswer but the user may choose any existing file or type in a new name entirely" "MVC has to stick with the boring way of doing it" | result | self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. result := self request: queryString initialAnswer: defaultAnswer. ^result isEmpty ifTrue: [nil] ifFalse:[result] ! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:42'! chooseDirectory: label from: dir "Let the user choose a file matching the given patterns. Returns a file name." self askForProvidedAnswerTo: label ifSupplied: [:answer | ^ answer]. ^ DirectoryChooserDialog openOn: dir label: label! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:42'! chooseFileMatching: patterns label: aString "Let the user choose a file matching the given patterns. Returns a file name." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ FileChooserDialog openOnPattern: patterns label: aString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:42'! chooseFileMatchingSuffixes: suffixList label: aString "Let the user choose a file matching the given suffixes. Returns a file name." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ FileChooserDialog openOnSuffixList: suffixList label: aString. ! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:10'! chooseFont: titleString for: aModel setSelector: setSelector getSelector: getSelector "Open a font-chooser for the given model" self askForProvidedAnswerTo: titleString ifSupplied: [:answer | ^ answer]. ^FontChooserTool default openWithWindowTitle: titleString for: aModel setSelector: setSelector getSelector: getSelector! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:54'! chooseFrom: aList lines: linesArray title: aString "Choose an item from the given list. Answer the index of the selected item. Cancel value is 0. There are several (historical) reasons for building a button dialog instead of a list chooser for small lists: 1) Unfortunately, there is existing code that uses this call to create simple confirmation dialogs with a list of #(yes no cancel). 2) Unfortunately, there is existing code that uses this call to mimick a drop-down menu with a (compact) pop-up menu." self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ 0]. ^ aList indexOf: answer]. aList ifEmpty: [^ 0]. aList size <= 7 ifTrue: [ | dialog | dialog := DialogWindow new title: 'Please Choose'; message: aString; filterEnabled: true; autoCancel: true; "Like a pop-up menu, click anywhere to dismiss." yourself. aList doWithIndex: [:ea :index | dialog createButton: ea value: index]. dialog selectedButtonIndex: 1. ^ dialog getUserResponseAtHand ifNil: [0]]. ^ ListChooser chooseFrom: aList title: aString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:54'! chooseFrom: labelList values: valueList lines: linesArray title: aString "Choose an item from the given list. Answer the selected item." | index | self askForProvidedAnswerTo: aString ifSupplied: [:answer | (answer = #cancel or: [answer isNil]) ifTrue: [^ nil]. ^ valueList at: (valueList indexOf: answer) ifAbsent: [nil]]. index := self chooseFrom: labelList lines: linesArray title: aString. ^ index = 0 ifTrue: [ nil ] ifFalse: [ valueList at: index ]! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:12'! chooseFromOrAddTo: aList lines: linesArray title: aString self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ ListChooser chooseItemFrom: aList title: aString addAllowed: true! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:12'! chooseMultipleFrom: aList lines: linesArray title: aString "Choose one or more items from the given list. Answer the indices of the selected items." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ ListMultipleChooser chooseFrom: aList title: aString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:12'! chooseMultipleFrom: labelList values: valueList lines: linesArray title: aString "Choose one or more items from the given list. Answer the selected items." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ (ListMultipleChooser chooseFrom: labelList title: aString) ifNotNil: [:indexList | indexList collect: [:index | valueList at: index]]! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:12'! confirm: queryString "Put up a yes/no menu with caption queryString. Answer true if the response is yes, false if no. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ UserDialogBoxMorph confirm: queryString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:14'! confirm: aString orCancel: cancelBlock "Put up a yes/no/cancel menu with caption aString. Answer true if   the response is yes, false if no. If cancel is chosen, evaluate   cancelBlock. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ (answer = #cancel or: [answer isNil]) ifTrue: [cancelBlock value] ifFalse: [answer]]. ^ UserDialogBoxMorph confirm: aString orCancel: cancelBlock! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:16'! confirm: aString orCancel: cancelBlock title: titleString "Put up a yes/no/cancel menu with caption aString, and titleString to label the dialog. Answer true if  the response is yes, false if no. If cancel is chosen, evaluate cancelBlock. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ (answer = #cancel or: [answer isNil]) ifTrue: [cancelBlock value] ifFalse: [answer]]. ^ UserDialogBoxMorph confirm: aString orCancel: cancelBlock title: titleString at: nil! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:16'! confirm: queryString title: titleString "Put up a yes/no menu with caption queryString, and titleString to label the dialog. Answer true if the response is yes, false if no. This is a modal question--the user must respond yes or no." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ UserDialogBoxMorph confirm: queryString title: titleString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 08:55'! confirm: queryString title: titleString trueChoice: trueChoice falseChoice: falseChoice "Put up a yes/no menu with caption queryString, and titleString to label the dialog. The actual wording for the two choices will be as provided in the trueChoice and falseChoice parameters. Answer true if the response is the true-choice, false if it is the false-choice. This is a modal question -- the user must respond one way or the other." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer isBoolean ifTrue: [answer] ifFalse: [trueChoice = answer]]. ^ UserDialogBoxMorph confirm: queryString title: titleString trueChoice: trueChoice falseChoice: falseChoice ! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:17'! confirm: queryString trueChoice: trueChoice falseChoice: falseChoice "Put up a yes/no menu with caption queryString. The actual wording for the two choices will be as provided in the trueChoice and falseChoice parameters. Answer true if the response is the true-choice, false if it's the false-choice. This is a modal question -- the user must respond one way or the other." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ UserDialogBoxMorph confirm: queryString trueChoice: trueChoice falseChoice: falseChoice ! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:17'! edit: aText label: labelString accept: anAction "Open an editor on the given string/text" | window | window := Workspace open. labelString ifNotNil: [ window setLabel: labelString ]. "By default, don't style in UIManager edit: requests" window model shouldStyle: false; acceptContents:  aText; acceptAction: anAction. ^ window! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/10/2018 09:15'! inform: aString "Display a message for the user to read and then dismiss" self askForProvidedAnswerTo: aString ifSupplied: [:answer | ^ answer]. ^ UserDialogBoxMorph inform: aString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 15:21'! multiLineRequest: queryString centerAt: aPoint initialAnswer: defaultAnswer answerHeight: answerHeight "Create a multi-line instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts.  Answer nil if the user cancels.  An empty string returned means that the ussr cleared the editing area and then hit 'accept'.  Because multiple lines are invited, we ask that the user use the ENTER key, or (in morphic anyway) hit the 'accept' button, to submit; that way, the return key can be typed to move to the next line." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^ FillInTheBlankMorph request: queryString initialAnswer: defaultAnswer centerAt: aPoint inWorld: self currentWorld onCancelReturn: nil acceptOnCR: false! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:29'! request: queryString initialAnswer: defaultAnswer centerAt: aPoint "Create an instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^ FillInTheBlankMorph request: queryString initialAnswer: defaultAnswer centerAt: aPoint! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:29'! requestPassword: queryString "Create an instance of me whose question is queryString. Invoke it centered at the cursor, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer]. ^ FillInTheBlankMorph requestPassword: queryString! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:29'! request: queryString initialAnswer: defaultAnswer "Create an instance of me whose question is queryString with the given initial answer. Invoke it centered at the given point, and answer the string the user accepts. Answer the empty string if the user cancels." self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^FillInTheBlankMorph request: queryString initialAnswer: defaultAnswer ! ! !MorphicUIManager methodsFor: 'ui requests' stamp: 'pre 7/9/2018 16:30'! saveFilenameRequest: queryString initialAnswer: defaultAnswer "Open a FileSaverDialog to ask for a place and filename to use for saving a file. The initial suggestion for the filename is defaultAnswer but the user may choose any existing file or type in a new name entirely" self askForProvidedAnswerTo: queryString ifSupplied: [:answer | ^ answer = #default ifTrue: [defaultAnswer] ifFalse: [answer]]. ^ FileSaverDialog openOnInitialFilename: defaultAnswer label: queryString ! ! !MorphicUIManager methodsFor: 'ui project indirecting' stamp: 'pre 7/9/2018 15:22'! openDebugger: aDebugger on: process context: context label: title contents: contentsStringOrNil fullView: bool "open a debugger - the two versions for mvc & morphic are very close and can surely be merged so that this can be removed" ^ aDebugger morphicOpenOn: process context: context label: title contents: contentsStringOrNil fullView: bool! ! !DummyUIManager reorganize! ('ui project indirecting' openDebugger:on:context:label:contents:fullView: openFancyMailComposition: openPluggableFileList:label:in: resumeDebugger:process: startUpMenu:withCaption:icon:at:allowKeyboard:) ('*52Deprecated' fontFromUser: openPluggableFileListLabel:in:) ('ui requests' chooseDirectory:from: chooseFrom:lines:title: chooseFrom:values:lines:title: confirm: confirm:orCancel: displayProgress:at:from:to:during: edit:label:accept: inform: informUserDuring: request:initialAnswer: requestPassword: saveFilenameRequest:initialAnswer:) ('*51Deprecated' checkForNewDisplaySize restoreDisplay) ! UIManager removeSelector: #askForProvidedAnswerTo:!
>