Frank Shearar uploaded a new version of ToolBuilder-Morphic to project The Trunk:
http://source.squeak.org/trunk/ToolBuilder-Morphic-fbs.91.mcz ==================== Summary ==================== Name: ToolBuilder-Morphic-fbs.91 Author: fbs Time: 9 January 2014, 2:56:27.235 pm UUID: abaa076b-af43-af42-8c98-7a71482c6a30 Ancestors: ToolBuilder-Morphic-fbs.90 Move the ToolBuilder classes back to ToolBuilder-Morphic: this way you can have Morphic with or without ToolBuilder. =============== Diff against ToolBuilder-Morphic-fbs.90 =============== Item was added: + SystemOrganization addCategory: #'ToolBuilder-Morphic'! Item was added: + Object subclass: #ListChooser + instanceVariableNames: 'window fullList selectedItems searchText searchMorph title listMorph index realIndex buttonBar builder addAllowed result' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !ListChooser commentStamp: 'MAD 3/14/2010 16:20' prior: 0! + I am a simple dialog to allow the user to pick from a list of strings or symbols. + I support keyboard and mouse navigation, and interactive filtering of the displayed items. + + You can specify whether you want the index, or the value of the selected item. If you're interested in the value, you can also allow users to Add a new value not in the list. + + cmd-s or <enter> or double-click answers the currently selected item's value/index; + cmd-l or <escape> or closing the window answers nil/zero. + + Now using ToolBuilder, so needs Morphic-MAD.381. + + Released under the MIT Licence.! Item was added: + ----- Method: ListChooser class>>chooseFrom: (in category 'ChooserTool compatibility') ----- + chooseFrom: aList + ^ self + chooseFrom: aList + title: self defaultTitle! Item was added: + ----- Method: ListChooser class>>chooseFrom:title: (in category 'ChooserTool compatibility') ----- + chooseFrom: aList title: aString + ^ self + chooseIndexFrom: aList + title: aString + addAllowed: false! Item was added: + ----- Method: ListChooser class>>chooseIndexFrom: (in category 'instance creation') ----- + chooseIndexFrom: aList + ^ self + chooseIndexFrom: aList + title: self defaultTitle! Item was added: + ----- Method: ListChooser class>>chooseIndexFrom:title: (in category 'instance creation') ----- + chooseIndexFrom: aList title: aString + ^ self + chooseIndexFrom: aList + title: (aString isEmptyOrNil ifTrue: [ self defaultTitle ] ifFalse: [ aString ]) + addAllowed: false! Item was added: + ----- Method: ListChooser class>>chooseIndexFrom:title:addAllowed: (in category 'instance creation') ----- + chooseIndexFrom: aList title: aString addAllowed: aBoolean + ^ self new + chooseIndexFrom: aList + title: (aString isEmptyOrNil ifTrue: [ self defaultTitle ] ifFalse: [ aString ]) + addAllowed: aBoolean! Item was added: + ----- Method: ListChooser class>>chooseItemFrom: (in category 'instance creation') ----- + chooseItemFrom: aList + ^ self + chooseItemFrom: aList + title: self defaultTitle! Item was added: + ----- Method: ListChooser class>>chooseItemFrom:title: (in category 'instance creation') ----- + chooseItemFrom: aList title: aString + ^ self + chooseItemFrom: aList + title: aString + addAllowed: false! Item was added: + ----- Method: ListChooser class>>chooseItemFrom:title:addAllowed: (in category 'instance creation') ----- + chooseItemFrom: aList title: aString addAllowed: aBoolean + ^ self new + chooseItemFrom: aList + title: (aString isEmptyOrNil ifTrue: [ self defaultTitle ] ifFalse: [ aString ]) + addAllowed: aBoolean! Item was added: + ----- Method: ListChooser class>>defaultTitle (in category 'instance creation') ----- + defaultTitle + ^ 'Please choose:'! Item was added: + ----- Method: ListChooser class>>testDictionary (in category 'examples') ----- + testDictionary + ^ self + chooseItemFrom: (Dictionary newFrom: {#a->1. 2->#b.}) + title: 'Pick from Dictionary' "gives values, not keys"! Item was added: + ----- Method: ListChooser class>>testIndex (in category 'examples') ----- + testIndex + ^ self + chooseIndexFrom: (Smalltalk classNames , Smalltalk traitNames) asOrderedCollection + title: 'Pick a class'! Item was added: + ----- Method: ListChooser class>>testItem (in category 'examples') ----- + testItem + ^ self + chooseItemFrom: (Smalltalk classNames , Smalltalk traitNames) asOrderedCollection + title: 'Pick a class'! Item was added: + ----- Method: ListChooser class>>testItemAdd (in category 'examples') ----- + testItemAdd + ^ self + chooseItemFrom: (Smalltalk classNames , Smalltalk traitNames) asOrderedCollection + title: 'Pick or Add:' + addAllowed: true! Item was added: + ----- Method: ListChooser class>>testLongTitle (in category 'examples') ----- + testLongTitle + ^ self + chooseItemFrom: #(this is a list of values that aren/t the point here) + title: 'Pick from some values from this list'! Item was added: + ----- Method: ListChooser class>>testSet (in category 'examples') ----- + testSet + ^ self + chooseItemFrom: #(a list of values as a Set) asSet + title: 'Pick from Set'! Item was added: + ----- Method: ListChooser>>accept (in category 'event handling') ----- + accept + "if the user submits with no valid entry, make them start over" + self canAccept ifFalse: [ + searchMorph selectAll. + ^ self ]. + + "find the selected item in the original list, and return it" + result := selectedItems at: index. + + builder ifNotNil: [ :bldr | + builder := nil. + bldr close: window ]! Item was added: + ----- Method: ListChooser>>acceptColor (in category 'drawing') ----- + acceptColor + ^ self canAccept + ifTrue: [ ColorTheme current okColor ] + ifFalse: [ Color lightGray "ColorTheme current disabledColor <- you don't have this!!" ]! Item was added: + ----- Method: ListChooser>>acceptText: (in category 'event handling') ----- + acceptText: someText + "the text morph wants to tell us about its contents but I don't care, I'm only interested in the list" + self accept! Item was added: + ----- Method: ListChooser>>add (in category 'event handling') ----- + add + "if the user submits with no valid entry, make them start over" + self canAdd ifFalse: [ + searchMorph selectAll. + ^ self ]. + + "find the string to return" + result := searchMorph getText. + + builder ifNotNil: [ :bldr | + builder := nil. + bldr close: window ]! Item was added: + ----- Method: ListChooser>>buildButtonBarWith: (in category 'building') ----- + buildButtonBarWith: builder + | panel button | + panel := builder pluggablePanelSpec new + model: self; + layout: #proportional; + children: OrderedCollection new. + button := builder pluggableButtonSpec new. + button + model: self; + label: 'Accept (s)'; + action: #accept; + enabled: #canAccept; + state: #canAccept; + color: #acceptColor; + frame: (0.0 @ 0.0 corner: 0.34@1). + panel children add: button. + + button := builder pluggableButtonSpec new. + button + model: self; + label: 'Add (a)'; + action: #add; + enabled: #canAdd; + frame: (0.36 @ 0.0 corner: 0.63@1). + panel children add: button. + + button := builder pluggableButtonSpec new. + button + model: self; + label: 'Cancel (l)'; + action: #cancel; + color: #cancelColor; + frame: (0.65 @ 0.0 corner: 1@1). + panel children add: button. + + ^ panel! Item was added: + ----- Method: ListChooser>>buildListMorphWith: (in category 'building') ----- + buildListMorphWith: builder + | listSpec | + listSpec := builder pluggableListSpec new. + listSpec + model: self; + list: #list; + getIndex: #selectedIndex; + setIndex: #selectedIndex:; + doubleClick: #accept; + "handleBasicKeys: false;" + keystrokePreview: #keyStrokeFromList:; + "doubleClickSelector: #accept;" + autoDeselect: false. + ^ listSpec! Item was added: + ----- Method: ListChooser>>buildSearchMorphWith: (in category 'building') ----- + buildSearchMorphWith: builder + | fieldSpec | + fieldSpec := builder pluggableInputFieldSpec new. + fieldSpec + model: self; + getText: #searchText; + setText: #acceptText:; + menu: nil. + "hideScrollBarsIndefinitely;" + "acceptOnCR: true;" + "setBalloonText: 'Type a string to filter down the listed items'." + "onKeyStrokeSend: #keyStroke: to: self." + ^ fieldSpec! Item was added: + ----- Method: ListChooser>>buildWindowWith: (in category 'building') ----- + buildWindowWith: builder + | windowSpec | + windowSpec := builder pluggableWindowSpec new. + windowSpec model: self. + windowSpec label: #title. + windowSpec children: OrderedCollection new. + ^windowSpec! Item was added: + ----- Method: ListChooser>>buildWindowWith:specs: (in category 'building') ----- + buildWindowWith: builder specs: specs + | windowSpec | + windowSpec := self buildWindowWith: builder. + specs do: [ :assoc | + | rect action widgetSpec | + rect := assoc key. + action := assoc value. + widgetSpec := action value. + widgetSpec ifNotNil:[ + widgetSpec frame: rect. + windowSpec children add: widgetSpec ] ]. + ^ windowSpec! Item was added: + ----- Method: ListChooser>>buildWith: (in category 'building') ----- + buildWith: aBuilder + | windowSpec | + builder := aBuilder. + windowSpec := self buildWindowWith: builder specs: { + (0@0 corner: 1@0.05) -> [self buildSearchMorphWith: builder]. + (0@0.05 corner: 1@0.9) -> [self buildListMorphWith: builder]. + (0@0.9 corner: 1@1) -> [self buildButtonBarWith: builder]. + }. + windowSpec closeAction: #closed. + windowSpec extent: self initialExtent. + window := builder build: windowSpec. + + + searchMorph := window submorphs detect: + [ :each | each isKindOf: PluggableTextMorph ]. + searchMorph + hideScrollBarsIndefinitely; + acceptOnCR: true; + setBalloonText: 'Type a string to filter down the listed items'; + onKeyStrokeSend: #keyStroke: to: self; + hasUnacceptedEdits: true "force acceptOnCR to work even with no text entered". + listMorph := window submorphs detect: + [ :each | each isKindOf: PluggableListMorph ]. + ^ window! Item was added: + ----- Method: ListChooser>>canAccept (in category 'testing') ----- + canAccept + ^ self selectedIndex > 0! Item was added: + ----- Method: ListChooser>>canAdd (in category 'testing') ----- + canAdd + ^ addAllowed and: [ self canAccept not ]! Item was added: + ----- Method: ListChooser>>cancel (in category 'event handling') ----- + cancel + "Cancel the dialog and move on" + index := 0. + builder ifNotNil: [ builder close: window ]! Item was added: + ----- Method: ListChooser>>cancelColor (in category 'drawing') ----- + cancelColor + ^ ColorTheme current cancelColor! Item was added: + ----- Method: ListChooser>>chooseIndexFrom:title: (in category 'initialize-release') ----- + chooseIndexFrom: labelList title: aString + | choice | + choice := self chooseItemFrom: labelList title: aString addAllowed: false. + ^ fullList indexOf: choice ifAbsent: 0! Item was added: + ----- Method: ListChooser>>chooseIndexFrom:title:addAllowed: (in category 'initialize-release') ----- + chooseIndexFrom: labelList title: aString addAllowed: aBoolean + | choice | + choice := self chooseItemFrom: labelList title: aString addAllowed: false. + addAllowed := aBoolean. + ^ fullList indexOf: choice ifAbsent: 0! Item was added: + ----- Method: ListChooser>>chooseItemFrom:title:addAllowed: (in category 'initialize-release') ----- + chooseItemFrom: labelList title: aString addAllowed: aBoolean + fullList := labelList asOrderedCollection. "coerce everything into an OC" + builder := ToolBuilder default. + self list: fullList. + self title: aString. + addAllowed := aBoolean. + window := ToolBuilder default open: self. + window center: Sensor cursorPoint. + window setConstrainedPosition: (Sensor cursorPoint - (window fullBounds extent // 2)) hangOut: false. + builder runModal: window. + ^ result! Item was added: + ----- Method: ListChooser>>closed (in category 'event handling') ----- + closed + "Cancel the dialog and move on" + builder ifNotNil: [ index := 0 ]! Item was added: + ----- Method: ListChooser>>handlesKeyboard: (in category 'event handling') ----- + handlesKeyboard: evt + ^ true! Item was added: + ----- Method: ListChooser>>initialExtent (in category 'building') ----- + initialExtent + | listFont titleFont buttonFont listWidth titleWidth buttonWidth | + listFont := Preferences standardListFont. + titleFont := Preferences windowTitleFont. + buttonFont := Preferences standardButtonFont. + listWidth := 20 * (listFont widthOf: $m). + titleWidth := titleFont widthOfString: self title, '__________'. "add some space for titlebar icons" + buttonWidth := buttonFont widthOfString: '_Accept_(s)___Add (a)___Cancel_(l)_'. + ^ (listWidth max: (titleWidth max: buttonWidth))@(30 * (listFont height))! Item was added: + ----- Method: ListChooser>>keyStroke: (in category 'event handling') ----- + keyStroke: event + | newText key | + "handle updates to the search box interactively" + key := event keyString. + (key = '<up>') ifTrue: [ + self move: -1. + ^ self ]. + (key = '<down>') ifTrue: [ + self move: 1. + ^ self ]. + + (key = '<Cmd-s>') ifTrue: [ self accept. ^ self ]. + (key = '<cr>') ifTrue: [ self accept. ^ self ]. + + (key = '<escape>') ifTrue: [ self cancel. ^ self ]. + (key = '<Cmd-l>') ifTrue: [ self cancel. ^ self ]. + + (key = '<Cmd-a>') ifTrue: [ self add. ^ self ]. + + "pull out what's been typed, and update the list as required" + newText := searchMorph textMorph asText asString. + (newText = searchText) ifFalse: [ + searchText := newText. + self updateFilter ]. + ! Item was added: + ----- Method: ListChooser>>keyStrokeFromList: (in category 'event handling') ----- + keyStrokeFromList: event + "we don't want the list to be picking up events, excepting scroll events" + + "Don't sent ctrl-up/ctrl-down events to the searchMorph: they're scrolling events." + (#(30 31) contains: [:each | each = event keyValue]) not + ifTrue: + ["window world primaryHand keyboardFocus: searchMorph." + searchMorph keyStroke: event. + "let the list know we've dealt with it" + ^true]. + ^false. + ! Item was added: + ----- Method: ListChooser>>list (in category 'accessing') ----- + list + ^ selectedItems! Item was added: + ----- Method: ListChooser>>list: (in category 'accessing') ----- + list: items + fullList := items. + selectedItems := items. + self changed: #itemList.! Item was added: + ----- Method: ListChooser>>list:title: (in category 'accessing') ----- + list: aList title: aString + self list: aList. + self title: aString! Item was added: + ----- Method: ListChooser>>move: (in category 'event handling') ----- + move: offset + | newindex | + "The up arrow key moves the cursor, and it seems impossible to restore. + So, for consistency, on either arrow, select everything, so a new letter-press starts over. yuk." + searchMorph selectAll. + + newindex := self selectedIndex + offset. + newindex > selectedItems size ifTrue: [ ^ nil ]. + newindex < 1 ifTrue: [ ^ nil ]. + self selectedIndex: newindex. + ! Item was added: + ----- Method: ListChooser>>moveWindowNear: (in category 'drawing') ----- + moveWindowNear: aPoint + | trialRect delta | + trialRect := Rectangle center: aPoint extent: window fullBounds extent. + delta := trialRect amountToTranslateWithin: World bounds. + window position: trialRect origin + delta.! Item was added: + ----- Method: ListChooser>>realIndex (in category 'accessing') ----- + realIndex + ^ realIndex ifNil: [ 0 ]! Item was added: + ----- Method: ListChooser>>searchText (in category 'accessing') ----- + searchText + ^ searchText ifNil: [ searchText := '' ]! Item was added: + ----- Method: ListChooser>>searchText: (in category 'accessing') ----- + searchText: aString + searchText := aString! Item was added: + ----- Method: ListChooser>>selectedIndex (in category 'accessing') ----- + selectedIndex + ^ index ifNil: [ index := 1 ]! Item was added: + ----- Method: ListChooser>>selectedIndex: (in category 'accessing') ----- + selectedIndex: anInt + index := (anInt min: selectedItems size). + self changed: #selectedIndex. + self changed: #canAccept.! Item was added: + ----- Method: ListChooser>>title (in category 'accessing') ----- + title + ^ title ifNil: [ title := 'Please choose' ]! Item was added: + ----- Method: ListChooser>>title: (in category 'accessing') ----- + title: aString + title := aString.! Item was added: + ----- Method: ListChooser>>updateFilter (in category 'event handling') ----- + updateFilter + + selectedItems := + searchText isEmptyOrNil + ifTrue: [ fullList ] + ifFalse: [ | pattern patternMatches prefixMatches | + pattern := (searchText includes: $*) + ifTrue: [ searchText ] + ifFalse: [ '*', searchText, '*' ]. + patternMatches := fullList select: [:s | pattern match: s ]. + prefixMatches := OrderedCollection new: patternMatches size. + patternMatches removeAllSuchThat: [ :each | + (each findString: searchText startingAt: 1 caseSensitive: false) = 1 + and: [ + prefixMatches add: each. + true ] ]. + prefixMatches addAllLast: patternMatches; yourself]. + self changed: #list. + self selectedIndex: 1. + self changed: #selectedIndex.! Item was added: + ToolBuilder subclass: #MorphicToolBuilder + instanceVariableNames: 'widgets panes parentMenu' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !MorphicToolBuilder commentStamp: 'ar 2/11/2005 15:02' prior: 0! + The Morphic tool builder.! Item was added: + ----- Method: MorphicToolBuilder class>>isActiveBuilder (in category 'accessing') ----- + isActiveBuilder + "Answer whether I am the currently active builder" + ^Smalltalk isMorphic! Item was added: + ----- Method: MorphicToolBuilder>>add:to: (in category 'private') ----- + add: aMorph to: aParent + aParent addMorphBack: aMorph. + aParent isSystemWindow ifTrue:[ + aParent addPaneMorph: aMorph. + ].! Item was added: + ----- Method: MorphicToolBuilder>>alternateMultiSelectListClass (in category 'widget classes') ----- + alternateMultiSelectListClass + ^ AlternatePluggableListMorphOfMany ! Item was added: + ----- Method: MorphicToolBuilder>>asFrame: (in category 'private') ----- + asFrame: aRectangle + | frame | + aRectangle ifNil:[^nil]. + frame := LayoutFrame new. + frame + leftFraction: aRectangle left; + rightFraction: aRectangle right; + topFraction: aRectangle top; + bottomFraction: aRectangle bottom. + ^frame! Item was added: + ----- Method: MorphicToolBuilder>>buildHelpFor:spec: (in category 'pluggable widgets') ----- + buildHelpFor: widget spec: aSpec + aSpec help + ifNotNil: [widget setBalloonText: aSpec help]! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableActionButton: (in category 'pluggable widgets') ----- + buildPluggableActionButton: aSpec + | button | + button := self buildPluggableButton: aSpec. + button color: Color white. + ^button! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableAlternateMultiSelectionList: (in category 'pluggable widgets') ----- + buildPluggableAlternateMultiSelectionList: aSpec + | listMorph listClass | + aSpec getSelected ifNotNil: [ ^ self error: 'There is no PluggableAlternateListMorphOfManyByItem' ]. + listClass := self alternateMultiSelectListClass. + listMorph := listClass + on: aSpec model + list: aSpec list + primarySelection: aSpec getIndex + changePrimarySelection: aSpec setIndex + listSelection: aSpec getSelectionList + changeListSelection: aSpec setSelectionList + menu: aSpec menu. + listMorph + setProperty: #highlightSelector toValue: #highlightMessageList:with: ; + setProperty: #itemConversionMethod toValue: #asStringOrText ; + setProperty: #balloonTextSelectorForSubMorphs toValue: #balloonTextForClassAndMethodString ; + enableDragNDrop: SystemBrowser browseWithDragNDrop ; + menuTitleSelector: #messageListSelectorTitle. + self + register: listMorph + id: aSpec name. + listMorph + keystrokeActionSelector: aSpec keyPress ; + getListElementSelector: aSpec listItem ; + getListSizeSelector: aSpec listSize. + self + buildHelpFor: listMorph + spec: aSpec. + self + setFrame: aSpec frame + in: listMorph. + parent ifNotNil: [ self add: listMorph to: parent ]. + panes ifNotNil: [ aSpec list ifNotNil:[panes add: aSpec list ] ]. + ^ listMorph! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableButton: (in category 'pluggable widgets') ----- + buildPluggableButton: aSpec + | widget label state action enabled | + label := aSpec label. + state := aSpec state. + action := aSpec action. + widget := self buttonClass on: aSpec model + getState: (state isSymbol ifTrue:[state]) + action: nil + label: (label isSymbol ifTrue:[label]). + widget style: aSpec style. + aSpec changeLabelWhen + ifNotNilDo: [ :event | widget whenChanged: event update: aSpec label]. + self register: widget id: aSpec name. + enabled := aSpec enabled. + enabled isSymbol + ifTrue:[widget getEnabledSelector: enabled] + ifFalse:[widget enabled:enabled]. + widget action: action. + widget getColorSelector: aSpec color. + widget offColor: Color white.. + self buildHelpFor: widget spec: aSpec. + (label isSymbol or:[label == nil]) ifFalse:[widget label: label]. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableCheckBox: (in category 'pluggable widgets') ----- + buildPluggableCheckBox: spec + + | widget label state action | + label := spec label. + state := spec state. + action := spec action. + widget := self checkBoxClass on: spec model + getState: (state isSymbol ifTrue:[state]) + action: (action isSymbol ifTrue:[action]) + label: (label isSymbol ifTrue:[label]). + self register: widget id: spec name. + + widget installButton. + " widget getColorSelector: spec color. + widget offColor: Color white.. + self buildHelpFor: widget spec: spec. + (label isSymbol or:[label == nil]) ifFalse:[widget label: label]. + " self setFrame: spec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableCodePane: (in category 'pluggable widgets') ----- + buildPluggableCodePane: aSpec + "Install the default styler for code panes. + Implementation note: We should just be doing something like, e.g., + ^(self buildPluggableText: aSpec) useDefaultStyler + Unfortunately, this will retrieve and layout the initial text twice which + can make for a noticable performance difference when looking at some + larger piece of code. So instead we copy the implementation from + buildPlugggableText: here and insert #useDefaultStyler at the right point" + | widget | + widget := self codePaneClass new. + widget useDefaultStyler. + widget on: aSpec model + text: aSpec getText + accept: aSpec setText + readSelection: aSpec selection + menu: aSpec menu. + widget font: Preferences standardCodeFont. + self register: widget id: aSpec name. + widget getColorSelector: aSpec color. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + widget borderColor: Color lightGray. + widget color: Color white. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableDropDownList: (in category 'pluggable widgets') ----- + buildPluggableDropDownList: spec + + | widget model listSelector selectionSelector selectionSetter | + model := spec model. + listSelector := spec listSelector. + selectionSelector := spec selectionSelector. + selectionSetter := spec selectionSetter. + widget := self dropDownListClass new + model: model; + listSelector: listSelector; + selectionSelector: selectionSelector; + selectionSetter: selectionSetter; + yourself. + self register: widget id: spec name. + + widget installDropDownList. + self setFrame: spec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableInputField: (in category 'pluggable widgets') ----- + buildPluggableInputField: aSpec + | widget | + widget := self buildPluggableText: aSpec. + widget acceptOnCR: true. + widget hideScrollBarsIndefinitely. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableList: (in category 'pluggable widgets') ----- + buildPluggableList: aSpec + | widget listClass getIndex setIndex | + aSpec getSelected ifNil:[ + listClass := self listClass. + getIndex := aSpec getIndex. + setIndex := aSpec setIndex. + ] ifNotNil:[ + listClass := self listByItemClass. + getIndex := aSpec getSelected. + setIndex := aSpec setSelected. + ]. + widget := listClass on: aSpec model + list: aSpec list + selected: getIndex + changeSelected: setIndex + menu: aSpec menu + keystroke: aSpec keyPress. + self register: widget id: aSpec name. + widget getListElementSelector: aSpec listItem. + widget getListSizeSelector: aSpec listSize. + widget getIconSelector: aSpec icon. + widget doubleClickSelector: aSpec doubleClick. + widget dragItemSelector: aSpec dragItem. + widget dropItemSelector: aSpec dropItem. + widget wantsDropSelector: aSpec dropAccept. + widget autoDeselect: aSpec autoDeselect. + widget keystrokePreviewSelector: aSpec keystrokePreview. + aSpec color isNil + ifTrue: [widget + borderWidth: 1; + borderColor: Color lightGray; + color: Color white] + ifFalse: [widget color: aSpec color]. + self buildHelpFor: widget spec: aSpec. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + panes ifNotNil:[ + aSpec list ifNotNil:[panes add: aSpec list]. + ]. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableMenu: (in category 'building') ----- + buildPluggableMenu: menuSpec + | prior menu | + prior := parentMenu. + parentMenu := menu := self menuClass new. + menuSpec label ifNotNil:[parentMenu addTitle: menuSpec label]. + menuSpec items do:[:each| each buildWith: self]. + parentMenu := prior. + ^menu! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableMenuItem: (in category 'building') ----- + buildPluggableMenuItem: itemSpec + | item action label menu | + item := self menuItemClass new. + label := (itemSpec isCheckable + ifTrue: [ itemSpec checked ifTrue: ['<on>'] ifFalse: ['<off>']] + ifFalse: ['']), itemSpec label. + item contents: label. + item isEnabled: itemSpec enabled. + (action := itemSpec action) ifNotNil:[ + item + target: action receiver; + selector: action selector; + arguments: action arguments. + ]. + (menu := itemSpec subMenu) ifNotNil:[ + item subMenu: (menu buildWith: self). + ]. + parentMenu ifNotNil:[parentMenu addMorphBack: item]. + itemSpec separator ifTrue:[parentMenu addLine]. + ^item! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableMultiSelectionList: (in category 'pluggable widgets') ----- + buildPluggableMultiSelectionList: aSpec + | widget listClass | + aSpec getSelected ifNotNil:[^self error:'There is no PluggableListMorphOfManyByItem']. + listClass := self multiSelectListClass. + widget := listClass on: aSpec model + list: aSpec list + primarySelection: aSpec getIndex + changePrimarySelection: aSpec setIndex + listSelection: aSpec getSelectionList + changeListSelection: aSpec setSelectionList + menu: aSpec menu. + self register: widget id: aSpec name. + widget keystrokeActionSelector: aSpec keyPress. + widget getListElementSelector: aSpec listItem. + widget getListSizeSelector: aSpec listSize. + self buildHelpFor: widget spec: aSpec. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + panes ifNotNil:[ + aSpec list ifNotNil:[panes add: aSpec list]. + ]. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggablePanel: (in category 'pluggable widgets') ----- + buildPluggablePanel: aSpec + | widget children frame | + widget := self panelClass new. + self register: widget id: aSpec name. + widget model: aSpec model. + widget color: Color transparent. + widget clipSubmorphs: true. + children := aSpec children. + children isSymbol ifTrue:[ + widget getChildrenSelector: children. + widget update: children. + children := #(). + ]. + self buildAll: children in: widget. + self buildHelpFor: widget spec: aSpec. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + self setLayout: aSpec layout in: widget. + widget layoutInset: 0. + widget borderWidth: 0. + widget submorphsDo:[:sm| + (frame := sm layoutFrame) ifNotNil:[ + (frame rightFraction = 0 or:[frame rightFraction = 1]) + ifFalse:[frame rightOffset:1]. + (frame bottomFraction = 0 or:[frame bottomFraction = 1]) + ifFalse:[frame bottomOffset: 1]]]. + widget color: Color transparent. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableText: (in category 'pluggable widgets') ----- + buildPluggableText: aSpec + | widget | + widget := self textPaneClass on: aSpec model + text: aSpec getText + accept: aSpec setText + readSelection: aSpec selection + menu: aSpec menu. + widget askBeforeDiscardingEdits: aSpec askBeforeDiscardingEdits. + widget font: Preferences standardCodeFont. + self register: widget id: aSpec name. + widget getColorSelector: aSpec color. + self buildHelpFor: widget spec: aSpec. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + widget borderColor: Color lightGray. + widget color: Color white. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableTree: (in category 'pluggable widgets') ----- + buildPluggableTree: aSpec + | widget | + widget := self treeClass new. + self register: widget id: aSpec name. + widget model: aSpec model. + widget getSelectedPathSelector: aSpec getSelectedPath. + widget setSelectedSelector: aSpec setSelected. + widget getChildrenSelector: aSpec getChildren. + widget hasChildrenSelector: aSpec hasChildren. + widget getLabelSelector: aSpec label. + widget getIconSelector: aSpec icon. + widget getHelpSelector: aSpec help. + widget getMenuSelector: aSpec menu. + widget keystrokeActionSelector: aSpec keyPress. + widget getRootsSelector: aSpec roots. + widget autoDeselect: aSpec autoDeselect. + widget dropItemSelector: aSpec dropItem. + widget wantsDropSelector: aSpec dropAccept. + widget dragItemSelector: aSpec dragItem. + self setFrame: aSpec frame in: widget. + parent ifNotNil:[self add: widget to: parent]. + " panes ifNotNil:[ + aSpec roots ifNotNil:[panes add: aSpec roots]. + ]. " + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buildPluggableWindow: (in category 'pluggable widgets') ----- + buildPluggableWindow: aSpec + | widget children | + aSpec layout == #proportional ifFalse:[ + "This needs to be implemented - probably by adding a single pane and then the rest" + ^self error: 'Not implemented'. + ]. + widget := (self windowClassFor: aSpec) new. + self register: widget id: aSpec name. + widget model: aSpec model. + aSpec label ifNotNil: + [:label| + label isSymbol + ifTrue:[widget getLabelSelector: label] + ifFalse:[widget setLabel: label]]. + aSpec multiWindowStyle notNil ifTrue: + [widget savedMultiWindowState: (SavedMultiWindowState on: aSpec model)]. + children := aSpec children. + children isSymbol ifTrue:[ + widget getChildrenSelector: children. + widget update: children. + children := #(). + ]. + widget closeWindowSelector: aSpec closeAction. + panes := OrderedCollection new. + self buildAll: children in: widget. + self buildHelpFor: widget spec: aSpec. + widget bounds: (RealEstateAgent + initialFrameFor: widget + initialExtent: (aSpec extent ifNil:[widget initialExtent]) + world: self currentWorld). + widget setUpdatablePanesFrom: panes. + ^widget! Item was added: + ----- Method: MorphicToolBuilder>>buttonClass (in category 'widget classes') ----- + buttonClass + ^ PluggableButtonMorphPlus! Item was added: + ----- Method: MorphicToolBuilder>>checkBoxClass (in category 'widget classes') ----- + checkBoxClass + ^ PluggableCheckBoxMorph! Item was added: + ----- Method: MorphicToolBuilder>>close: (in category 'opening') ----- + close: aWidget + "Close a previously opened widget" + aWidget delete! Item was added: + ----- Method: MorphicToolBuilder>>codePaneClass (in category 'widget classes') ----- + codePaneClass + ^ PluggableTextMorphPlus! Item was added: + ----- Method: MorphicToolBuilder>>dropDownListClass (in category 'widget classes') ----- + dropDownListClass + ^ PluggableDropDownListMorph! Item was added: + ----- Method: MorphicToolBuilder>>listByItemClass (in category 'widget classes') ----- + listByItemClass + ^ PluggableListMorphByItemPlus! Item was added: + ----- Method: MorphicToolBuilder>>listClass (in category 'widget classes') ----- + listClass + ^ PluggableListMorphPlus! Item was added: + ----- Method: MorphicToolBuilder>>menuClass (in category 'widget classes') ----- + menuClass + ^ MenuMorph! Item was added: + ----- Method: MorphicToolBuilder>>menuItemClass (in category 'widget classes') ----- + menuItemClass + ^ MenuItemMorph! Item was added: + ----- Method: MorphicToolBuilder>>multiSelectListClass (in category 'widget classes') ----- + multiSelectListClass + ^ PluggableListMorphOfMany! Item was added: + ----- Method: MorphicToolBuilder>>open: (in category 'opening') ----- + open: anObject + "Build and open the object. Answer the widget opened." + | morph | + anObject isMorph + ifTrue:[morph := anObject] + ifFalse:[morph := self build: anObject]. + (morph isKindOf: MenuMorph) + ifTrue:[morph popUpInWorld: World]. + (morph isKindOf: SystemWindow) + ifTrue:[morph openInWorldExtent: morph extent] + ifFalse:[morph openInWorld]. + ^morph! Item was added: + ----- Method: MorphicToolBuilder>>open:label: (in category 'opening') ----- + open: anObject label: aString + "Build an open the object, labeling it appropriately. Answer the widget opened." + | window | + window := self open: anObject. + window setLabel: aString. + ^window! Item was added: + ----- Method: MorphicToolBuilder>>panelClass (in category 'widget classes') ----- + panelClass + ^ PluggablePanelMorph! Item was added: + ----- Method: MorphicToolBuilder>>register:id: (in category 'private') ----- + register: widget id: id + id ifNil:[^self]. + widgets ifNil:[widgets := Dictionary new]. + widgets at: id put: widget. + widget setNameTo: id.! Item was added: + ----- Method: MorphicToolBuilder>>runModal: (in category 'opening') ----- + runModal: aWidget + "Run the (previously opened) widget modally, e.g., + do not return control to the sender before the user has responded." + [aWidget world notNil] whileTrue: [ + aWidget outermostWorldMorph doOneCycle. + ]. + ! Item was added: + ----- Method: MorphicToolBuilder>>setFrame:in: (in category 'private') ----- + setFrame: aRectangle in: widget + | frame | + aRectangle ifNil:[^nil]. + frame := aRectangle isRectangle + ifTrue: [self asFrame: aRectangle] + ifFalse: [aRectangle]. "assume LayoutFrame" + widget layoutFrame: frame. + widget hResizing: #spaceFill; vResizing: #spaceFill. + (parent isSystemWindow) ifTrue:[ + widget borderWidth: 2; borderColor: #inset. + ].! Item was added: + ----- Method: MorphicToolBuilder>>setLayout:in: (in category 'private') ----- + setLayout: layout in: widget + layout == #proportional ifTrue:[ + widget layoutPolicy: ProportionalLayout new. + ^self]. + layout == #horizontal ifTrue:[ + widget layoutPolicy: TableLayout new. + widget listDirection: #leftToRight. + widget submorphsDo:[:m| m hResizing: #spaceFill; vResizing: #spaceFill]. + widget cellInset: 1@1. + widget layoutInset: 1@1. + widget color: Color transparent. + "and then some..." + ^self]. + layout == #vertical ifTrue:[ + widget layoutPolicy: TableLayout new. + widget listDirection: #topToBottom. + widget submorphsDo:[:m| m hResizing: #spaceFill; vResizing: #spaceFill]. + widget cellInset: 1@1. + widget layoutInset: 1@1. + widget color: Color transparent. + "and then some..." + ^self]. + ^self error: 'Unknown layout: ', layout.! Item was added: + ----- Method: MorphicToolBuilder>>textPaneClass (in category 'widget classes') ----- + textPaneClass + ^ PluggableTextMorphPlus! Item was added: + ----- Method: MorphicToolBuilder>>treeClass (in category 'widget classes') ----- + treeClass + ^ PluggableTreeMorph! Item was added: + ----- Method: MorphicToolBuilder>>widgetAt:ifAbsent: (in category 'private') ----- + widgetAt: id ifAbsent: aBlock + widgets ifNil:[^aBlock value]. + ^widgets at: id ifAbsent: aBlock! Item was added: + ----- Method: MorphicToolBuilder>>windowClass (in category 'widget classes') ----- + windowClass + ^ PluggableSystemWindow! Item was added: + ----- Method: MorphicToolBuilder>>windowClassFor: (in category 'widget classes') ----- + windowClassFor: aSpec + aSpec isDialog ifTrue: [^ PluggableDialogWindow]. + ^aSpec multiWindowStyle + caseOf: + { [nil] -> [PluggableSystemWindow]. + [#labelButton] -> [PluggableSystemWindowWithLabelButton] } + otherwise: [PluggableSystemWindowWithLabelButton]! Item was added: + UIManager subclass: #MorphicUIManager + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !MorphicUIManager commentStamp: 'dtl 5/2/2010 16:07' prior: 0! + MorphicUIManager is a UIManager that implements user interface requests for a Morphic user interface.! Item was added: + ----- Method: MorphicUIManager class>>isActiveManager (in category 'accessing') ----- + isActiveManager + "Answer whether I should act as the active ui manager" + ^Smalltalk isMorphic! Item was added: + ----- Method: MorphicUIManager>>chooseClassOrTrait:from: (in category 'ui requests') ----- + chooseClassOrTrait: label from: environment + "Let the user choose a Class or Trait. Use ListChooser in Morphic." + + | names index | + names := environment classAndTraitNames. + index := self + chooseFrom: names + lines: #() + title: label. + index = 0 ifTrue: [ ^nil ]. + ^environment + at: (names at: index) + ifAbsent: [ nil ]! Item was added: + ----- Method: MorphicUIManager>>chooseDirectory:from: (in category 'ui requests') ----- + chooseDirectory: label from: dir + "Let the user choose a directory" + ^FileList2 modalFolderSelector: dir! Item was added: + ----- Method: MorphicUIManager>>chooseFileMatching:label: (in category 'ui requests') ----- + chooseFileMatching: patterns label: aString + "Let the user choose a file matching the given patterns" + | result | + result := FileList2 modalFileSelectorForSuffixes: patterns. + ^result ifNotNil:[result fullName]! Item was added: + ----- Method: MorphicUIManager>>chooseFont:for:setSelector:getSelector: (in category 'ui requests') ----- + chooseFont: titleString for: aModel setSelector: setSelector getSelector: getSelector + "Open a font-chooser for the given model" + ^FontChooserTool default + openWithWindowTitle: titleString + for: aModel + setSelector: setSelector + getSelector: getSelector! Item was added: + ----- Method: MorphicUIManager>>chooseFrom:lines:title: (in category 'ui requests') ----- + chooseFrom: aList lines: linesArray title: aString + "Choose an item from the given list. Answer the index of the selected item." + ^ aList size > 30 + ifTrue: + [ "Don't put more than 30 items in a menu. Use ListChooser insted" + ListChooser + chooseFrom: aList + title: aString ] + ifFalse: + [ MenuMorph + chooseFrom: aList + lines: linesArray + title: aString ]! Item was added: + ----- Method: MorphicUIManager>>chooseFrom:values:lines:title: (in category 'ui requests') ----- + chooseFrom: labelList values: valueList lines: linesArray title: aString + "Choose an item from the given list. Answer the selected item." + | index | + ^ labelList size > 30 + ifTrue: + [ "No point in displaying more than 30 items in a menu. Use ListChooser insted" + index := ListChooser + chooseFrom: labelList + title: aString. + index = 0 ifFalse: [ valueList at: index ] ] + ifFalse: + [ MenuMorph + chooseFrom: labelList + values: valueList + lines: linesArray + title: aString ]! Item was added: + ----- Method: MorphicUIManager>>confirm: (in category 'ui requests') ----- + 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." + ^UserDialogBoxMorph confirm: queryString! Item was added: + ----- Method: MorphicUIManager>>confirm:orCancel: (in category 'ui requests') ----- + 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." + ^UserDialogBoxMorph confirm: aString orCancel: cancelBlock! Item was added: + ----- Method: MorphicUIManager>>confirm:trueChoice:falseChoice: (in category 'ui requests') ----- + 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." + ^ UserDialogBoxMorph confirm: queryString trueChoice: trueChoice falseChoice: falseChoice ! Item was added: + ----- Method: MorphicUIManager>>displayProgress:at:from:to:during: (in category 'ui requests') ----- + displayProgress: titleString at: aPoint from: minVal to: maxVal during: workBlock + "Display titleString as a caption over a progress bar while workBlock is evaluated." + | result progress | + progress := SystemProgressMorph + position: aPoint + label: titleString + min: minVal + max: maxVal. + [ [ result := workBlock value: progress ] + on: ProgressNotification + do: + [ : ex | ex extraParam isString ifTrue: + [ SystemProgressMorph uniqueInstance + labelAt: progress + put: ex extraParam ]. + ex resume ] ] ensure: [ SystemProgressMorph close: progress ]. + ^ result! Item was added: + ----- Method: MorphicUIManager>>edit:label:accept: (in category 'ui requests') ----- + 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.! Item was added: + ----- Method: MorphicUIManager>>inform: (in category 'ui requests') ----- + inform: aString + "Display a message for the user to read and then dismiss" + ^UserDialogBoxMorph inform: aString! Item was added: + ----- Method: MorphicUIManager>>informUserDuring: (in category 'ui requests') ----- + informUserDuring: aBlock + "Display a message above (or below if insufficient room) the cursor + during execution of the given block. + UIManager default informUserDuring:[:bar| + #(one two three) do:[:info| + bar value: info. + (Delay forSeconds: 1) wait]]" + SystemProgressMorph + informUserAt: nil during: aBlock.! Item was added: + ----- Method: MorphicUIManager>>initialize (in category 'initialize-release') ----- + initialize + toolBuilder := MorphicToolBuilder new! Item was added: + ----- Method: MorphicUIManager>>multiLineRequest:centerAt:initialAnswer:answerHeight: (in category 'ui requests') ----- + 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." + ^FillInTheBlankMorph + request: queryString + initialAnswer: defaultAnswer + centerAt: aPoint + inWorld: self currentWorld + onCancelReturn: nil + acceptOnCR: false! Item was added: + ----- Method: MorphicUIManager>>newDisplayDepthNoRestore: (in category 'display') ----- + newDisplayDepthNoRestore: pixelSize + "Change depths. Check if there is enough space!! , di" + | area need | + pixelSize = Display depth ifTrue: [^ self "no change"]. + pixelSize abs < Display depth ifFalse: + ["Make sure there is enough space" + area := Display boundingBox area. "pixels" + + need := (area * (pixelSize abs - Display depth) // 8) "new bytes needed" + + Smalltalk lowSpaceThreshold. + (Smalltalk garbageCollectMost <= need + and: [Smalltalk garbageCollect <= need]) + ifTrue: [self error: 'Insufficient free space']]. + Display setExtent: Display extent depth: pixelSize. + + DisplayScreen startUp! Item was added: + ----- Method: MorphicUIManager>>request:initialAnswer: (in category 'ui requests') ----- + 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." + ^FillInTheBlankMorph request: queryString initialAnswer: defaultAnswer ! Item was added: + ----- Method: MorphicUIManager>>request:initialAnswer:centerAt: (in category 'ui requests') ----- + 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." + ^FillInTheBlankMorph request: queryString initialAnswer: defaultAnswer centerAt: aPoint! Item was added: + ----- Method: MorphicUIManager>>requestPassword: (in category 'ui requests') ----- + 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." + ^FillInTheBlankMorph requestPassword: queryString! Item was added: + ----- Method: MorphicUIManager>>restoreDisplay (in category 'display') ----- + restoreDisplay + "Restore the bits on Display" + Project current ifNotNil:[:p| p invalidate; restore].! Item was added: + ----- Method: MorphicUIManager>>restoreDisplayAfter: (in category 'display') ----- + restoreDisplayAfter: aBlock + "Evaluate the block, wait for a mouse click, and then restore the screen." + + aBlock value. + Sensor waitButton. + self restoreDisplay! Item was added: + PluggableButtonMorph subclass: #PluggableButtonMorphPlus + instanceVariableNames: 'enabled action getColorSelector getEnabledSelector updateMap' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableButtonMorphPlus commentStamp: 'ar 2/11/2005 21:53' prior: 0! + An extended version of PluggableButtonMorph supporting enablement, color and block/message actions.! Item was added: + ----- Method: PluggableButtonMorphPlus>>action (in category 'accessing') ----- + action + ^action! Item was added: + ----- Method: PluggableButtonMorphPlus>>action: (in category 'accessing') ----- + action: anAction + action := nil. + anAction isSymbol ifTrue:[^super action: anAction]. + action := anAction.! Item was added: + ----- Method: PluggableButtonMorphPlus>>enabled (in category 'accessing') ----- + enabled + ^ enabled ifNil: [enabled := true]! Item was added: + ----- Method: PluggableButtonMorphPlus>>enabled: (in category 'accessing') ----- + enabled: aBool + enabled := aBool. + enabled + ifFalse:[self color: Color gray] + ifTrue:[self getModelState + ifTrue: [self color: onColor] + ifFalse: [self color: offColor]]! Item was added: + ----- Method: PluggableButtonMorphPlus>>getColorSelector (in category 'accessing') ----- + getColorSelector + ^getColorSelector! Item was added: + ----- Method: PluggableButtonMorphPlus>>getColorSelector: (in category 'accessing') ----- + getColorSelector: aSymbol + getColorSelector := aSymbol. + self update: getColorSelector.! Item was added: + ----- Method: PluggableButtonMorphPlus>>getEnabledSelector (in category 'accessing') ----- + getEnabledSelector + ^getEnabledSelector! Item was added: + ----- Method: PluggableButtonMorphPlus>>getEnabledSelector: (in category 'accessing') ----- + getEnabledSelector: aSymbol + getEnabledSelector := aSymbol. + self update: aSymbol.! Item was added: + ----- Method: PluggableButtonMorphPlus>>initialize (in category 'initialize-release') ----- + initialize + super initialize. + enabled := true. + onColor := Color veryLightGray. + offColor := Color white! Item was added: + ----- Method: PluggableButtonMorphPlus>>mouseDown: (in category 'action') ----- + mouseDown: evt + enabled ifFalse:[^self]. + ^super mouseDown: evt! Item was added: + ----- Method: PluggableButtonMorphPlus>>mouseMove: (in category 'action') ----- + mouseMove: evt + enabled ifFalse:[^self]. + ^super mouseMove: evt! Item was added: + ----- Method: PluggableButtonMorphPlus>>mouseUp: (in category 'action') ----- + mouseUp: evt + enabled ifFalse:[^self]. + ^super mouseUp: evt! Item was added: + ----- Method: PluggableButtonMorphPlus>>onColor:offColor: (in category 'accessing') ----- + onColor: colorWhenOn offColor: colorWhenOff + "Set the fill colors to be used when this button is on/off." + + onColor := colorWhenOn. + offColor := colorWhenOff. + self update: getStateSelector.! Item was added: + ----- Method: PluggableButtonMorphPlus>>performAction (in category 'action') ----- + performAction + enabled ifFalse:[^self]. + action ifNotNil:[^action value]. + ^super performAction! Item was added: + ----- Method: PluggableButtonMorphPlus>>update: (in category 'updating') ----- + update: what + what ifNil:[^self]. + what == getLabelSelector ifTrue: [ + self label: (model perform: getLabelSelector)]. + what == getEnabledSelector ifTrue:[^self enabled: (model perform: getEnabledSelector)]. + + getColorSelector ifNotNil: [ | cc | + color = (cc := model perform: getColorSelector) ifFalse:[ + color := cc. + self onColor: color offColor: color. + self changed. + ]. + ]. + self getModelState + ifTrue: [self color: onColor] + ifFalse: [self color: offColor]. + getEnabledSelector ifNotNil:[ + self enabled: (model perform: getEnabledSelector). + ]. + updateMap ifNotNil: + [(updateMap at: what ifAbsent: []) + ifNotNilDo: [ :newTarget | ^self update: newTarget]]. + ! Item was added: + ----- Method: PluggableButtonMorphPlus>>updateMap (in category 'updating') ----- + updateMap + ^ updateMap ifNil: [updateMap := Dictionary new] + ! Item was added: + ----- Method: PluggableButtonMorphPlus>>whenChanged:update: (in category 'updating') ----- + whenChanged: notification update: target + "On receipt of a notification, such as #contents notification from a CodeHolder, + invoke an update as if target had been the original notification." + + self updateMap at: notification put: target! Item was added: + AlignmentMorph subclass: #PluggableCheckBoxMorph + instanceVariableNames: 'model actionSelector valueSelector label' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! Item was added: + ----- Method: PluggableCheckBoxMorph class>>on:getState:action:label: (in category 'as yet unclassified') ----- + on: anObject getState: getStateSel action: actionSel label: labelSel + + ^ self new + on: anObject + getState: getStateSel + action: actionSel + label: labelSel + menu: nil + ! Item was added: + ----- Method: PluggableCheckBoxMorph>>actionSelector (in category 'accessing') ----- + actionSelector + "Answer the value of actionSelector" + + ^ actionSelector! Item was added: + ----- Method: PluggableCheckBoxMorph>>actionSelector: (in category 'accessing') ----- + actionSelector: anObject + "Set the value of actionSelector" + + actionSelector := anObject! Item was added: + ----- Method: PluggableCheckBoxMorph>>basicPanel (in category 'installing') ----- + basicPanel + ^BorderedMorph new + beTransparent; + extent: 0@0; + borderWidth: 0; + layoutInset: 0; + cellInset: 0; + layoutPolicy: TableLayout new; + listCentering: #topLeft; + cellPositioning: #center; + hResizing: #spaceFill; + vResizing: #shrinkWrap; + yourself! Item was added: + ----- Method: PluggableCheckBoxMorph>>horizontalPanel (in category 'installing') ----- + horizontalPanel + ^self basicPanel + cellPositioning: #center; + listDirection: #leftToRight; + yourself.! Item was added: + ----- Method: PluggableCheckBoxMorph>>installButton (in category 'installing') ----- + installButton + + | aButton aLabel | + aButton := UpdatingThreePhaseButtonMorph checkBox + target: self model; + actionSelector: self actionSelector; + getSelector: self valueSelector; + yourself. + aLabel := (StringMorph contents: self label translated + font: (StrikeFont familyName: TextStyle defaultFont familyName + size: TextStyle defaultFont pointSize - 1)). + self addMorph: (self horizontalPanel + addMorphBack: aButton; + addMorphBack: aLabel; + yourself).! Item was added: + ----- Method: PluggableCheckBoxMorph>>label (in category 'accessing') ----- + label + "Answer the value of label" + + ^ label! Item was added: + ----- Method: PluggableCheckBoxMorph>>label: (in category 'accessing') ----- + label: anObject + "Set the value of label" + + label := anObject! Item was added: + ----- Method: PluggableCheckBoxMorph>>model (in category 'accessing') ----- + model + "Answer the value of model" + + ^ model. + ! Item was added: + ----- Method: PluggableCheckBoxMorph>>model: (in category 'accessing') ----- + model: anObject + "Set the value of model" + + model := anObject! Item was added: + ----- Method: PluggableCheckBoxMorph>>on:getState:action:label:menu: (in category 'initialization') ----- + on: anObject getState: getStateSel action: actionSel label: labelSel menu: menuSel + + self model: anObject. + self valueSelector: getStateSel. + self actionSelector: actionSel. + self label: (self model perform: labelSel). + ! Item was added: + ----- Method: PluggableCheckBoxMorph>>valueSelector (in category 'accessing') ----- + valueSelector + "Answer the value of valueSelector" + + ^ valueSelector! Item was added: + ----- Method: PluggableCheckBoxMorph>>valueSelector: (in category 'accessing') ----- + valueSelector: anObject + "Set the value of valueSelector" + + valueSelector := anObject! Item was added: + PluggableSystemWindow subclass: #PluggableDialogWindow + instanceVariableNames: 'statusValue' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! Item was added: + ----- Method: PluggableDialogWindow>>statusValue (in category 'as yet unclassified') ----- + statusValue + ^statusValue! Item was added: + ----- Method: PluggableDialogWindow>>statusValue: (in category 'as yet unclassified') ----- + statusValue: val + statusValue := val! Item was added: + AlignmentMorph subclass: #PluggableDropDownListMorph + instanceVariableNames: 'model listSelector selectionSelector selectionSetter' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! Item was added: + ----- Method: PluggableDropDownListMorph>>basicPanel (in category 'drawing') ----- + basicPanel + ^BorderedMorph new + beTransparent; + extent: 0@0; + borderWidth: 0; + layoutInset: 0; + cellInset: 0; + layoutPolicy: TableLayout new; + listCentering: #topLeft; + cellPositioning: #center; + hResizing: #spaceFill; + vResizing: #shrinkWrap; + yourself! Item was added: + ----- Method: PluggableDropDownListMorph>>currentSelection (in category 'accessing') ----- + currentSelection + + ^ self model perform: selectionSelector! Item was added: + ----- Method: PluggableDropDownListMorph>>currentSelection: (in category 'accessing') ----- + currentSelection: obj + + ^ self model perform: selectionSetter with: obj! Item was added: + ----- Method: PluggableDropDownListMorph>>horizontalPanel (in category 'drawing') ----- + horizontalPanel + ^self basicPanel + cellPositioning: #center; + listDirection: #leftToRight; + yourself.! Item was added: + ----- Method: PluggableDropDownListMorph>>installDropDownList (in category 'drawing') ----- + installDropDownList + + | aButton aLabel | + aButton := PluggableButtonMorph on: self model getState: nil action: nil. + aLabel := (StringMorph contents: self model currentRemoteVatId translated + font: (StrikeFont familyName: TextStyle defaultFont familyName + size: TextStyle defaultFont pointSize - 1)). + self addMorph: (self horizontalPanel + addMorphBack: aLabel; + addMorphBack: aButton; + yourself).! Item was added: + ----- Method: PluggableDropDownListMorph>>list (in category 'accessing') ----- + list + "Answer the value of list" + + ^ self model perform: self listSelector. + ! Item was added: + ----- Method: PluggableDropDownListMorph>>listSelector (in category 'accessing') ----- + listSelector + "Answer the value of listSelector" + + ^ listSelector! Item was added: + ----- Method: PluggableDropDownListMorph>>listSelector: (in category 'accessing') ----- + listSelector: anObject + "Set the value of listSelector" + + listSelector := anObject! Item was added: + ----- Method: PluggableDropDownListMorph>>model (in category 'accessing') ----- + model + ^ model! Item was added: + ----- Method: PluggableDropDownListMorph>>model: (in category 'accessing') ----- + model: anObject + "Set the value of model" + + model := anObject! Item was added: + ----- Method: PluggableDropDownListMorph>>selectionSelector (in category 'accessing') ----- + selectionSelector + "Answer the value of selectionSelector" + + ^ selectionSelector! Item was added: + ----- Method: PluggableDropDownListMorph>>selectionSelector: (in category 'accessing') ----- + selectionSelector: anObject + "Set the value of selectionSelector" + + selectionSelector := anObject! Item was added: + ----- Method: PluggableDropDownListMorph>>selectionSetter (in category 'accessing') ----- + selectionSetter + "Answer the value of selectionSetter" + + ^ selectionSetter! Item was added: + ----- Method: PluggableDropDownListMorph>>selectionSetter: (in category 'accessing') ----- + selectionSetter: anObject + "Set the value of selectionSetter" + + selectionSetter := anObject! Item was added: + PluggableListMorphPlus subclass: #PluggableListMorphByItemPlus + instanceVariableNames: 'itemList' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableListMorphByItemPlus commentStamp: '<historical>' prior: 0! + Main comment stating the purpose of this class and relevant relationship to other classes. + + Possible useful expressions for doIt or printIt. + + Structure: + instVar1 type -- comment about the purpose of instVar1 + instVar2 type -- comment about the purpose of instVar2 + + Any further useful comments about the general approach of this implementation.! Item was added: + ----- Method: PluggableListMorphByItemPlus>>changeModelSelection: (in category 'model access') ----- + changeModelSelection: anInteger + "Change the model's selected item to be the one at the given index." + + | item | + setIndexSelector ifNotNil: [ + item := (anInteger = 0 ifTrue: [nil] ifFalse: [itemList at: anInteger]). + model perform: setIndexSelector with: item]. + self update: getIndexSelector. + ! Item was added: + ----- Method: PluggableListMorphByItemPlus>>getCurrentSelectionIndex (in category 'model access') ----- + getCurrentSelectionIndex + "Answer the index of the current selection." + | item | + getIndexSelector == nil ifTrue: [^ 0]. + item := model perform: getIndexSelector. + ^ itemList findFirst: [ :x | x = item] + ! Item was added: + ----- Method: PluggableListMorphByItemPlus>>getList (in category 'as yet unclassified') ----- + getList + "cache the raw items in itemList" + itemList := getListSelector ifNil: [ #() ] ifNotNil: [ model perform: getListSelector ]. + ^super getList! Item was added: + ----- Method: PluggableListMorphByItemPlus>>list: (in category 'initialization') ----- + list: arrayOfStrings + "Set the receivers items to be the given list of strings." + "Note: the instance variable 'items' holds the original list. + The instance variable 'list' is a paragraph constructed from + this list." + "NOTE: this is no longer true; list is a real list, and itemList is no longer used. And this method shouldn't be called, incidentally." + self isThisEverCalled . + itemList := arrayOfStrings. + ^ super list: arrayOfStrings! Item was added: + PluggableListMorph subclass: #PluggableListMorphPlus + instanceVariableNames: 'dragItemSelector dropItemSelector wantsDropSelector' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableListMorphPlus commentStamp: 'ar 7/15/2005 11:10' prior: 0! + Extensions for PluggableListMorph needed by ToolBuilder! Item was added: + ----- Method: PluggableListMorphPlus>>acceptDroppingMorph:event: (in category 'drag and drop') ----- + acceptDroppingMorph: aMorph event: evt + | item | + dropItemSelector isNil | potentialDropRow isNil ifTrue: [^self]. + item := aMorph passenger. + model perform: dropItemSelector with: item with: potentialDropRow. + self resetPotentialDropRow. + evt hand releaseMouseFocus: self. + Cursor normal show. + ! Item was added: + ----- Method: PluggableListMorphPlus>>dragItemSelector (in category 'accessing') ----- + dragItemSelector + ^dragItemSelector! Item was added: + ----- Method: PluggableListMorphPlus>>dragItemSelector: (in category 'accessing') ----- + dragItemSelector: aSymbol + dragItemSelector := aSymbol. + aSymbol ifNotNil:[self dragEnabled: true].! Item was added: + ----- Method: PluggableListMorphPlus>>dropItemSelector (in category 'accessing') ----- + dropItemSelector + ^dropItemSelector! Item was added: + ----- Method: PluggableListMorphPlus>>dropItemSelector: (in category 'accessing') ----- + dropItemSelector: aSymbol + dropItemSelector := aSymbol. + aSymbol ifNotNil:[self dropEnabled: true].! Item was added: + ----- Method: PluggableListMorphPlus>>startDrag: (in category 'drag and drop') ----- + startDrag: evt + + dragItemSelector ifNil:[^self]. + evt hand hasSubmorphs ifTrue: [^ self]. + [ | dragIndex draggedItem ddm | + (self dragEnabled and: [model okToChange]) ifFalse: [^ self]. + dragIndex := self rowAtLocation: evt position. + dragIndex = 0 ifTrue:[^self]. + draggedItem := model perform: dragItemSelector with: (self modelIndexFor: dragIndex). + draggedItem ifNil:[^self]. + ddm := TransferMorph withPassenger: draggedItem from: self. + ddm dragTransferType: #dragTransferPlus. + evt hand grabMorph: ddm] + ensure: [Cursor normal show. + evt hand releaseMouseFocus: self]! Item was added: + ----- Method: PluggableListMorphPlus>>wantsDropSelector (in category 'accessing') ----- + wantsDropSelector + ^wantsDropSelector! Item was added: + ----- Method: PluggableListMorphPlus>>wantsDropSelector: (in category 'accessing') ----- + wantsDropSelector: aSymbol + wantsDropSelector := aSymbol! Item was added: + ----- Method: PluggableListMorphPlus>>wantsDroppedMorph:event: (in category 'drag and drop') ----- + wantsDroppedMorph: aMorph event: anEvent + aMorph dragTransferType == #dragTransferPlus ifFalse:[^false]. + dropItemSelector ifNil:[^false]. + wantsDropSelector ifNil:[^true]. + ^(model perform: wantsDropSelector with: aMorph passenger) == true! Item was added: + AlignmentMorph subclass: #PluggablePanelMorph + instanceVariableNames: 'model getChildrenSelector' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggablePanelMorph commentStamp: 'ar 2/11/2005 20:13' prior: 0! + A pluggable panel morph which deals with changing children.! Item was added: + ----- Method: PluggablePanelMorph>>canBeEncroached (in category 'private') ----- + canBeEncroached + ^ submorphs allSatisfy: + [ : each | each canBeEncroached ]! Item was added: + ----- Method: PluggablePanelMorph>>children (in category 'accessing') ----- + children + ^ model perform: getChildrenSelector! Item was added: + ----- Method: PluggablePanelMorph>>getChildrenSelector (in category 'accessing') ----- + getChildrenSelector + ^getChildrenSelector! Item was added: + ----- Method: PluggablePanelMorph>>getChildrenSelector: (in category 'accessing') ----- + getChildrenSelector: aSymbol + getChildrenSelector := aSymbol.! Item was added: + ----- Method: PluggablePanelMorph>>model (in category 'accessing') ----- + model + ^model! Item was added: + ----- Method: PluggablePanelMorph>>model: (in category 'accessing') ----- + model: aModel + model ifNotNil:[model removeDependent: self]. + model := aModel. + model ifNotNil:[model addDependent: self].! Item was added: + ----- Method: PluggablePanelMorph>>update: (in category 'update') ----- + update: selectorSymbolOrNil + selectorSymbolOrNil ifNil: [ ^ self ]. + selectorSymbolOrNil = getChildrenSelector ifTrue: + [ self + removeAllMorphs ; + addAllMorphs: self children ; + submorphsDo: + [ : m | m + hResizing: #spaceFill ; + vResizing: #spaceFill ] ]! Item was added: + SystemWindow subclass: #PluggableSystemWindow + instanceVariableNames: 'getLabelSelector getChildrenSelector children closeWindowSelector' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableSystemWindow commentStamp: 'ar 2/11/2005 20:14' prior: 0! + A pluggable system window. Fixes the issues with label retrieval and adds support for changing children.! Item was added: + ----- Method: PluggableSystemWindow>>addPaneMorph: (in category 'accessing') ----- + addPaneMorph: aMorph + self addMorph: aMorph fullFrame: aMorph layoutFrame! Item was added: + ----- Method: PluggableSystemWindow>>closeWindowSelector (in category 'accessing') ----- + closeWindowSelector + ^closeWindowSelector! Item was added: + ----- Method: PluggableSystemWindow>>closeWindowSelector: (in category 'accessing') ----- + closeWindowSelector: aSymbol + closeWindowSelector := aSymbol! Item was added: + ----- Method: PluggableSystemWindow>>delete (in category 'initialization') ----- + delete + closeWindowSelector ifNotNil:[model perform: closeWindowSelector]. + super delete. + ! Item was added: + ----- Method: PluggableSystemWindow>>getChildrenSelector (in category 'accessing') ----- + getChildrenSelector + ^getChildrenSelector! Item was added: + ----- Method: PluggableSystemWindow>>getChildrenSelector: (in category 'accessing') ----- + getChildrenSelector: aSymbol + getChildrenSelector := aSymbol! Item was added: + ----- Method: PluggableSystemWindow>>getLabelSelector (in category 'accessing') ----- + getLabelSelector + ^getLabelSelector! Item was added: + ----- Method: PluggableSystemWindow>>getLabelSelector: (in category 'accessing') ----- + getLabelSelector: aSymbol + getLabelSelector := aSymbol. + self update: aSymbol.! Item was added: + ----- Method: PluggableSystemWindow>>label (in category 'accessing') ----- + label + ^label contents! Item was added: + ----- Method: PluggableSystemWindow>>label: (in category 'accessing') ----- + label: aString + self setLabel: aString.! Item was added: + ----- Method: PluggableSystemWindow>>update: (in category 'updating') ----- + update: what + what ifNil:[^self]. + what == getLabelSelector ifTrue:[self setLabel: (model perform: getLabelSelector)]. + what == getChildrenSelector ifTrue:[ + children ifNil:[children := #()]. + self removeAllMorphsIn: children. + children := model perform: getChildrenSelector. + self addAllMorphs: children. + children do:[:m| m hResizing: #spaceFill; vResizing: #spaceFill]. + ]. + ^super update: what! Item was added: + PluggableTextMorph subclass: #PluggableTextMorphPlus + instanceVariableNames: 'getColorSelector acceptAction unstyledAcceptText styler' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableTextMorphPlus commentStamp: 'ar 2/11/2005 21:53' prior: 0! + A pluggable text morph with support for color.! Item was added: + ----- Method: PluggableTextMorphPlus>>accept (in category 'updating') ----- + accept + super accept. + acceptAction ifNotNil:[acceptAction value: textMorph asText].! Item was added: + ----- Method: PluggableTextMorphPlus>>acceptAction (in category 'accessing') ----- + acceptAction + ^acceptAction! Item was added: + ----- Method: PluggableTextMorphPlus>>acceptAction: (in category 'accessing') ----- + acceptAction: anAction + acceptAction := anAction! Item was added: + ----- Method: PluggableTextMorphPlus>>acceptTextInModel (in category 'styling') ----- + acceptTextInModel + + self okToStyle ifFalse:[^super acceptTextInModel]. + "#correctFrom:to:with: is sent when the method source is + manipulated during compilation (removing unused temps, + changing selectors etc). But #correctFrom:to:with: operates + on the textMorph's text, and we may be saving an unstyled + copy of the text. This means that these corrections will be lost + unless we also apply the corrections to the unstyled copy that we are saving. + So remember the unstyled copy in unstyledAcceptText, so + that when #correctFrom:to:with: is received we can also apply + the correction to it" + unstyledAcceptText := styler unstyledTextFrom: textMorph asText. + [^setTextSelector isNil or: + [setTextSelector numArgs = 2 + ifTrue: [model perform: setTextSelector with: unstyledAcceptText with: self] + ifFalse: [model perform: setTextSelector with: unstyledAcceptText]] + ] ensure:[unstyledAcceptText := nil]! Item was added: + ----- Method: PluggableTextMorphPlus>>correctFrom:to:with: (in category 'styling') ----- + correctFrom: start to: stop with: aString + "see the comment in #acceptTextInModel " + unstyledAcceptText ifNotNil:[unstyledAcceptText replaceFrom: start to: stop with: aString ]. + ^ super correctFrom: start to: stop with: aString! Item was added: + ----- Method: PluggableTextMorphPlus>>getColorSelector (in category 'accessing') ----- + getColorSelector + ^getColorSelector! Item was added: + ----- Method: PluggableTextMorphPlus>>getColorSelector: (in category 'accessing') ----- + getColorSelector: aSymbol + getColorSelector := aSymbol. + self update: getColorSelector.! Item was added: + ----- Method: PluggableTextMorphPlus>>getMenu: (in category 'menu') ----- + getMenu: shiftKeyState + "Answer the menu for this text view. We override the superclass implementation to + so we can give the selection interval to the model." + + | menu aMenu | + getMenuSelector == nil ifTrue: [^ nil]. + getMenuSelector numArgs < 3 ifTrue: [^ super getMenu: shiftKeyState]. + menu := MenuMorph new defaultTarget: model. + getMenuSelector numArgs = 3 ifTrue: + [aMenu := model + perform: getMenuSelector + with: menu + with: shiftKeyState + with: self selectionInterval. + getMenuTitleSelector ifNotNil: + [aMenu addTitle: (model perform: getMenuTitleSelector)]. + ^ aMenu]. + ^ self error: 'The getMenuSelector must be a 1- or 2 or 3-keyword symbol'! Item was added: + ----- Method: PluggableTextMorphPlus>>hasUnacceptedEdits: (in category 'styling') ----- + hasUnacceptedEdits: aBoolean + "re-implemented to re-style the text iff aBoolean is true" + + super hasUnacceptedEdits: aBoolean. + (aBoolean and: [self okToStyle]) + ifTrue: [ styler styleInBackgroundProcess: textMorph contents]! Item was added: + ----- Method: PluggableTextMorphPlus>>okToStyle (in category 'testing') ----- + okToStyle + styler ifNil:[^false]. + (model respondsTo: #aboutToStyle: ) ifFalse:[^true]. + ^model aboutToStyle: styler + ! Item was added: + ----- Method: PluggableTextMorphPlus>>setText: (in category 'styling') ----- + setText: aText + + self okToStyle ifFalse:[^super setText: aText]. + super setText: (styler format: aText asText). + aText size < 4096 + ifTrue:[styler style: textMorph contents] + ifFalse:[styler styleInBackgroundProcess: textMorph contents]! Item was added: + ----- Method: PluggableTextMorphPlus>>styler (in category 'accessing') ----- + styler + "The styler responsible for highlighting text in the receiver" + ^styler! Item was added: + ----- Method: PluggableTextMorphPlus>>styler: (in category 'accessing') ----- + styler: anObject + "The styler responsible for highlighting text in the receiver" + styler := anObject! Item was added: + ----- Method: PluggableTextMorphPlus>>stylerStyled: (in category 'styling') ----- + stylerStyled: styledCopyOfText + "Sent after the styler completed styling the underlying text" + textMorph contents runs: styledCopyOfText runs . + "textMorph paragraph recomposeFrom: 1 to: textMorph contents size delta: 0." "caused chars to appear in wrong order esp. in demo mode. remove this line when sure it is fixed" + textMorph paragraph composeAll. + textMorph updateFromParagraph. + selectionInterval + ifNotNil:[ + textMorph editor + selectInvisiblyFrom: selectionInterval first to: selectionInterval last; + storeSelectionInParagraph; + setEmphasisHere]. + textMorph editor blinkParen. + self scrollSelectionIntoView! Item was added: + ----- Method: PluggableTextMorphPlus>>stylerStyledInBackground: (in category 'styling') ----- + stylerStyledInBackground: styledCopyOfText + "Sent after the styler completed styling of the text" + + "It is possible that the text string has changed since the styling began. Disregard the styles if styledCopyOfText's string differs with the current textMorph contents string" + textMorph contents string = styledCopyOfText string + ifTrue: [self stylerStyled: styledCopyOfText]! Item was added: + ----- Method: PluggableTextMorphPlus>>update: (in category 'updating') ----- + update: what + what ifNil:[^self]. + what == getColorSelector ifTrue:[self color: (model perform: getColorSelector)]. + ^super update: what! Item was added: + ----- Method: PluggableTextMorphPlus>>useDefaultStyler (in category 'initialize') ----- + useDefaultStyler + "This should be changed to a proper registry but as long as there is only shout this will do" + Smalltalk at: #SHTextStylerST80 ifPresent:[:stylerClass| + self styler: (stylerClass new view: self). + ].! Item was added: + ListItemWrapper subclass: #PluggableTreeItemNode + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableTreeItemNode commentStamp: 'ar 2/12/2005 04:37' prior: 0! + Tree item for PluggableTreeMorph.! Item was added: + ----- Method: PluggableTreeItemNode>>acceptDroppingObject: (in category 'accessing') ----- + acceptDroppingObject: anotherItem + ^model dropNode: anotherItem on: self! Item was added: + ----- Method: PluggableTreeItemNode>>asString (in category 'accessing') ----- + asString + ^model printNode: self! Item was added: + ----- Method: PluggableTreeItemNode>>balloonText (in category 'accessing') ----- + balloonText + ^model balloonTextForNode: self! Item was added: + ----- Method: PluggableTreeItemNode>>canBeDragged (in category 'accessing') ----- + canBeDragged + ^model isDraggableNode: self! Item was added: + ----- Method: PluggableTreeItemNode>>contents (in category 'accessing') ----- + contents + ^model contentsOfNode: self! Item was added: + ----- Method: PluggableTreeItemNode>>hasContents (in category 'accessing') ----- + hasContents + ^model hasNodeContents: self! Item was added: + ----- Method: PluggableTreeItemNode>>icon (in category 'accessing') ----- + icon + ^model iconOfNode: self! Item was added: + ----- Method: PluggableTreeItemNode>>item (in category 'accessing') ----- + item + ^item! Item was added: + ----- Method: PluggableTreeItemNode>>wantsDroppedObject: (in category 'accessing') ----- + wantsDroppedObject: anotherItem + ^model wantsDroppedNode: anotherItem on: self! Item was added: + SimpleHierarchicalListMorph subclass: #PluggableTreeMorph + instanceVariableNames: 'roots selectedWrapper getRootsSelector getChildrenSelector hasChildrenSelector getLabelSelector getIconSelector getSelectedPathSelector setSelectedSelector getHelpSelector dropItemSelector wantsDropSelector dragItemSelector' + classVariableNames: '' + poolDictionaries: '' + category: 'ToolBuilder-Morphic'! + + !PluggableTreeMorph commentStamp: 'ar 2/12/2005 04:38' prior: 0! + A pluggable tree morph.! Item was added: + ----- Method: PluggableTreeMorph>>acceptDroppingMorph:event: (in category 'morphic') ----- + acceptDroppingMorph: aTransferMorph event: evt + dropItemSelector ifNil: [ ^ self ]. + model + perform: dropItemSelector + withEnoughArguments: {aTransferMorph passenger. + (self itemFromPoint: evt position) withoutListWrapper. + aTransferMorph shouldCopy}. + evt hand releaseMouseFocus: self. + potentialDropMorph ifNotNil: [ potentialDropMorph highlightForDrop: false ]. + Cursor normal show! Item was added: + ----- Method: PluggableTreeMorph>>balloonTextForNode: (in category 'node access') ----- + balloonTextForNode: node + getHelpSelector ifNil:[^nil]. + ^model perform: getHelpSelector with: node item! Item was added: + ----- Method: PluggableTreeMorph>>contentsOfNode: (in category 'node access') ----- + contentsOfNode: node + | children | + getChildrenSelector ifNil:[^#()]. + children := model perform: getChildrenSelector with: node item. + ^children collect:[:item| PluggableTreeItemNode with: item model: self]! Item was added: + ----- Method: PluggableTreeMorph>>dragItemSelector (in category 'accessing') ----- + dragItemSelector + ^dragItemSelector! Item was added: + ----- Method: PluggableTreeMorph>>dragItemSelector: (in category 'accessing') ----- + dragItemSelector: aSymbol + dragItemSelector := aSymbol. + aSymbol ifNotNil:[self dragEnabled: true].! Item was added: + ----- Method: PluggableTreeMorph>>dropItemSelector (in category 'accessing') ----- + dropItemSelector + ^dropItemSelector! Item was added: + ----- Method: PluggableTreeMorph>>dropItemSelector: (in category 'accessing') ----- + dropItemSelector: aSymbol + dropItemSelector := aSymbol. + aSymbol ifNotNil:[self dropEnabled: true].! Item was added: + ----- Method: PluggableTreeMorph>>dropNode:on: (in category 'node access') ----- + dropNode: srcNode on: dstNode + dropItemSelector ifNil:[^nil]. + model perform: dropItemSelector with: srcNode item with: dstNode item! Item was added: + ----- Method: PluggableTreeMorph>>getChildrenSelector (in category 'accessing') ----- + getChildrenSelector + ^getChildrenSelector! Item was added: + ----- Method: PluggableTreeMorph>>getChildrenSelector: (in category 'accessing') ----- + getChildrenSelector: aSymbol + getChildrenSelector := aSymbol.! Item was added: + ----- Method: PluggableTreeMorph>>getHelpSelector (in category 'accessing') ----- + getHelpSelector + ^getHelpSelector! Item was added: + ----- Method: PluggableTreeMorph>>getHelpSelector: (in category 'accessing') ----- + getHelpSelector: aSymbol + getHelpSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>getIconSelector (in category 'accessing') ----- + getIconSelector + ^getIconSelector! Item was added: + ----- Method: PluggableTreeMorph>>getIconSelector: (in category 'accessing') ----- + getIconSelector: aSymbol + getIconSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>getLabelSelector (in category 'accessing') ----- + getLabelSelector + ^getLabelSelector! Item was added: + ----- Method: PluggableTreeMorph>>getLabelSelector: (in category 'accessing') ----- + getLabelSelector: aSymbol + getLabelSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>getMenuSelector (in category 'accessing') ----- + getMenuSelector + ^getMenuSelector! Item was added: + ----- Method: PluggableTreeMorph>>getMenuSelector: (in category 'accessing') ----- + getMenuSelector: aSymbol + getMenuSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>getRootsSelector (in category 'accessing') ----- + getRootsSelector + ^getRootsSelector! Item was added: + ----- Method: PluggableTreeMorph>>getRootsSelector: (in category 'accessing') ----- + getRootsSelector: aSelector + getRootsSelector := aSelector. + self update: getRootsSelector.! Item was added: + ----- Method: PluggableTreeMorph>>getSelectedPathSelector (in category 'accessing') ----- + getSelectedPathSelector + ^getSelectedPathSelector! Item was added: + ----- Method: PluggableTreeMorph>>getSelectedPathSelector: (in category 'accessing') ----- + getSelectedPathSelector: aSymbol + getSelectedPathSelector := aSymbol.! Item was added: + ----- Method: PluggableTreeMorph>>hasChildrenSelector (in category 'accessing') ----- + hasChildrenSelector + ^hasChildrenSelector! Item was added: + ----- Method: PluggableTreeMorph>>hasChildrenSelector: (in category 'accessing') ----- + hasChildrenSelector: aSymbol + hasChildrenSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>hasNodeContents: (in category 'node access') ----- + hasNodeContents: node + hasChildrenSelector ifNil:[^node contents isEmpty not]. + ^model perform: hasChildrenSelector with: node item! Item was added: + ----- Method: PluggableTreeMorph>>iconOfNode: (in category 'node access') ----- + iconOfNode: node + getIconSelector ifNil:[^nil]. + ^model perform: getIconSelector with: node item! Item was added: + ----- Method: PluggableTreeMorph>>isDraggableNode: (in category 'node access') ----- + isDraggableNode: node + ^true! Item was added: + ----- Method: PluggableTreeMorph>>keystrokeActionSelector (in category 'accessing') ----- + keystrokeActionSelector + ^keystrokeActionSelector! Item was added: + ----- Method: PluggableTreeMorph>>keystrokeActionSelector: (in category 'accessing') ----- + keystrokeActionSelector: aSymbol + keystrokeActionSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>printNode: (in category 'node access') ----- + printNode: node + getLabelSelector ifNil:[^node item printString]. + ^model perform: getLabelSelector with: node item! Item was added: + ----- Method: PluggableTreeMorph>>roots (in category 'accessing') ----- + roots + ^roots! Item was added: + ----- Method: PluggableTreeMorph>>roots: (in category 'accessing') ----- + roots: anArray + roots := anArray collect:[:item| PluggableTreeItemNode with: item model: self]. + self list: roots.! Item was added: + ----- Method: PluggableTreeMorph>>selectPath:in: (in category 'updating') ----- + selectPath: path in: listItem + path isEmpty ifTrue: [^self setSelectedMorph: nil]. + listItem withSiblingsDo: [:each | + (each complexContents item = path first) ifTrue: [ + each isExpanded ifFalse: [ + each toggleExpandedState. + self adjustSubmorphPositions. + ]. + each changed. + path size = 1 ifTrue: [ + ^self setSelectedMorph: each + ]. + each firstChild ifNil: [^self setSelectedMorph: nil]. + ^self selectPath: path allButFirst in: each firstChild + ]. + ]. + ^self setSelectedMorph: nil + + ! Item was added: + ----- Method: PluggableTreeMorph>>setSelectedMorph: (in category 'selection') ----- + setSelectedMorph: aMorph + selectedWrapper := aMorph complexContents. + self selection: selectedWrapper. + setSelectedSelector ifNotNil:[ + model + perform: setSelectedSelector + with: (selectedWrapper ifNotNil:[selectedWrapper item]). + ].! Item was added: + ----- Method: PluggableTreeMorph>>setSelectedSelector (in category 'accessing') ----- + setSelectedSelector + ^setSelectedSelector! Item was added: + ----- Method: PluggableTreeMorph>>setSelectedSelector: (in category 'accessing') ----- + setSelectedSelector: aSymbol + setSelectedSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>startDrag: (in category 'morphic') ----- + startDrag: evt + | ddm itemMorph passenger | + self dragEnabled + ifTrue: [itemMorph := scroller submorphs + detect: [:any | any highlightedForMouseDown] + ifNone: []]. + (itemMorph isNil + or: [evt hand hasSubmorphs]) + ifTrue: [^ self]. + itemMorph highlightForMouseDown: false. + itemMorph ~= self selectedMorph + ifTrue: [self setSelectedMorph: itemMorph]. + passenger := self model perform: dragItemSelector with: itemMorph withoutListWrapper. + passenger + ifNotNil: [ddm := TransferMorph withPassenger: passenger from: self. + ddm dragTransferType: #dragTransferPlus. + Preferences dragNDropWithAnimation + ifTrue: [self model dragAnimationFor: itemMorph transferMorph: ddm]. + evt hand grabMorph: ddm]. + evt hand releaseMouseFocus: self! Item was added: + ----- Method: PluggableTreeMorph>>update: (in category 'updating') ----- + update: what + what ifNil:[^self]. + what == getRootsSelector ifTrue:[ + self roots: (model perform: getRootsSelector) + ]. + what == getSelectedPathSelector ifTrue:[ + ^self selectPath: (model perform: getSelectedPathSelector) + in: (scroller submorphs at: 1 ifAbsent: [^self]) + ]. + ^super update: what! Item was added: + ----- Method: PluggableTreeMorph>>wantsDropSelector (in category 'accessing') ----- + wantsDropSelector + ^wantsDropSelector! Item was added: + ----- Method: PluggableTreeMorph>>wantsDropSelector: (in category 'accessing') ----- + wantsDropSelector: aSymbol + wantsDropSelector := aSymbol! Item was added: + ----- Method: PluggableTreeMorph>>wantsDroppedMorph:event: (in category 'morphic') ----- + wantsDroppedMorph: aMorph event: anEvent + aMorph dragTransferType == #dragTransferPlus ifFalse:[^false]. + dropItemSelector ifNil:[^false]. + wantsDropSelector ifNil:[^true]. + ^ (model perform: wantsDropSelector with: aMorph passenger) == true.! Item was added: + ----- Method: PluggableTreeMorph>>wantsDroppedNode:on: (in category 'node access') ----- + wantsDroppedNode: srcNode on: dstNode + dropItemSelector ifNil:[^false]. + wantsDropSelector ifNil:[^true]. + ^(model perform: wantsDropSelector with: srcNode with: dstNode) == true! |
Free forum by Nabble | Edit this page |