'From Squeak3.4alpha of 6 November 2002 [latest update: #5097] on 8 November 2002 at 9:32:26 pm'! "Change Set: transitionScripts-sw Date: 8 November 2002 Author: Scott Wallace Fixes the long-standing deficiency in stacks that opening and closing were not being run on a card turn unless it involved a background switch. Also adds a menu item to the stack/cards submenu allowing one-touch creation of a background field, i.e. a TextMorph that will occur on a every card with each card instance bearing separate contents."! !Morph methodsFor: 'menus' stamp: 'sw 11/8/2002 15:01'! addStackItemsTo: aMenu "Add stack-related items to the menu" | stackSubMenu | stackSubMenu _ MenuMorph new defaultTarget: self. (owner notNil and: [owner isStackBackground]) ifTrue: [self isShared ifFalse: [self couldHoldSeparateDataForEachInstance ifTrue: [stackSubMenu add: 'Background field, shared value' target: self action: #putOnBackground. stackSubMenu add: 'Background field, individual values' target: self action: #becomeSharedBackgroundField] ifFalse: [stackSubMenu add: 'put onto Background' target: self action: #putOnBackground]] ifTrue: [stackSubMenu add: 'remove from Background' target: self action: #putOnForeground. self couldHoldSeparateDataForEachInstance ifTrue: [self holdsSeparateDataForEachInstance ifFalse: [stackSubMenu add: 'start holding separate data for each instance' target: self action: #makeHoldSeparateDataForEachInstance] ifTrue: [stackSubMenu add: 'stop holding separate data for each instance' target: self action: #stopHoldingSeparateDataForEachInstance]. stackSubMenu add: 'be default value on new card' target: self action: #setAsDefaultValueForNewCard. (self hasProperty: #thumbnailImage) ifTrue: [stackSubMenu add: 'stop using for reference thumbnail' target: self action: #stopUsingForReferenceThumbnail] ifFalse: [stackSubMenu add: 'start using for reference thumbnail' target: self action: #startUsingForReferenceThumbnail]]]. stackSubMenu addLine]. (self isStackBackground) ifFalse: [stackSubMenu add: 'be a card in an existing stack...' action: #insertAsStackBackground]. stackSubMenu add: 'make an instance for my data' action: #abstractAModel. (self isStackBackground) ifFalse: [stackSubMenu add: 'become a stack of cards' action: #wrapWithAStack]. aMenu add: 'stacks and cards...' subMenu: stackSubMenu ! ! !Morph methodsFor: 'card in a stack' stamp: 'sw 11/8/2002 14:57'! becomeSharedBackgroundField "Mark the receiver as holding separate data for each instance (i.e., like a 'background field') and reassess the shape of the corresponding background so that it will be able to accommodate this arrangement." ((self hasProperty: #shared) and: [self hasProperty: #holdsSeparateDataForEachInstance]) ifFalse: [self setProperty: #shared toValue: true. self setProperty: #holdsSeparateDataForEachInstance toValue: true. self stack reassessBackgroundShape]! ! !Morph methodsFor: 'card in a stack' stamp: 'sw 11/8/2002 15:16'! installAsCurrent: anInstance "Install anInstance as the one currently viewed in the receiver. Dock up all the morphs in the receiver which contain data rooted in the player instance to the instance data. Run any 'opening' scripts that pertain." | fieldList itsFocus | self player == anInstance ifTrue: [^ self]. fieldList _ self allMorphs select: [:aMorph | (aMorph wouldAcceptKeyboardFocusUponTab) and: [aMorph isLocked not]]. self currentWorld hands do: [:aHand | (itsFocus _ aHand keyboardFocus) notNil ifTrue: [(fieldList includes: itsFocus) ifTrue: [aHand newKeyboardFocus: nil]]]. self player uninstallFrom: self. "out with the old" anInstance installPrivateMorphsInto: self. self changed. anInstance costume: self. self player: anInstance. self player class variableDocks do: [:aVariableDock | aVariableDock dockMorphUpToInstance: anInstance]. self currentWorld startSteppingSubmorphsOf: self! ! !BookMorph methodsFor: 'navigation' stamp: 'sw 11/8/2002 13:31'! goToPage: pageNumber transitionSpec: transitionSpec runTransitionScripts: aBoolean "Go the the given page number; use the transitionSpec supplied, and if the boolean parameter is true, run opening and closing scripts as appropriate" | pageMorph | pages isEmpty ifTrue: [^ self]. pageMorph _ (self hasProperty: #dontWrapAtEnd) ifTrue: [pages atPin: pageNumber] ifFalse: [pages atWrap: pageNumber]. ^ self goToPageMorph: pageMorph transitionSpec: transitionSpec runTransitionScripts: aBoolean! ! !BookMorph methodsFor: 'navigation' stamp: 'sw 11/8/2002 21:30'! goToPageMorph: aMorph "Set the given morph as the current page; run closing and opening scripts as appropriate" self goToPageMorph: aMorph runTransitionScripts: true! ! !BookMorph methodsFor: 'navigation' stamp: 'sw 11/8/2002 13:34'! goToPageMorph: aMorph runTransitionScripts: aBoolean "Set the given morph as the current page. If the boolean parameter is true, then opening and closing scripts will be run" self goToPage: (pages identityIndexOf: aMorph ifAbsent: [^ self "abort"]) transitionSpec: nil runTransitionScripts: aBoolean ! ! !BookMorph methodsFor: 'navigation' stamp: 'sw 11/8/2002 13:07'! goToPageMorph: newPage transitionSpec: transitionSpec runTransitionScripts: aBoolean "Install the given page as the new current page; use the given transition spec, and if the boolean parameter is true, run closing and opening scripts on the outgoing and incoming players" | pageIndex aWorld oldPageIndex ascending tSpec readIn | pages isEmpty ifTrue: [^ self]. self setProperty: #searchContainer toValue: nil. "forget previous search" self setProperty: #searchOffset toValue: nil. self setProperty: #searchKey toValue: nil. pageIndex _ pages identityIndexOf: newPage ifAbsent: [^ self "abort"]. readIn _ newPage isInMemory not. oldPageIndex _ pages identityIndexOf: currentPage ifAbsent: [nil]. ascending _ ((oldPageIndex == nil) or: [newPage == currentPage]) ifTrue: [nil] ifFalse: [oldPageIndex < pageIndex]. tSpec _ transitionSpec ifNil: "If transition not specified by requestor..." [newPage valueOfProperty: #transitionSpec " ... then consult new page" ifAbsent: [self transitionSpecFor: self " ... otherwise this is the default"]]. self flag: #arNote. "Probably unnecessary" (aWorld _ self world) ifNotNil: [self primaryHand releaseKeyboardFocus]. currentPage ifNotNil: [currentPage updateCachedThumbnail]. self currentPage ~~ nil ifTrue: [(((pages at: pageIndex) owner isKindOf: TransitionMorph) and: [(pages at: pageIndex) isInWorld]) ifTrue: [^ self "In the process of a prior pageTurn"]. aBoolean ifTrue: [self currentPlayerDo: [:aPlayer | aPlayer runAllClosingScripts]]. ascending ifNotNil: ["Show appropriate page transition and start new page when done" currentPage stopStepping. (pages at: pageIndex) position: currentPage position. ^ (TransitionMorph effect: tSpec second direction: tSpec third inverse: (ascending or: [transitionSpec notNil]) not) showTransitionFrom: currentPage to: (pages at: pageIndex) in: self whenStart: [self playPageFlipSound: tSpec first] whenDone: [currentPage delete; fullReleaseCachedState. self insertPageMorphInCorrectSpot: (pages at: pageIndex). self adjustCurrentPageForFullScreen. self snapToEdgeIfAppropriate. aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage]. aBoolean ifTrue: [self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts]]. (aWorld _ self world) ifNotNil: ["WHY??" aWorld displayWorld]. readIn ifTrue: [currentPage updateThumbnailUrlInBook: self url. currentPage sqkPage computeThumbnail]. "just store it" ]]. "No transition, but at least decommission current page" currentPage delete; fullReleaseCachedState]. self insertPageMorphInCorrectSpot: (pages at: pageIndex). self adjustCurrentPageForFullScreen. self snapToEdgeIfAppropriate. aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage]. self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts]. (aWorld _ self world) ifNotNil: ["WHY??" aWorld displayWorld]. readIn ifTrue: [currentPage updateThumbnailUrl. currentPage sqkPage computeThumbnail]. "just store it" ! ! !StackMorph methodsFor: 'card access' stamp: 'sw 11/8/2002 15:15'! goToCard: destinationCard "Install the indicated destinationCard as the current card in the receiver. Any viewer currently open on the current card will get retargeted to look at the new one." | aBackground existingCard oldViewers | destinationCard == self currentCard ifTrue: [^ self]. self currentPlayerDo: [:aPlayer | aPlayer runAllClosingScripts]. "Like HyperCard 'on closeCard'" aBackground _ self backgroundWithCard: destinationCard. existingCard _ aBackground currentDataInstance. oldViewers _ existingCard ifNil: [#()] ifNotNil: [existingCard allOpenViewers]. aBackground installAsCurrent: destinationCard. aBackground setProperty: #myStack toValue: self. "pointer cardMorph -> stack" aBackground ~~ currentPage ifTrue: [self goToPageMorph: aBackground runTransitionScripts: false]. self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts] . "Like HyperCard 'on opencard'" oldViewers do: [:aViewer | aViewer retargetFrom: existingCard to: destinationCard]! !